@ -66,6 +66,12 @@ char core_pattern[CORENAME_MAX_SIZE] = "core";
unsigned int core_pipe_limit ;
int suid_dumpable = 0 ;
struct core_name {
char * corename ;
int used , size ;
} ;
static atomic_t call_count = ATOMIC_INIT ( 1 ) ;
/* The maximal length of core_pattern is also specified in sysctl.c */
static LIST_HEAD ( formats ) ;
@ -1459,127 +1465,148 @@ void set_binfmt(struct linux_binfmt *new)
EXPORT_SYMBOL ( set_binfmt ) ;
static int expand_corename ( struct core_name * cn )
{
char * old_corename = cn - > corename ;
cn - > size = CORENAME_MAX_SIZE * atomic_inc_return ( & call_count ) ;
cn - > corename = krealloc ( old_corename , cn - > size , GFP_KERNEL ) ;
if ( ! cn - > corename ) {
kfree ( old_corename ) ;
return - ENOMEM ;
}
return 0 ;
}
static int cn_printf ( struct core_name * cn , const char * fmt , . . . )
{
char * cur ;
int need ;
int ret ;
va_list arg ;
va_start ( arg , fmt ) ;
need = vsnprintf ( NULL , 0 , fmt , arg ) ;
va_end ( arg ) ;
if ( likely ( need < cn - > size - cn - > used - 1 ) )
goto out_printf ;
ret = expand_corename ( cn ) ;
if ( ret )
goto expand_fail ;
out_printf :
cur = cn - > corename + cn - > used ;
va_start ( arg , fmt ) ;
vsnprintf ( cur , need + 1 , fmt , arg ) ;
va_end ( arg ) ;
cn - > used + = need ;
return 0 ;
expand_fail :
return ret ;
}
/* format_corename will inspect the pattern parameter, and output a
* name into corename , which must have space for at least
* CORENAME_MAX_SIZE bytes plus one byte for the zero terminator .
*/
static int format_corename ( char * corename , long signr )
static int format_corename ( struct core_name * cn , long signr )
{
const struct cred * cred = current_cred ( ) ;
const char * pat_ptr = core_pattern ;
int ispipe = ( * pat_ptr = = ' | ' ) ;
char * out_ptr = corename ;
char * const out_end = corename + CORENAME_MAX_SIZE ;
int rc ;
int pid_in_pattern = 0 ;
int err = 0 ;
cn - > size = CORENAME_MAX_SIZE * atomic_read ( & call_count ) ;
cn - > corename = kmalloc ( cn - > size , GFP_KERNEL ) ;
cn - > used = 0 ;
if ( ! cn - > corename )
return - ENOMEM ;
/* Repeat as long as we have more pattern to process and more output
space */
while ( * pat_ptr ) {
if ( * pat_ptr ! = ' % ' ) {
if ( out_ptr = = out_end )
if ( * pat_ptr = = 0 )
goto out ;
* out_ptr + + = * pat_ptr + + ;
err = cn_printf ( cn , " %c " , * pat_ptr + + ) ;
} else {
switch ( * + + pat_ptr ) {
/* single % at the end, drop that */
case 0 :
goto out ;
/* Double percent, output one percent */
case ' % ' :
if ( out_ptr = = out_end )
goto out ;
* out_ptr + + = ' % ' ;
err = cn_printf ( cn , " %c " , ' % ' ) ;
break ;
/* pid */
case ' p ' :
pid_in_pattern = 1 ;
rc = snprintf ( out_ptr , out_end - out_ptr ,
" %d " , task_tgid_vnr ( current ) ) ;
if ( rc > out_end - out_ptr )
goto out ;
out_ptr + = rc ;
err = cn_printf ( cn , " %d " ,
task_tgid_vnr ( current ) ) ;
break ;
/* uid */
case ' u ' :
rc = snprintf ( out_ptr , out_end - out_ptr ,
" %d " , cred - > uid ) ;
if ( rc > out_end - out_ptr )
goto out ;
out_ptr + = rc ;
err = cn_printf ( cn , " %d " , cred - > uid ) ;
break ;
/* gid */
case ' g ' :
rc = snprintf ( out_ptr , out_end - out_ptr ,
" %d " , cred - > gid ) ;
if ( rc > out_end - out_ptr )
goto out ;
out_ptr + = rc ;
err = cn_printf ( cn , " %d " , cred - > gid ) ;
break ;
/* signal that caused the coredump */
case ' s ' :
rc = snprintf ( out_ptr , out_end - out_ptr ,
" %ld " , signr ) ;
if ( rc > out_end - out_ptr )
goto out ;
out_ptr + = rc ;
err = cn_printf ( cn , " %ld " , signr ) ;
break ;
/* UNIX time of coredump */
case ' t ' : {
struct timeval tv ;
do_gettimeofday ( & tv ) ;
rc = snprintf ( out_ptr , out_end - out_ptr ,
" %lu " , tv . tv_sec ) ;
if ( rc > out_end - out_ptr )
goto out ;
out_ptr + = rc ;
err = cn_printf ( cn , " %lu " , tv . tv_sec ) ;
break ;
}
/* hostname */
case ' h ' :
down_read ( & uts_sem ) ;
rc = snprintf ( out_ptr , out_end - out_ptr ,
" %s " , utsname ( ) - > nodename ) ;
err = cn_printf ( cn , " %s " ,
utsname ( ) - > nodename ) ;
up_read ( & uts_sem ) ;
if ( rc > out_end - out_ptr )
goto out ;
out_ptr + = rc ;
break ;
/* executable */
case ' e ' :
rc = snprintf ( out_ptr , out_end - out_ptr ,
" %s " , current - > comm ) ;
if ( rc > out_end - out_ptr )
goto out ;
out_ptr + = rc ;
err = cn_printf ( cn , " %s " , current - > comm ) ;
break ;
/* core limit size */
case ' c ' :
rc = snprintf ( out_ptr , out_end - out_ptr ,
" %lu " , rlimit ( RLIMIT_CORE ) ) ;
if ( rc > out_end - out_ptr )
goto out ;
out_ptr + = rc ;
err = cn_printf ( cn , " %lu " ,
rlimit ( RLIMIT_CORE ) ) ;
break ;
default :
break ;
}
+ + pat_ptr ;
}
if ( err )
return err ;
}
/* Backward compatibility with core_uses_pid:
*
* If core_pattern does not include a % p ( as is the default )
* and core_uses_pid is set , then . % pid will be appended to
* the filename . Do not do this for piped commands . */
if ( ! ispipe & & ! pid_in_pattern & & core_uses_pid ) {
rc = snprintf ( out_ptr , out_end - out_ptr ,
" .%d " , task_tgid_vnr ( current ) ) ;
if ( rc > out_end - out_ptr )
goto out ;
out_ptr + = rc ;
err = cn_printf ( cn , " .%d " , task_tgid_vnr ( current ) ) ;
if ( err )
return err ;
}
out :
* out_ptr = 0 ;
return ispipe ;
}
@ -1856,7 +1883,7 @@ static int umh_pipe_setup(struct subprocess_info *info)
void do_coredump ( long signr , int exit_code , struct pt_regs * regs )
{
struct core_state core_state ;
char corename [ CORENAME_MAX_SIZE + 1 ] ;
struct core_name cn ;
struct mm_struct * mm = current - > mm ;
struct linux_binfmt * binfmt ;
const struct cred * old_cred ;
@ -1911,7 +1938,13 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
*/
clear_thread_flag ( TIF_SIGPENDING ) ;
ispipe = format_corename ( corename , signr ) ;
ispipe = format_corename ( & cn , signr ) ;
if ( ispipe = = - ENOMEM ) {
printk ( KERN_WARNING " format_corename failed \n " ) ;
printk ( KERN_WARNING " Aborting core \n " ) ;
goto fail_corename ;
}
if ( ispipe ) {
int dump_count ;
@ -1948,7 +1981,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
goto fail_dropcount ;
}
helper_argv = argv_split ( GFP_KERNEL , corename + 1 , NULL ) ;
helper_argv = argv_split ( GFP_KERNEL , cn . c orename + 1 , NULL ) ;
if ( ! helper_argv ) {
printk ( KERN_WARNING " %s failed to allocate memory \n " ,
__func__ ) ;
@ -1961,7 +1994,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
argv_free ( helper_argv ) ;
if ( retval ) {
printk ( KERN_INFO " Core dump to %s pipe failed \n " ,
corename ) ;
cn . c orename ) ;
goto close_fail ;
}
} else {
@ -1970,7 +2003,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
if ( cprm . limit < binfmt - > min_coredump )
goto fail_unlock ;
cprm . file = filp_open ( corename ,
cprm . file = filp_open ( cn . c orename ,
O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag ,
0600 ) ;
if ( IS_ERR ( cprm . file ) )
@ -2012,6 +2045,8 @@ fail_dropcount:
if ( ispipe )
atomic_dec ( & core_dump_count ) ;
fail_unlock :
kfree ( cn . corename ) ;
fail_corename :
coredump_finish ( mm ) ;
revert_creds ( old_cred ) ;
fail_creds :