Re: Fix for new elf_loader bug?

From: Marcelo Tosatti
Date: Fri Jan 07 2005 - 18:19:17 EST


On Sat, Jan 08, 2005 at 12:26:39AM +0200, Vasil Kolev wrote:
> On ????, 2005-01-07 at 15:05 -0200, Marcelo Tosatti wrote:
> > On Fri, Jan 07, 2005 at 04:49:35PM +0100, Frank Steiner wrote:
> > > Hi,
> > >
> > > is there already a patch for the new problem with the elf loader, maybe
> > > in the bitkeeper tree?
> > >
> > > http://www.isec.pl/vulnerabilities/isec-0021-uselib.txt
> >
> > 2.6.10-ac6 contains a fix for the problem - a similar version should hit the BK tree
> > RSN.
>
> Looking at the advisory, it affects 2.4, too, where can a patch for it
> be found?

http://linux.bkbits.net:8080/linux-2.4/patch@xxxxxx?nav=index.html|ChangeSet@-1d|cset@xxxxxx

Attached.

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.1550 -> 1.1551
# kernel/ksyms.c 1.84 -> 1.85
# include/linux/mm.h 1.48 -> 1.49
# fs/binfmt_aout.c 1.9 -> 1.10
# fs/binfmt_elf.c 1.38 -> 1.39
# arch/sparc64/kernel/binfmt_aout32.c 1.6 -> 1.7
# mm/mmap.c 1.35 -> 1.36
# arch/mips/kernel/irixelf.c 1.6 -> 1.7
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 05/01/07 marcelo@xxxxxxxxxx 1.1551
# Paul Starzetz: sys_uselib() race vulnerability (CAN-2004-1235)
#
# http://isec.pl/vulnerabilities/isec-0021-uselib.txt
# --------------------------------------------
#
diff -Nru a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c
--- a/arch/mips/kernel/irixelf.c Fri Jan 7 18:04:11 2005
+++ b/arch/mips/kernel/irixelf.c Fri Jan 7 18:04:11 2005
@@ -130,7 +130,7 @@
end = PAGE_ALIGN(end);
if (end <= start)
return;
- do_brk(start, end - start);
+ do_brk_locked(start, end - start);
}


@@ -379,7 +379,7 @@

/* Map the last of the bss segment */
if (last_bss > len) {
- do_brk(len, (last_bss - len));
+ do_brk_locked(len, (last_bss - len));
}
kfree(elf_phdata);

@@ -567,7 +567,7 @@
unsigned long v;
struct prda *pp;

- v = do_brk (PRDA_ADDRESS, PAGE_SIZE);
+ v = do_brk_locked (PRDA_ADDRESS, PAGE_SIZE);

if (v < 0)
return;
@@ -859,7 +859,7 @@
len = (elf_phdata->p_filesz + elf_phdata->p_vaddr+ 0xfff) & 0xfffff000;
bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
if (bss > len)
- do_brk(len, bss-len);
+ do_brk_locked(len, bss-len);
kfree(elf_phdata);
return 0;
}
diff -Nru a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c
--- a/arch/sparc64/kernel/binfmt_aout32.c Fri Jan 7 18:04:11 2005
+++ b/arch/sparc64/kernel/binfmt_aout32.c Fri Jan 7 18:04:11 2005
@@ -49,7 +49,7 @@
end = PAGE_ALIGN(end);
if (end <= start)
return;
- do_brk(start, end - start);
+ do_brk_locked(start, end - start);
}

/*
@@ -246,10 +246,10 @@
if (N_MAGIC(ex) == NMAGIC) {
loff_t pos = fd_offset;
/* Fuck me plenty... */
- error = do_brk(N_TXTADDR(ex), ex.a_text);
+ error = do_brk_locked(N_TXTADDR(ex), ex.a_text);
bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
ex.a_text, &pos);
- error = do_brk(N_DATADDR(ex), ex.a_data);
+ error = do_brk_locked(N_DATADDR(ex), ex.a_data);
bprm->file->f_op->read(bprm->file, (char *) N_DATADDR(ex),
ex.a_data, &pos);
goto beyond_if;
@@ -257,7 +257,7 @@

if (N_MAGIC(ex) == OMAGIC) {
loff_t pos = fd_offset;
- do_brk(N_TXTADDR(ex) & PAGE_MASK,
+ do_brk_locked(N_TXTADDR(ex) & PAGE_MASK,
ex.a_text+ex.a_data + PAGE_SIZE - 1);
bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
ex.a_text+ex.a_data, &pos);
@@ -272,7 +272,7 @@

if (!bprm->file->f_op->mmap) {
loff_t pos = fd_offset;
- do_brk(0, ex.a_text+ex.a_data);
+ do_brk_locked(0, ex.a_text+ex.a_data);
bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
ex.a_text+ex.a_data, &pos);
goto beyond_if;
@@ -388,7 +388,7 @@
len = PAGE_ALIGN(ex.a_text + ex.a_data);
bss = ex.a_text + ex.a_data + ex.a_bss;
if (bss > len) {
- error = do_brk(start_addr + len, bss - len);
+ error = do_brk_locked(start_addr + len, bss - len);
retval = error;
if (error != start_addr + len)
goto out;
diff -Nru a/fs/binfmt_aout.c b/fs/binfmt_aout.c
--- a/fs/binfmt_aout.c Fri Jan 7 18:04:11 2005
+++ b/fs/binfmt_aout.c Fri Jan 7 18:04:11 2005
@@ -46,7 +46,7 @@
start = PAGE_ALIGN(start);
end = PAGE_ALIGN(end);
if (end > start) {
- unsigned long addr = do_brk(start, end - start);
+ unsigned long addr = do_brk_locked(start, end - start);
if (BAD_ADDR(addr))
return addr;
}
@@ -317,10 +317,10 @@
loff_t pos = fd_offset;
/* Fuck me plenty... */
/* <AOL></AOL> */
- error = do_brk(N_TXTADDR(ex), ex.a_text);
+ error = do_brk_locked(N_TXTADDR(ex), ex.a_text);
bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
ex.a_text, &pos);
- error = do_brk(N_DATADDR(ex), ex.a_data);
+ error = do_brk_locked(N_DATADDR(ex), ex.a_data);
bprm->file->f_op->read(bprm->file, (char *) N_DATADDR(ex),
ex.a_data, &pos);
goto beyond_if;
@@ -341,7 +341,7 @@
map_size = ex.a_text+ex.a_data;
#endif

- error = do_brk(text_addr & PAGE_MASK, map_size);
+ error = do_brk_locked(text_addr & PAGE_MASK, map_size);
if (error != (text_addr & PAGE_MASK)) {
send_sig(SIGKILL, current, 0);
return error;
@@ -375,7 +375,7 @@

if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
loff_t pos = fd_offset;
- do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
+ do_brk_locked(N_TXTADDR(ex), ex.a_text+ex.a_data);
bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
ex.a_text+ex.a_data, &pos);
flush_icache_range((unsigned long) N_TXTADDR(ex),
@@ -476,7 +476,7 @@
error_time = jiffies;
}

- do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
+ do_brk_locked(start_addr, ex.a_text + ex.a_data + ex.a_bss);

file->f_op->read(file, (char *)start_addr,
ex.a_text + ex.a_data, &pos);
@@ -500,7 +500,7 @@
len = PAGE_ALIGN(ex.a_text + ex.a_data);
bss = ex.a_text + ex.a_data + ex.a_bss;
if (bss > len) {
- error = do_brk(start_addr + len, bss - len);
+ error = do_brk_locked(start_addr + len, bss - len);
retval = error;
if (error != start_addr + len)
goto out;
diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c
--- a/fs/binfmt_elf.c Fri Jan 7 18:04:11 2005
+++ b/fs/binfmt_elf.c Fri Jan 7 18:04:11 2005
@@ -84,7 +84,7 @@
start = ELF_PAGEALIGN(start);
end = ELF_PAGEALIGN(end);
if (end > start) {
- unsigned long addr = do_brk(start, end - start);
+ unsigned long addr = do_brk_locked(start, end - start);
if (BAD_ADDR(addr))
return addr;
}
@@ -379,7 +379,7 @@

/* Map the last of the bss segment */
if (last_bss > elf_bss) {
- error = do_brk(elf_bss, last_bss - elf_bss);
+ error = do_brk_locked(elf_bss, last_bss - elf_bss);
if (BAD_ADDR(error))
goto out_close;
}
@@ -425,7 +425,7 @@
goto out;
}

- do_brk(0, text_data);
+ do_brk_locked(0, text_data);
if (!interpreter->f_op || !interpreter->f_op->read)
goto out;
if (interpreter->f_op->read(interpreter, addr, text_data, &offset) < 0)
@@ -433,7 +433,7 @@
flush_icache_range((unsigned long)addr,
(unsigned long)addr + text_data);

- do_brk(ELF_PAGESTART(text_data + ELF_MIN_ALIGN - 1),
+ do_brk_locked(ELF_PAGESTART(text_data + ELF_MIN_ALIGN - 1),
interp_ex->a_bss);
elf_entry = interp_ex->a_entry;

@@ -974,7 +974,7 @@
len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr + ELF_MIN_ALIGN - 1);
bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
if (bss > len)
- do_brk(len, bss - len);
+ do_brk_locked(len, bss - len);
error = 0;

out_free_ph:
diff -Nru a/include/linux/mm.h b/include/linux/mm.h
--- a/include/linux/mm.h Fri Jan 7 18:04:11 2005
+++ b/include/linux/mm.h Fri Jan 7 18:04:11 2005
@@ -575,6 +575,7 @@
extern int do_munmap(struct mm_struct *, unsigned long, size_t);

extern unsigned long do_brk(unsigned long, unsigned long);
+extern unsigned long do_brk_locked(unsigned long, unsigned long);

static inline void __vma_unlink(struct mm_struct * mm, struct vm_area_struct * vma, struct vm_area_struct * prev)
{
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
--- a/kernel/ksyms.c Fri Jan 7 18:04:11 2005
+++ b/kernel/ksyms.c Fri Jan 7 18:04:11 2005
@@ -88,6 +88,7 @@
EXPORT_SYMBOL(do_mmap_pgoff);
EXPORT_SYMBOL(do_munmap);
EXPORT_SYMBOL(do_brk);
+EXPORT_SYMBOL(do_brk_locked);
EXPORT_SYMBOL(exit_mm);
EXPORT_SYMBOL(exit_files);
EXPORT_SYMBOL(exit_fs);
diff -Nru a/mm/mmap.c b/mm/mmap.c
--- a/mm/mmap.c Fri Jan 7 18:04:11 2005
+++ b/mm/mmap.c Fri Jan 7 18:04:11 2005
@@ -1116,6 +1116,21 @@
return addr;
}

+/* locking version of do_brk. */
+unsigned long do_brk_locked(unsigned long addr, unsigned long len)
+{
+ unsigned long ret;
+
+ down_write(&current->mm->mmap_sem);
+ ret = do_brk(addr, len);
+ up_write(&current->mm->mmap_sem);
+
+ return ret;
+}
+
+
+
+
/* Build the RB tree corresponding to the VMA list. */
void build_mmap_rb(struct mm_struct * mm)
{