aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMarcelo Tosatti <marcelo.tosatti@cyclades.com>2005-01-11 16:12:09 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-01-11 16:12:09 -0800
commit6a424edaddfcd5b68be2e1e641962764b57d7680 (patch)
tree4b2a8197472ae861ea6595a781c2521dff9087c1 /fs
parentfa6e49a2497cb4298d81c0d384c1ade8bcf1f0a3 (diff)
downloadhistory-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.c17
-rw-r--r--fs/binfmt_elf.c12
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(&current->mm->mmap_sem);
+ addr = do_brk(start, end - start);
+ up_write(&current->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(&current->mm->mmap_sem);
error = do_brk(N_TXTADDR(ex), ex.a_text);
+ up_write(&current->mm->mmap_sem);
bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
ex.a_text, &pos);
+ down_write(&current->mm->mmap_sem);
error = do_brk(N_DATADDR(ex), ex.a_data);
+ up_write(&current->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(&current->mm->mmap_sem);
error = do_brk(text_addr & PAGE_MASK, map_size);
+ up_write(&current->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(&current->mm->mmap_sem);
do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
+ up_write(&current->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(&current->mm->mmap_sem);
do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
+ up_write(&current->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(&current->mm->mmap_sem);
+ addr = do_brk(start, end - start);
+ up_write(&current->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(&current->mm->mmap_sem);
error = do_brk(elf_bss, last_bss - elf_bss);
+ up_write(&current->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(&current->mm->mmap_sem);
do_brk(0, text_data);
+ up_write(&current->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(&current->mm->mmap_sem);
do_brk(ELF_PAGESTART(text_data + ELF_MIN_ALIGN - 1),
interp_ex->a_bss);
+ up_write(&current->mm->mmap_sem);
elf_entry = interp_ex->a_entry;
out: