diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2013-04-13 20:31:37 -0400 | 
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-04-29 15:40:23 -0400 | 
| commit | 3dc20cb282ec03cc4c997130d680c800011ed479 (patch) | |
| tree | d8374e58a433a144c571e193cb0b024374ee0b6a | |
| parent | 3af0761307d04f6b9a4626fb80011a22c143d75e (diff) | |
new helper: read_code()
switch binfmts that use ->read() to that (and to kernel_read()
in several cases in binfmt_flat - sure, it's nommu, but still,
doing ->read() into kmalloc'ed buffer...)
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| -rw-r--r-- | arch/x86/ia32/ia32_aout.c | 30 | ||||
| -rw-r--r-- | fs/binfmt_aout.c | 25 | ||||
| -rw-r--r-- | fs/binfmt_elf_fdpic.c | 7 | ||||
| -rw-r--r-- | fs/binfmt_flat.c | 37 | ||||
| -rw-r--r-- | fs/exec.c | 9 | ||||
| -rw-r--r-- | include/linux/binfmts.h | 1 | 
6 files changed, 42 insertions, 67 deletions
| diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c index 03abf9b70011..03d721cbbc32 100644 --- a/arch/x86/ia32/ia32_aout.c +++ b/arch/x86/ia32/ia32_aout.c @@ -323,11 +323,8 @@ static int load_aout_binary(struct linux_binprm *bprm)  	if (N_MAGIC(ex) == OMAGIC) {  		unsigned long text_addr, map_size; -		loff_t pos;  		text_addr = N_TXTADDR(ex); - -		pos = 32;  		map_size = ex.a_text+ex.a_data;  		error = vm_brk(text_addr & PAGE_MASK, map_size); @@ -337,15 +334,12 @@ static int load_aout_binary(struct linux_binprm *bprm)  			return error;  		} -		error = bprm->file->f_op->read(bprm->file, -			 (char __user *)text_addr, -			  ex.a_text+ex.a_data, &pos); +		error = read_code(bprm->file, text_addr, 32, +				  ex.a_text + ex.a_data);  		if ((signed long)error < 0) {  			send_sig(SIGKILL, current, 0);  			return error;  		} - -		flush_icache_range(text_addr, text_addr+ex.a_text+ex.a_data);  	} else {  #ifdef WARN_OLD  		static unsigned long error_time, error_time2; @@ -367,15 +361,9 @@ static int load_aout_binary(struct linux_binprm *bprm)  #endif  		if (!bprm->file->f_op->mmap || (fd_offset & ~PAGE_MASK) != 0) { -			loff_t pos = fd_offset; -  			vm_brk(N_TXTADDR(ex), ex.a_text+ex.a_data); -			bprm->file->f_op->read(bprm->file, -					(char __user *)N_TXTADDR(ex), -					ex.a_text+ex.a_data, &pos); -			flush_icache_range((unsigned long) N_TXTADDR(ex), -					   (unsigned long) N_TXTADDR(ex) + -					   ex.a_text+ex.a_data); +			read_code(bprm->file, N_TXTADDR(ex), fd_offset, +					ex.a_text+ex.a_data);  			goto beyond_if;  		} @@ -452,8 +440,6 @@ static int load_aout_library(struct file *file)  	start_addr =  ex.a_entry & 0xfffff000;  	if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) { -		loff_t pos = N_TXTOFF(ex); -  #ifdef WARN_OLD  		static unsigned long error_time;  		if (time_after(jiffies, error_time + 5*HZ)) { @@ -466,12 +452,8 @@ static int load_aout_library(struct file *file)  #endif  		vm_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss); -		file->f_op->read(file, (char __user *)start_addr, -			ex.a_text + ex.a_data, &pos); -		flush_icache_range((unsigned long) start_addr, -				   (unsigned long) start_addr + ex.a_text + -				   ex.a_data); - +		read_code(file, start_addr, N_TXTOFF(ex), +			  ex.a_text + ex.a_data);  		retval = 0;  		goto out;  	} diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index bbc8f8827eac..b23253df8756 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -287,15 +287,12 @@ static int load_aout_binary(struct linux_binprm * bprm)  			return error;  		} -		error = bprm->file->f_op->read(bprm->file, -			  (char __user *)text_addr, -			  ex.a_text+ex.a_data, &pos); +		error = read_code(bprm->file, text_addr, pos, +				  ex.a_text+ex.a_data);  		if ((signed long)error < 0) {  			send_sig(SIGKILL, current, 0);  			return error;  		} -			  -		flush_icache_range(text_addr, text_addr+ex.a_text+ex.a_data);  	} else {  		if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&  		    (N_MAGIC(ex) != NMAGIC) && printk_ratelimit()) @@ -311,14 +308,9 @@ static int load_aout_binary(struct linux_binprm * bprm)  		}  		if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) { -			loff_t pos = fd_offset;  			vm_brk(N_TXTADDR(ex), ex.a_text+ex.a_data); -			bprm->file->f_op->read(bprm->file, -					(char __user *)N_TXTADDR(ex), -					ex.a_text+ex.a_data, &pos); -			flush_icache_range((unsigned long) N_TXTADDR(ex), -					   (unsigned long) N_TXTADDR(ex) + -					   ex.a_text+ex.a_data); +			read_code(bprm->file, N_TXTADDR(ex), fd_offset, +				  ex.a_text + ex.a_data);  			goto beyond_if;  		} @@ -397,8 +389,6 @@ static int load_aout_library(struct file *file)  	start_addr =  ex.a_entry & 0xfffff000;  	if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) { -		loff_t pos = N_TXTOFF(ex); -  		if (printk_ratelimit())  		{  			printk(KERN_WARNING  @@ -407,11 +397,8 @@ static int load_aout_library(struct file *file)  		}  		vm_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss); -		file->f_op->read(file, (char __user *)start_addr, -			ex.a_text + ex.a_data, &pos); -		flush_icache_range((unsigned long) start_addr, -				   (unsigned long) start_addr + ex.a_text + ex.a_data); - +		read_code(file, start_addr, N_TXTOFF(ex), +			  ex.a_text + ex.a_data);  		retval = 0;  		goto out;  	} diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 9c13e023e2b7..2711d9901632 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -926,7 +926,6 @@ static int elf_fdpic_map_file_constdisp_on_uclinux(  	struct elf32_fdpic_loadseg *seg;  	struct elf32_phdr *phdr;  	unsigned long load_addr, base = ULONG_MAX, top = 0, maddr = 0, mflags; -	loff_t fpos;  	int loop, ret;  	load_addr = params->load_addr; @@ -964,14 +963,12 @@ static int elf_fdpic_map_file_constdisp_on_uclinux(  		if (params->phdrs[loop].p_type != PT_LOAD)  			continue; -		fpos = phdr->p_offset; -  		seg->addr = maddr + (phdr->p_vaddr - base);  		seg->p_vaddr = phdr->p_vaddr;  		seg->p_memsz = phdr->p_memsz; -		ret = file->f_op->read(file, (void *) seg->addr, -				       phdr->p_filesz, &fpos); +		ret = read_code(file, seg->addr, phdr->p_offset, +				       phdr->p_filesz);  		if (ret < 0)  			return ret; diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 2036d21baaef..d50bbe59da1e 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -207,11 +207,12 @@ static int decompress_exec(  	/* Read in first chunk of data and parse gzip header. */  	fpos = offset; -	ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos); +	ret = kernel_read(bprm->file, offset, buf, LBUFSIZE);  	strm.next_in = buf;  	strm.avail_in = ret;  	strm.total_in = 0; +	fpos += ret;  	retval = -ENOEXEC; @@ -277,7 +278,7 @@ static int decompress_exec(  	}  	while ((ret = zlib_inflate(&strm, Z_NO_FLUSH)) == Z_OK) { -		ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos); +		ret = kernel_read(bprm->file, fpos, buf, LBUFSIZE);  		if (ret <= 0)  			break;  		len -= ret; @@ -285,6 +286,7 @@ static int decompress_exec(  		strm.next_in = buf;  		strm.avail_in = ret;  		strm.total_in = 0; +		fpos += ret;  	}  	if (ret < 0) { @@ -428,6 +430,7 @@ static int load_flat_file(struct linux_binprm * bprm,  	unsigned long textpos = 0, datapos = 0, result;  	unsigned long realdatastart = 0;  	unsigned long text_len, data_len, bss_len, stack_len, flags; +	unsigned long full_data;  	unsigned long len, memp = 0;  	unsigned long memp_size, extra, rlim;  	unsigned long *reloc = 0, *rp; @@ -451,6 +454,7 @@ static int load_flat_file(struct linux_binprm * bprm,  	relocs    = ntohl(hdr->reloc_count);  	flags     = ntohl(hdr->flags);  	rev       = ntohl(hdr->rev); +	full_data = data_len + relocs * sizeof(unsigned long);  	if (strncmp(hdr->magic, "bFLT", 4)) {  		/* @@ -577,12 +581,12 @@ static int load_flat_file(struct linux_binprm * bprm,  #ifdef CONFIG_BINFMT_ZFLAT  		if (flags & FLAT_FLAG_GZDATA) {  			result = decompress_exec(bprm, fpos, (char *) datapos,  -						 data_len + (relocs * sizeof(unsigned long)), 0); +						 full_data, 0);  		} else  #endif  		{ -			result = bprm->file->f_op->read(bprm->file, (char *) datapos, -					data_len + (relocs * sizeof(unsigned long)), &fpos); +			result = read_code(bprm->file, datapos, fpos, +					full_data);  		}  		if (IS_ERR_VALUE(result)) {  			printk("Unable to read data+bss, errno %d\n", (int)-result); @@ -627,30 +631,25 @@ static int load_flat_file(struct linux_binprm * bprm,  		if (flags & FLAT_FLAG_GZIP) {  			result = decompress_exec(bprm, sizeof (struct flat_hdr),  					 (((char *) textpos) + sizeof (struct flat_hdr)), -					 (text_len + data_len + (relocs * sizeof(unsigned long)) +					 (text_len + full_data  						  - sizeof (struct flat_hdr)),  					 0);  			memmove((void *) datapos, (void *) realdatastart, -					data_len + (relocs * sizeof(unsigned long))); +					full_data);  		} else if (flags & FLAT_FLAG_GZDATA) { -			fpos = 0; -			result = bprm->file->f_op->read(bprm->file, -					(char *) textpos, text_len, &fpos); +			result = read_code(bprm->file, textpos, 0, text_len);  			if (!IS_ERR_VALUE(result))  				result = decompress_exec(bprm, text_len, (char *) datapos, -						 data_len + (relocs * sizeof(unsigned long)), 0); +						 full_data, 0);  		}  		else  #endif  		{ -			fpos = 0; -			result = bprm->file->f_op->read(bprm->file, -					(char *) textpos, text_len, &fpos); -			if (!IS_ERR_VALUE(result)) { -				fpos = ntohl(hdr->data_start); -				result = bprm->file->f_op->read(bprm->file, (char *) datapos, -					data_len + (relocs * sizeof(unsigned long)), &fpos); -			} +			result = read_code(bprm->file, textpos, 0, text_len); +			if (!IS_ERR_VALUE(result)) +				result = read_code(bprm->file, datapos, +						   ntohl(hdr->data_start), +						   full_data);  		}  		if (IS_ERR_VALUE(result)) {  			printk("Unable to read code+data+bss, errno %d\n",(int)-result); diff --git a/fs/exec.c b/fs/exec.c index a96a4885bbbf..77dc9096440f 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -802,6 +802,15 @@ int kernel_read(struct file *file, loff_t offset,  EXPORT_SYMBOL(kernel_read); +ssize_t read_code(struct file *file, unsigned long addr, loff_t pos, size_t len) +{ +	ssize_t res = file->f_op->read(file, (void __user *)addr, len, &pos); +	if (res > 0) +		flush_icache_range(addr, addr + len); +	return res; +} +EXPORT_SYMBOL(read_code); +  static int exec_mmap(struct mm_struct *mm)  {  	struct task_struct *tsk; diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index c3a09149f793..70cf138690e9 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -118,5 +118,6 @@ extern int prepare_bprm_creds(struct linux_binprm *bprm);  extern void install_exec_creds(struct linux_binprm *bprm);  extern void set_binfmt(struct linux_binfmt *new);  extern void free_bprm(struct linux_binprm *); +extern ssize_t read_code(struct file *, unsigned long, loff_t, size_t);  #endif /* _LINUX_BINFMTS_H */ | 
