diff options
author | Marcelo Tosatti <marcelo.tosatti@cyclades.com> | 2005-01-11 16:12:09 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-01-11 16:12:09 -0800 |
commit | 6a424edaddfcd5b68be2e1e641962764b57d7680 (patch) | |
tree | 4b2a8197472ae861ea6595a781c2521dff9087c1 /fs | |
parent | fa6e49a2497cb4298d81c0d384c1ade8bcf1f0a3 (diff) | |
download | history-6a424edaddfcd5b68be2e1e641962764b57d7680.tar.gz |
[PATCH] do_brk() needs mmap_sem write-locked
It seems to be general consensus that its safer to require all do_brk() callers
to grab mmap_sem, and have do_brk to warn otherwise. This is what the following
patch does.
Similar version has been changed to in v2.4.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/binfmt_aout.c | 17 | ||||
-rw-r--r-- | fs/binfmt_elf.c | 12 |
2 files changed, 25 insertions, 4 deletions
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index 8075fdff23646c..a53d9a9e0de4ae 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -50,7 +50,10 @@ static int set_brk(unsigned long start, unsigned long end) start = PAGE_ALIGN(start); end = PAGE_ALIGN(end); if (end > start) { - unsigned long addr = do_brk(start, end - start); + unsigned long addr; + down_write(¤t->mm->mmap_sem); + addr = do_brk(start, end - start); + up_write(¤t->mm->mmap_sem); if (BAD_ADDR(addr)) return addr; } @@ -323,10 +326,14 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) loff_t pos = fd_offset; /* Fuck me plenty... */ /* <AOL></AOL> */ + down_write(¤t->mm->mmap_sem); error = do_brk(N_TXTADDR(ex), ex.a_text); + up_write(¤t->mm->mmap_sem); bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex), ex.a_text, &pos); + down_write(¤t->mm->mmap_sem); error = do_brk(N_DATADDR(ex), ex.a_data); + up_write(¤t->mm->mmap_sem); bprm->file->f_op->read(bprm->file, (char *) N_DATADDR(ex), ex.a_data, &pos); goto beyond_if; @@ -346,8 +353,9 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) pos = 32; map_size = ex.a_text+ex.a_data; #endif - + down_write(¤t->mm->mmap_sem); error = do_brk(text_addr & PAGE_MASK, map_size); + up_write(¤t->mm->mmap_sem); if (error != (text_addr & PAGE_MASK)) { send_sig(SIGKILL, current, 0); return error; @@ -382,7 +390,9 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) { loff_t pos = fd_offset; + down_write(¤t->mm->mmap_sem); do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data); + up_write(¤t->mm->mmap_sem); bprm->file->f_op->read(bprm->file, (char __user *)N_TXTADDR(ex), ex.a_text+ex.a_data, &pos); @@ -487,8 +497,9 @@ static int load_aout_library(struct file *file) file->f_dentry->d_name.name); error_time = jiffies; } - + down_write(¤t->mm->mmap_sem); do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss); + up_write(¤t->mm->mmap_sem); file->f_op->read(file, (char __user *)start_addr, ex.a_text + ex.a_data, &pos); diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index a66bc8df6d6f9b..6eb6971bdee2b1 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -88,7 +88,10 @@ static int set_brk(unsigned long start, unsigned long end) start = ELF_PAGEALIGN(start); end = ELF_PAGEALIGN(end); if (end > start) { - unsigned long addr = do_brk(start, end - start); + unsigned long addr; + down_write(¤t->mm->mmap_sem); + addr = do_brk(start, end - start); + up_write(¤t->mm->mmap_sem); if (BAD_ADDR(addr)) return addr; } @@ -409,7 +412,9 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, /* Map the last of the bss segment */ if (last_bss > elf_bss) { + down_write(¤t->mm->mmap_sem); error = do_brk(elf_bss, last_bss - elf_bss); + up_write(¤t->mm->mmap_sem); if (BAD_ADDR(error)) goto out_close; } @@ -449,7 +454,9 @@ static unsigned long load_aout_interp(struct exec * interp_ex, goto out; } + down_write(¤t->mm->mmap_sem); do_brk(0, text_data); + up_write(¤t->mm->mmap_sem); if (!interpreter->f_op || !interpreter->f_op->read) goto out; if (interpreter->f_op->read(interpreter, addr, text_data, &offset) < 0) @@ -457,8 +464,11 @@ static unsigned long load_aout_interp(struct exec * interp_ex, flush_icache_range((unsigned long)addr, (unsigned long)addr + text_data); + + down_write(¤t->mm->mmap_sem); do_brk(ELF_PAGESTART(text_data + ELF_MIN_ALIGN - 1), interp_ex->a_bss); + up_write(¤t->mm->mmap_sem); elf_entry = interp_ex->a_entry; out: |