ELF loader naivity fix

Pavel Kankovsky (peak@kerberos.troja.mff.cuni.cz)
Tue, 7 Jul 1998 22:08:57 +0200 (MET DST)


[ This is my 2nd attempt to send this message. It was probably lost when
I sent it for the first time (on May 6). ]

It seems the routines interpreting ELF headers trust them more than
necessary. To be specific:

1) do_load_elf_binary() can be confused by odd values e_phentsize

impact: the kernel may be coaxed to access the memory outside the
area it has kmalloc()'ed for the phdr table

fix: the kernel refuses to load the binary if e_phentsize !=
sizeof(elf_phdr) (check reused from do_load_elf_interpret())

I have also added this check to do_load_elf_library() to make
things consistent (even it does not use the value)

2) do_load_elf_binary() can be forced to temporarily kmalloc() arbitrary
(subject to the limits imposed by kmalloc() implementation) amount of
non-swappable memory when it reads the phdr table or the interpreter
filename

impact: potential denial of service, not serious (in most cases) but
I am a purist :)

[ Actually, this is quite serious because it is possible to make the
loader block forever when it opens the interpreter (e.g. if the
filename points at a fifo). One needs only several processes of this
sort to hoard all kernel memory. ]

fix: the kernel refuses to load the binary if the size of phdr table
is biger than ELF_EXEC_PAGESIZE (check reused from
do_load_elf_interpret())

the kernel refuses to load the binary (with ENOMEM, is this
right?) if the interpret filename is longer than PAGE_SIZE
(open() would fail anyway)

Affected versions: <=2.0.34pre10, <=2.1.99

[ 2.0.34 and 2.1.108 seem to be affected as well. ]

(Replies by e-mail, please. I am not subscribed to this list.)

--Pavel Kankovsky aka Peak [ Boycott Microsoft--http://www.vcnet.com/bms ]

Here is the patch (against 2.1.98):

--- binfmt_elf.c-2.1.98.orig Mon May 4 14:56:59 1998
+++ binfmt_elf.c-2.1.98 Wed May 6 10:38:27 1998
@@ -440,10 +440,20 @@
!bprm->dentry->d_inode->i_op->default_file_ops->mmap)
goto out;

+ /*
+ * If the size of this structure has changed, then punt, since
+ * we will be doing the wrong thing.
+ */
+ if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr))
+ goto out;
+
/* Now read in all of the header information */

+ size = sizeof(struct elf_phdr) * interp_elf_ex->e_phnum;
+ if (size > ELF_EXEC_PAGESIZE)
+ goto out;
+
retval = -ENOMEM;
- size = elf_ex.e_phentsize * elf_ex.e_phnum;
elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);
if (!elf_phdata)
goto out;
@@ -478,6 +488,10 @@
* is an a.out format binary
*/

+ retval = -ENAMETOOLONG;
+ if (elf_ppnt->p_filesz > PAGE_SIZE)
+ goto out_free_file;
+
retval = -ENOMEM;
elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
GFP_KERNEL);
@@ -836,6 +850,13 @@
!elf_check_arch(elf_ex.e_machine) ||
(!inode->i_op || !inode->i_op->default_file_ops->mmap))
goto out_putf;
+
+ /*
+ * If the size of this structure has changed, then punt, since
+ * we will be doing the wrong thing.
+ */
+ if (elf_ex.e_phentsize != sizeof(struct elf_phdr))
+ goto out;

/* Now read in all of the header information */

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu