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) | |||
323 | 323 | ||
324 | if (N_MAGIC(ex) == OMAGIC) { | 324 | if (N_MAGIC(ex) == OMAGIC) { |
325 | unsigned long text_addr, map_size; | 325 | unsigned long text_addr, map_size; |
326 | loff_t pos; | ||
327 | 326 | ||
328 | text_addr = N_TXTADDR(ex); | 327 | text_addr = N_TXTADDR(ex); |
329 | |||
330 | pos = 32; | ||
331 | map_size = ex.a_text+ex.a_data; | 328 | map_size = ex.a_text+ex.a_data; |
332 | 329 | ||
333 | error = vm_brk(text_addr & PAGE_MASK, map_size); | 330 | error = vm_brk(text_addr & PAGE_MASK, map_size); |
@@ -337,15 +334,12 @@ static int load_aout_binary(struct linux_binprm *bprm) | |||
337 | return error; | 334 | return error; |
338 | } | 335 | } |
339 | 336 | ||
340 | error = bprm->file->f_op->read(bprm->file, | 337 | error = read_code(bprm->file, text_addr, 32, |
341 | (char __user *)text_addr, | 338 | ex.a_text + ex.a_data); |
342 | ex.a_text+ex.a_data, &pos); | ||
343 | if ((signed long)error < 0) { | 339 | if ((signed long)error < 0) { |
344 | send_sig(SIGKILL, current, 0); | 340 | send_sig(SIGKILL, current, 0); |
345 | return error; | 341 | return error; |
346 | } | 342 | } |
347 | |||
348 | flush_icache_range(text_addr, text_addr+ex.a_text+ex.a_data); | ||
349 | } else { | 343 | } else { |
350 | #ifdef WARN_OLD | 344 | #ifdef WARN_OLD |
351 | static unsigned long error_time, error_time2; | 345 | static unsigned long error_time, error_time2; |
@@ -367,15 +361,9 @@ static int load_aout_binary(struct linux_binprm *bprm) | |||
367 | #endif | 361 | #endif |
368 | 362 | ||
369 | if (!bprm->file->f_op->mmap || (fd_offset & ~PAGE_MASK) != 0) { | 363 | if (!bprm->file->f_op->mmap || (fd_offset & ~PAGE_MASK) != 0) { |
370 | loff_t pos = fd_offset; | ||
371 | |||
372 | vm_brk(N_TXTADDR(ex), ex.a_text+ex.a_data); | 364 | vm_brk(N_TXTADDR(ex), ex.a_text+ex.a_data); |
373 | bprm->file->f_op->read(bprm->file, | 365 | read_code(bprm->file, N_TXTADDR(ex), fd_offset, |
374 | (char __user *)N_TXTADDR(ex), | 366 | ex.a_text+ex.a_data); |
375 | ex.a_text+ex.a_data, &pos); | ||
376 | flush_icache_range((unsigned long) N_TXTADDR(ex), | ||
377 | (unsigned long) N_TXTADDR(ex) + | ||
378 | ex.a_text+ex.a_data); | ||
379 | goto beyond_if; | 367 | goto beyond_if; |
380 | } | 368 | } |
381 | 369 | ||
@@ -452,8 +440,6 @@ static int load_aout_library(struct file *file) | |||
452 | start_addr = ex.a_entry & 0xfffff000; | 440 | start_addr = ex.a_entry & 0xfffff000; |
453 | 441 | ||
454 | if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) { | 442 | if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) { |
455 | loff_t pos = N_TXTOFF(ex); | ||
456 | |||
457 | #ifdef WARN_OLD | 443 | #ifdef WARN_OLD |
458 | static unsigned long error_time; | 444 | static unsigned long error_time; |
459 | if (time_after(jiffies, error_time + 5*HZ)) { | 445 | if (time_after(jiffies, error_time + 5*HZ)) { |
@@ -466,12 +452,8 @@ static int load_aout_library(struct file *file) | |||
466 | #endif | 452 | #endif |
467 | vm_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss); | 453 | vm_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss); |
468 | 454 | ||
469 | file->f_op->read(file, (char __user *)start_addr, | 455 | read_code(file, start_addr, N_TXTOFF(ex), |
470 | ex.a_text + ex.a_data, &pos); | 456 | ex.a_text + ex.a_data); |
471 | flush_icache_range((unsigned long) start_addr, | ||
472 | (unsigned long) start_addr + ex.a_text + | ||
473 | ex.a_data); | ||
474 | |||
475 | retval = 0; | 457 | retval = 0; |
476 | goto out; | 458 | goto out; |
477 | } | 459 | } |
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) | |||
287 | return error; | 287 | return error; |
288 | } | 288 | } |
289 | 289 | ||
290 | error = bprm->file->f_op->read(bprm->file, | 290 | error = read_code(bprm->file, text_addr, pos, |
291 | (char __user *)text_addr, | 291 | ex.a_text+ex.a_data); |
292 | ex.a_text+ex.a_data, &pos); | ||
293 | if ((signed long)error < 0) { | 292 | if ((signed long)error < 0) { |
294 | send_sig(SIGKILL, current, 0); | 293 | send_sig(SIGKILL, current, 0); |
295 | return error; | 294 | return error; |
296 | } | 295 | } |
297 | |||
298 | flush_icache_range(text_addr, text_addr+ex.a_text+ex.a_data); | ||
299 | } else { | 296 | } else { |
300 | if ((ex.a_text & 0xfff || ex.a_data & 0xfff) && | 297 | if ((ex.a_text & 0xfff || ex.a_data & 0xfff) && |
301 | (N_MAGIC(ex) != NMAGIC) && printk_ratelimit()) | 298 | (N_MAGIC(ex) != NMAGIC) && printk_ratelimit()) |
@@ -311,14 +308,9 @@ static int load_aout_binary(struct linux_binprm * bprm) | |||
311 | } | 308 | } |
312 | 309 | ||
313 | if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) { | 310 | if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) { |
314 | loff_t pos = fd_offset; | ||
315 | vm_brk(N_TXTADDR(ex), ex.a_text+ex.a_data); | 311 | vm_brk(N_TXTADDR(ex), ex.a_text+ex.a_data); |
316 | bprm->file->f_op->read(bprm->file, | 312 | read_code(bprm->file, N_TXTADDR(ex), fd_offset, |
317 | (char __user *)N_TXTADDR(ex), | 313 | ex.a_text + ex.a_data); |
318 | ex.a_text+ex.a_data, &pos); | ||
319 | flush_icache_range((unsigned long) N_TXTADDR(ex), | ||
320 | (unsigned long) N_TXTADDR(ex) + | ||
321 | ex.a_text+ex.a_data); | ||
322 | goto beyond_if; | 314 | goto beyond_if; |
323 | } | 315 | } |
324 | 316 | ||
@@ -397,8 +389,6 @@ static int load_aout_library(struct file *file) | |||
397 | start_addr = ex.a_entry & 0xfffff000; | 389 | start_addr = ex.a_entry & 0xfffff000; |
398 | 390 | ||
399 | if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) { | 391 | if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) { |
400 | loff_t pos = N_TXTOFF(ex); | ||
401 | |||
402 | if (printk_ratelimit()) | 392 | if (printk_ratelimit()) |
403 | { | 393 | { |
404 | printk(KERN_WARNING | 394 | printk(KERN_WARNING |
@@ -407,11 +397,8 @@ static int load_aout_library(struct file *file) | |||
407 | } | 397 | } |
408 | vm_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss); | 398 | vm_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss); |
409 | 399 | ||
410 | file->f_op->read(file, (char __user *)start_addr, | 400 | read_code(file, start_addr, N_TXTOFF(ex), |
411 | ex.a_text + ex.a_data, &pos); | 401 | ex.a_text + ex.a_data); |
412 | flush_icache_range((unsigned long) start_addr, | ||
413 | (unsigned long) start_addr + ex.a_text + ex.a_data); | ||
414 | |||
415 | retval = 0; | 402 | retval = 0; |
416 | goto out; | 403 | goto out; |
417 | } | 404 | } |
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( | |||
926 | struct elf32_fdpic_loadseg *seg; | 926 | struct elf32_fdpic_loadseg *seg; |
927 | struct elf32_phdr *phdr; | 927 | struct elf32_phdr *phdr; |
928 | unsigned long load_addr, base = ULONG_MAX, top = 0, maddr = 0, mflags; | 928 | unsigned long load_addr, base = ULONG_MAX, top = 0, maddr = 0, mflags; |
929 | loff_t fpos; | ||
930 | int loop, ret; | 929 | int loop, ret; |
931 | 930 | ||
932 | load_addr = params->load_addr; | 931 | load_addr = params->load_addr; |
@@ -964,14 +963,12 @@ static int elf_fdpic_map_file_constdisp_on_uclinux( | |||
964 | if (params->phdrs[loop].p_type != PT_LOAD) | 963 | if (params->phdrs[loop].p_type != PT_LOAD) |
965 | continue; | 964 | continue; |
966 | 965 | ||
967 | fpos = phdr->p_offset; | ||
968 | |||
969 | seg->addr = maddr + (phdr->p_vaddr - base); | 966 | seg->addr = maddr + (phdr->p_vaddr - base); |
970 | seg->p_vaddr = phdr->p_vaddr; | 967 | seg->p_vaddr = phdr->p_vaddr; |
971 | seg->p_memsz = phdr->p_memsz; | 968 | seg->p_memsz = phdr->p_memsz; |
972 | 969 | ||
973 | ret = file->f_op->read(file, (void *) seg->addr, | 970 | ret = read_code(file, seg->addr, phdr->p_offset, |
974 | phdr->p_filesz, &fpos); | 971 | phdr->p_filesz); |
975 | if (ret < 0) | 972 | if (ret < 0) |
976 | return ret; | 973 | return ret; |
977 | 974 | ||
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( | |||
207 | 207 | ||
208 | /* Read in first chunk of data and parse gzip header. */ | 208 | /* Read in first chunk of data and parse gzip header. */ |
209 | fpos = offset; | 209 | fpos = offset; |
210 | ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos); | 210 | ret = kernel_read(bprm->file, offset, buf, LBUFSIZE); |
211 | 211 | ||
212 | strm.next_in = buf; | 212 | strm.next_in = buf; |
213 | strm.avail_in = ret; | 213 | strm.avail_in = ret; |
214 | strm.total_in = 0; | 214 | strm.total_in = 0; |
215 | fpos += ret; | ||
215 | 216 | ||
216 | retval = -ENOEXEC; | 217 | retval = -ENOEXEC; |
217 | 218 | ||
@@ -277,7 +278,7 @@ static int decompress_exec( | |||
277 | } | 278 | } |
278 | 279 | ||
279 | while ((ret = zlib_inflate(&strm, Z_NO_FLUSH)) == Z_OK) { | 280 | while ((ret = zlib_inflate(&strm, Z_NO_FLUSH)) == Z_OK) { |
280 | ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos); | 281 | ret = kernel_read(bprm->file, fpos, buf, LBUFSIZE); |
281 | if (ret <= 0) | 282 | if (ret <= 0) |
282 | break; | 283 | break; |
283 | len -= ret; | 284 | len -= ret; |
@@ -285,6 +286,7 @@ static int decompress_exec( | |||
285 | strm.next_in = buf; | 286 | strm.next_in = buf; |
286 | strm.avail_in = ret; | 287 | strm.avail_in = ret; |
287 | strm.total_in = 0; | 288 | strm.total_in = 0; |
289 | fpos += ret; | ||
288 | } | 290 | } |
289 | 291 | ||
290 | if (ret < 0) { | 292 | if (ret < 0) { |
@@ -428,6 +430,7 @@ static int load_flat_file(struct linux_binprm * bprm, | |||
428 | unsigned long textpos = 0, datapos = 0, result; | 430 | unsigned long textpos = 0, datapos = 0, result; |
429 | unsigned long realdatastart = 0; | 431 | unsigned long realdatastart = 0; |
430 | unsigned long text_len, data_len, bss_len, stack_len, flags; | 432 | unsigned long text_len, data_len, bss_len, stack_len, flags; |
433 | unsigned long full_data; | ||
431 | unsigned long len, memp = 0; | 434 | unsigned long len, memp = 0; |
432 | unsigned long memp_size, extra, rlim; | 435 | unsigned long memp_size, extra, rlim; |
433 | unsigned long *reloc = 0, *rp; | 436 | unsigned long *reloc = 0, *rp; |
@@ -451,6 +454,7 @@ static int load_flat_file(struct linux_binprm * bprm, | |||
451 | relocs = ntohl(hdr->reloc_count); | 454 | relocs = ntohl(hdr->reloc_count); |
452 | flags = ntohl(hdr->flags); | 455 | flags = ntohl(hdr->flags); |
453 | rev = ntohl(hdr->rev); | 456 | rev = ntohl(hdr->rev); |
457 | full_data = data_len + relocs * sizeof(unsigned long); | ||
454 | 458 | ||
455 | if (strncmp(hdr->magic, "bFLT", 4)) { | 459 | if (strncmp(hdr->magic, "bFLT", 4)) { |
456 | /* | 460 | /* |
@@ -577,12 +581,12 @@ static int load_flat_file(struct linux_binprm * bprm, | |||
577 | #ifdef CONFIG_BINFMT_ZFLAT | 581 | #ifdef CONFIG_BINFMT_ZFLAT |
578 | if (flags & FLAT_FLAG_GZDATA) { | 582 | if (flags & FLAT_FLAG_GZDATA) { |
579 | result = decompress_exec(bprm, fpos, (char *) datapos, | 583 | result = decompress_exec(bprm, fpos, (char *) datapos, |
580 | data_len + (relocs * sizeof(unsigned long)), 0); | 584 | full_data, 0); |
581 | } else | 585 | } else |
582 | #endif | 586 | #endif |
583 | { | 587 | { |
584 | result = bprm->file->f_op->read(bprm->file, (char *) datapos, | 588 | result = read_code(bprm->file, datapos, fpos, |
585 | data_len + (relocs * sizeof(unsigned long)), &fpos); | 589 | full_data); |
586 | } | 590 | } |
587 | if (IS_ERR_VALUE(result)) { | 591 | if (IS_ERR_VALUE(result)) { |
588 | printk("Unable to read data+bss, errno %d\n", (int)-result); | 592 | printk("Unable to read data+bss, errno %d\n", (int)-result); |
@@ -627,30 +631,25 @@ static int load_flat_file(struct linux_binprm * bprm, | |||
627 | if (flags & FLAT_FLAG_GZIP) { | 631 | if (flags & FLAT_FLAG_GZIP) { |
628 | result = decompress_exec(bprm, sizeof (struct flat_hdr), | 632 | result = decompress_exec(bprm, sizeof (struct flat_hdr), |
629 | (((char *) textpos) + sizeof (struct flat_hdr)), | 633 | (((char *) textpos) + sizeof (struct flat_hdr)), |
630 | (text_len + data_len + (relocs * sizeof(unsigned long)) | 634 | (text_len + full_data |
631 | - sizeof (struct flat_hdr)), | 635 | - sizeof (struct flat_hdr)), |
632 | 0); | 636 | 0); |
633 | memmove((void *) datapos, (void *) realdatastart, | 637 | memmove((void *) datapos, (void *) realdatastart, |
634 | data_len + (relocs * sizeof(unsigned long))); | 638 | full_data); |
635 | } else if (flags & FLAT_FLAG_GZDATA) { | 639 | } else if (flags & FLAT_FLAG_GZDATA) { |
636 | fpos = 0; | 640 | result = read_code(bprm->file, textpos, 0, text_len); |
637 | result = bprm->file->f_op->read(bprm->file, | ||
638 | (char *) textpos, text_len, &fpos); | ||
639 | if (!IS_ERR_VALUE(result)) | 641 | if (!IS_ERR_VALUE(result)) |
640 | result = decompress_exec(bprm, text_len, (char *) datapos, | 642 | result = decompress_exec(bprm, text_len, (char *) datapos, |
641 | data_len + (relocs * sizeof(unsigned long)), 0); | 643 | full_data, 0); |
642 | } | 644 | } |
643 | else | 645 | else |
644 | #endif | 646 | #endif |
645 | { | 647 | { |
646 | fpos = 0; | 648 | result = read_code(bprm->file, textpos, 0, text_len); |
647 | result = bprm->file->f_op->read(bprm->file, | 649 | if (!IS_ERR_VALUE(result)) |
648 | (char *) textpos, text_len, &fpos); | 650 | result = read_code(bprm->file, datapos, |
649 | if (!IS_ERR_VALUE(result)) { | 651 | ntohl(hdr->data_start), |
650 | fpos = ntohl(hdr->data_start); | 652 | full_data); |
651 | result = bprm->file->f_op->read(bprm->file, (char *) datapos, | ||
652 | data_len + (relocs * sizeof(unsigned long)), &fpos); | ||
653 | } | ||
654 | } | 653 | } |
655 | if (IS_ERR_VALUE(result)) { | 654 | if (IS_ERR_VALUE(result)) { |
656 | printk("Unable to read code+data+bss, errno %d\n",(int)-result); | 655 | printk("Unable to read code+data+bss, errno %d\n",(int)-result); |
@@ -802,6 +802,15 @@ int kernel_read(struct file *file, loff_t offset, | |||
802 | 802 | ||
803 | EXPORT_SYMBOL(kernel_read); | 803 | EXPORT_SYMBOL(kernel_read); |
804 | 804 | ||
805 | ssize_t read_code(struct file *file, unsigned long addr, loff_t pos, size_t len) | ||
806 | { | ||
807 | ssize_t res = file->f_op->read(file, (void __user *)addr, len, &pos); | ||
808 | if (res > 0) | ||
809 | flush_icache_range(addr, addr + len); | ||
810 | return res; | ||
811 | } | ||
812 | EXPORT_SYMBOL(read_code); | ||
813 | |||
805 | static int exec_mmap(struct mm_struct *mm) | 814 | static int exec_mmap(struct mm_struct *mm) |
806 | { | 815 | { |
807 | struct task_struct *tsk; | 816 | 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); | |||
118 | extern void install_exec_creds(struct linux_binprm *bprm); | 118 | extern void install_exec_creds(struct linux_binprm *bprm); |
119 | extern void set_binfmt(struct linux_binfmt *new); | 119 | extern void set_binfmt(struct linux_binfmt *new); |
120 | extern void free_bprm(struct linux_binprm *); | 120 | extern void free_bprm(struct linux_binprm *); |
121 | extern ssize_t read_code(struct file *, unsigned long, loff_t, size_t); | ||
121 | 122 | ||
122 | #endif /* _LINUX_BINFMTS_H */ | 123 | #endif /* _LINUX_BINFMTS_H */ |