mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	exec: let do_coredump() limit the number of concurrent dumps to pipes
Introduce core pipe limiting sysctl. Since we can dump cores to pipe, rather than directly to the filesystem, we create a condition in which a user can create a very high load on the system simply by running bad applications. If the pipe reader specified in core_pattern is poorly written, we can have lots of ourstandig resources and processes in the system. This sysctl introduces an ability to limit that resource consumption. core_pipe_limit defines how many in-flight dumps may be run in parallel, dumps beyond this value are skipped and a note is made in the kernel log. A special value of 0 in core_pipe_limit denotes unlimited core dumps may be handled (this is the default value). [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Neil Horman <nhorman@tuxdriver.com> Reported-by: Earl Chew <earl_chew@agilent.com> Cc: Oleg Nesterov <oleg@tv-sign.ru> Cc: Andi Kleen <andi@firstfloor.org> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
							parent
							
								
									725eae32df
								
							
						
					
					
						commit
						a293980c2e
					
				
					 3 changed files with 49 additions and 5 deletions
				
			
		|  | @ -22,6 +22,7 @@ show up in /proc/sys/kernel: | |||
| - callhome		     [ S390 only ] | ||||
| - auto_msgmni | ||||
| - core_pattern | ||||
| - core_pipe_limit | ||||
| - core_uses_pid | ||||
| - ctrl-alt-del | ||||
| - dentry-state | ||||
|  | @ -135,6 +136,27 @@ core_pattern is used to specify a core dumpfile pattern name. | |||
| 
 | ||||
| ============================================================== | ||||
| 
 | ||||
| core_pipe_limit: | ||||
| 
 | ||||
| This sysctl is only applicable when core_pattern is configured to pipe core | ||||
| files to user space helper a (when the first character of core_pattern is a '|', | ||||
| see above).  When collecting cores via a pipe to an application, it is | ||||
| occasionally usefull for the collecting application to gather data about the | ||||
| crashing process from its /proc/pid directory.  In order to do this safely, the | ||||
| kernel must wait for the collecting process to exit, so as not to remove the | ||||
| crashing processes proc files prematurely.  This in turn creates the possibility | ||||
| that a misbehaving userspace collecting process can block the reaping of a | ||||
| crashed process simply by never exiting.  This sysctl defends against that.  It | ||||
| defines how many concurrent crashing processes may be piped to user space | ||||
| applications in parallel.  If this value is exceeded, then those crashing | ||||
| processes above that value are noted via the kernel log and their cores are | ||||
| skipped.  0 is a special value, indicating that unlimited processes may be | ||||
| captured in parallel, but that no waiting will take place (i.e. the collecting | ||||
| process is not guaranteed access to /proc/<crahing pid>/).  This value defaults | ||||
| to 0. | ||||
| 
 | ||||
| ============================================================== | ||||
| 
 | ||||
| core_uses_pid: | ||||
| 
 | ||||
| The default coredump filename is "core".  By setting | ||||
|  |  | |||
							
								
								
									
										23
									
								
								fs/exec.c
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								fs/exec.c
									
									
									
									
									
								
							|  | @ -63,6 +63,7 @@ | |||
| 
 | ||||
| int core_uses_pid; | ||||
| char core_pattern[CORENAME_MAX_SIZE] = "core"; | ||||
| unsigned int core_pipe_limit; | ||||
| int suid_dumpable = 0; | ||||
| 
 | ||||
| /* The maximal length of core_pattern is also specified in sysctl.c */ | ||||
|  | @ -1744,7 +1745,8 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
| 	unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; | ||||
| 	char **helper_argv = NULL; | ||||
| 	int helper_argc = 0; | ||||
| 	char *delimit; | ||||
| 	int dump_count = 0; | ||||
| 	static atomic_t core_dump_count = ATOMIC_INIT(0); | ||||
| 
 | ||||
| 	audit_core_dumps(signr); | ||||
| 
 | ||||
|  | @ -1826,28 +1828,36 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
| 			goto fail_unlock; | ||||
| 		} | ||||
| 
 | ||||
| 		dump_count = atomic_inc_return(&core_dump_count); | ||||
| 		if (core_pipe_limit && (core_pipe_limit < dump_count)) { | ||||
| 			printk(KERN_WARNING "Pid %d(%s) over core_pipe_limit\n", | ||||
| 			       task_tgid_vnr(current), current->comm); | ||||
| 			printk(KERN_WARNING "Skipping core dump\n"); | ||||
| 			goto fail_dropcount; | ||||
| 		} | ||||
| 
 | ||||
| 		helper_argv = argv_split(GFP_KERNEL, corename+1, &helper_argc); | ||||
| 		if (!helper_argv) { | ||||
| 			printk(KERN_WARNING "%s failed to allocate memory\n", | ||||
| 			       __func__); | ||||
| 			goto fail_unlock; | ||||
| 			goto fail_dropcount; | ||||
| 		} | ||||
| 
 | ||||
| 		core_limit = RLIM_INFINITY; | ||||
| 
 | ||||
| 		/* SIGPIPE can happen, but it's just never processed */ | ||||
|  		if (call_usermodehelper_pipe(corename+1, helper_argv, NULL, | ||||
| 		if (call_usermodehelper_pipe(helper_argv[0], helper_argv, NULL, | ||||
| 				&file)) { | ||||
|  			printk(KERN_INFO "Core dump to %s pipe failed\n", | ||||
| 			       corename); | ||||
|  			goto fail_unlock; | ||||
| 			goto fail_dropcount; | ||||
|  		} | ||||
|  	} else | ||||
|  		file = filp_open(corename, | ||||
| 				 O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, | ||||
| 				 0600); | ||||
| 	if (IS_ERR(file)) | ||||
| 		goto fail_unlock; | ||||
| 		goto fail_dropcount; | ||||
| 	inode = file->f_path.dentry->d_inode; | ||||
| 	if (inode->i_nlink > 1) | ||||
| 		goto close_fail;	/* multiple links - don't dump */ | ||||
|  | @ -1877,6 +1887,9 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
| 		current->signal->group_exit_code |= 0x80; | ||||
| close_fail: | ||||
| 	filp_close(file, NULL); | ||||
| fail_dropcount: | ||||
| 	if (dump_count) | ||||
| 		atomic_dec(&core_dump_count); | ||||
| fail_unlock: | ||||
| 	if (helper_argv) | ||||
| 		argv_free(helper_argv); | ||||
|  |  | |||
|  | @ -76,6 +76,7 @@ extern int max_threads; | |||
| extern int core_uses_pid; | ||||
| extern int suid_dumpable; | ||||
| extern char core_pattern[]; | ||||
| extern unsigned int core_pipe_limit; | ||||
| extern int pid_max; | ||||
| extern int min_free_kbytes; | ||||
| extern int pid_max_min, pid_max_max; | ||||
|  | @ -423,6 +424,14 @@ static struct ctl_table kern_table[] = { | |||
| 		.proc_handler	= &proc_dostring, | ||||
| 		.strategy	= &sysctl_string, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.ctl_name	= CTL_UNNUMBERED, | ||||
| 		.procname	= "core_pipe_limit", | ||||
| 		.data		= &core_pipe_limit, | ||||
| 		.maxlen		= sizeof(unsigned int), | ||||
| 		.mode		= 0644, | ||||
| 		.proc_handler	= &proc_dointvec, | ||||
| 	}, | ||||
| #ifdef CONFIG_PROC_SYSCTL | ||||
| 	{ | ||||
| 		.procname	= "tainted", | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Neil Horman
						Neil Horman