diff options
Diffstat (limited to 'fs/exec.c')
| -rw-r--r-- | fs/exec.c | 77 | 
1 files changed, 53 insertions, 24 deletions
diff --git a/fs/exec.c b/fs/exec.c index 842d5700c15..25dcbe5fc35 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -181,14 +181,7 @@ static void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)  		return;  	bprm->vma_pages = pages; - -#ifdef SPLIT_RSS_COUNTING -	add_mm_counter(mm, MM_ANONPAGES, diff); -#else -	spin_lock(&mm->page_table_lock);  	add_mm_counter(mm, MM_ANONPAGES, diff); -	spin_unlock(&mm->page_table_lock); -#endif  }  static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, @@ -277,7 +270,7 @@ static int __bprm_mm_init(struct linux_binprm *bprm)  	 * use STACK_TOP because that can depend on attributes which aren't  	 * configured yet.  	 */ -	BUG_ON(VM_STACK_FLAGS & VM_STACK_INCOMPLETE_SETUP); +	BUILD_BUG_ON(VM_STACK_FLAGS & VM_STACK_INCOMPLETE_SETUP);  	vma->vm_end = STACK_TOP_MAX;  	vma->vm_start = vma->vm_end - PAGE_SIZE;  	vma->vm_flags = VM_STACK_FLAGS | VM_STACK_INCOMPLETE_SETUP; @@ -1430,9 +1423,9 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)  			}  		}  		read_unlock(&binfmt_lock); +#ifdef CONFIG_MODULES  		if (retval != -ENOEXEC || bprm->mm == NULL) {  			break; -#ifdef CONFIG_MODULES  		} else {  #define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e))  			if (printable(bprm->buf[0]) && @@ -1440,9 +1433,13 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)  			    printable(bprm->buf[2]) &&  			    printable(bprm->buf[3]))  				break; /* -ENOEXEC */ +			if (try) +				break; /* -ENOEXEC */  			request_module("binfmt-%04x", *(unsigned short *)(&bprm->buf[2])); -#endif  		} +#else +		break; +#endif  	}  	return retval;  } @@ -1462,6 +1459,23 @@ static int do_execve_common(const char *filename,  	struct files_struct *displaced;  	bool clear_in_exec;  	int retval; +	const struct cred *cred = current_cred(); + +	/* +	 * We move the actual failure in case of RLIMIT_NPROC excess from +	 * set*uid() to execve() because too many poorly written programs +	 * don't check setuid() return code.  Here we additionally recheck +	 * whether NPROC limit is still exceeded. +	 */ +	if ((current->flags & PF_NPROC_EXCEEDED) && +	    atomic_read(&cred->user->processes) > rlimit(RLIMIT_NPROC)) { +		retval = -EAGAIN; +		goto out_ret; +	} + +	/* We're below the limit (still or again), so we don't want to make +	 * further execve() calls fail. */ +	current->flags &= ~PF_NPROC_EXCEEDED;  	retval = unshare_files(&displaced);  	if (retval) @@ -1649,15 +1663,26 @@ expand_fail:  	return ret;  } +static void cn_escape(char *str) +{ +	for (; *str; str++) +		if (*str == '/') +			*str = '!'; +} +  static int cn_print_exe_file(struct core_name *cn)  {  	struct file *exe_file; -	char *pathbuf, *path, *p; +	char *pathbuf, *path;  	int ret;  	exe_file = get_mm_exe_file(current->mm); -	if (!exe_file) -		return cn_printf(cn, "(unknown)"); +	if (!exe_file) { +		char *commstart = cn->corename + cn->used; +		ret = cn_printf(cn, "%s (path unknown)", current->comm); +		cn_escape(commstart); +		return ret; +	}  	pathbuf = kmalloc(PATH_MAX, GFP_TEMPORARY);  	if (!pathbuf) { @@ -1671,9 +1696,7 @@ static int cn_print_exe_file(struct core_name *cn)  		goto free_buf;  	} -	for (p = path; *p; p++) -		if (*p == '/') -			*p = '!'; +	cn_escape(path);  	ret = cn_printf(cn, "%s", path); @@ -1745,16 +1768,22 @@ static int format_corename(struct core_name *cn, long signr)  				break;  			}  			/* hostname */ -			case 'h': +			case 'h': { +				char *namestart = cn->corename + cn->used;  				down_read(&uts_sem);  				err = cn_printf(cn, "%s",  					      utsname()->nodename);  				up_read(&uts_sem); +				cn_escape(namestart);  				break; +			}  			/* executable */ -			case 'e': +			case 'e': { +				char *commstart = cn->corename + cn->used;  				err = cn_printf(cn, "%s", current->comm); +				cn_escape(commstart);  				break; +			}  			case 'E':  				err = cn_print_exe_file(cn);  				break; @@ -2118,16 +2147,16 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)  	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;  		char **helper_argv; +		if (ispipe < 0) { +			printk(KERN_WARNING "format_corename failed\n"); +			printk(KERN_WARNING "Aborting core\n"); +			goto fail_corename; +		} +  		if (cprm.limit == 1) {  			/*  			 * Normally core limits are irrelevant to pipes, since  |