security-/misfeature-fix for binfmt_misc [PATCH]

Richard Guenther (richard.guenther@student.uni-tuebingen.de)
Tue, 1 Jul 1997 11:27:34 +0200 (MESZ)


Hi!

The patch below fixes binfmt_misc to use bprm->filename rather than
argv[0] (thanx to hpa). It does minor cleanup as well.

Richard.

diff -u --recursive --new-file linux-2.1.43/Documentation/binfmt_misc.txt linux-2.1.43x/Documentation/binfmt_misc.txt
--- linux-2.1.43/Documentation/binfmt_misc.txt Sun Jun 22 12:54:59 1997
+++ linux-2.1.43x/Documentation/binfmt_misc.txt Mon Jun 30 23:22:18 1997
@@ -1,5 +1,5 @@
Kernel Support for miscellaneous (your favourite) Binary Formats v1.1
- ====================================================================
+ =====================================================================

This Kernel feature allows to invoke almost (for restrictions see below) every
program by simply typing it's name in the shell.
@@ -47,15 +47,18 @@
- enable Java(TM)-support (like binfmt_java):
echo ":Java:M::\xca\xfe\xba\xbe::/usr/local/bin/java:" > register
echo :Applet:M::\<\!--applet::/usr/local/bin/appletviewer: > register
+
- enable support for em86 (like binfmt_em86, for Alpha AXP only):
echo ":i386:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:" > register
echo ":i486:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:" > register
+
- enable support for packed DOS applications (pre-configured dosemu hdimages):
echo ":DEXE:M::\x0eDEX::/usr/bin/dosexec:" > register
+
- enable support for DOS/Windows executables (using mzloader and dosemu/wine):
echo ":DOSWin:M::MZ::/usr/sbin/mzloader:" > register
echo ":DOS:E::com::/usr/sbin/mzloader:" > register
-
+ echo ":DOS2:E::exe::/usr/sbin/mzloader:" > register

You can enable/disable binfmt_misc or one binary type by echoing 0 (to disable)
or 1 (to enable) to /proc/sys/fs/binfmt_misc/status or /proc/.../the_name.
@@ -68,13 +71,12 @@
HINTS:
======

-If your interpreter does not look at the PATH to determine the full name of the
-program, you need to invoke a wrapper-script (like the following for java) first:
+If you want to pass special arguments to your interpreter, you can
+write a wrapper script for it.

-#!/bin/sh
-FOO=`which $1` || exit 1
-shift
-/usr/local/bin/java $FOO ${1+$@}
+Your interpreter should NOT look in the PATH for the filename; the
+kernel passes it the full filename to use. Using the PATH can cause
+unexpected behaviour and be a security hazard.


There is a web page about binfmt_misc at
diff -u --recursive --new-file linux-2.1.43/fs/binfmt_misc.c linux-2.1.43x/fs/binfmt_misc.c
--- linux-2.1.43/fs/binfmt_misc.c Sun Jun 22 12:55:07 1997
+++ linux-2.1.43x/fs/binfmt_misc.c Mon Jun 30 23:15:43 1997
@@ -7,9 +7,11 @@
* a specified wrapper. This should obsolete binfmt_java, binfmt_em86 and
* binfmt_mz.
*
- * 25.4.97 first version
- * [...]
- * 19.5.97 cleanup
+ * 1997-04-25 first version
+ * [...]
+ * 1997-05-19 cleanup
+ * 1997-06-26 hpa: pass the real filename rather than argv[0]
+ * 1997-06-30 minor cleanup
*/

#include <linux/module.h>
@@ -85,7 +87,6 @@
*ep = e->next;
entry_proc_cleanup(e);
kfree(e);
- MOD_DEC_USE_COUNT;
}
write_unlock(&entries_lock);
}
@@ -102,7 +103,6 @@
entries = entries->next;
entry_proc_cleanup(e);
kfree(e);
- MOD_DEC_USE_COUNT;
}
write_unlock(&entries_lock);
}
@@ -161,7 +161,6 @@
char *iname_addr = iname, *p;
int retval, fmt_flags = 0;

- MOD_INC_USE_COUNT;
if (!enabled) {
retval = -ENOEXEC;
goto _ret;
@@ -185,12 +184,11 @@

/* Build args for interpreter */
if ((fmt_flags & ENTRY_STRIP_EXT) &&
- (p = strrchr(bprm->filename, '.'))) {
+ (p = strrchr(bprm->filename, '.')))
*p = '\0';
- remove_arg_zero(bprm);
- bprm->p = copy_strings(1, &bprm->filename, bprm->page, bprm->p, 2);
- bprm->argc++;
- }
+ remove_arg_zero(bprm);
+ bprm->p = copy_strings(1, &bprm->filename, bprm->page, bprm->p, 2);
+ bprm->argc++;
bprm->p = copy_strings(1, &iname_addr, bprm->page, bprm->p, 2);
bprm->argc++;
if (!bprm->p) {
@@ -206,7 +204,6 @@
if ((retval = prepare_binprm(bprm)) >= 0)
retval = search_binary_handler(bprm, regs);
_ret:
- MOD_DEC_USE_COUNT;
return retval;
}

@@ -265,18 +262,13 @@
struct binfmt_entry *e;
int memsize, cnt = count - 1, err = 0;

- MOD_INC_USE_COUNT;
/* some sanity checks */
- if ((count < 11) || (count > 256)) {
- err = -EINVAL;
- goto _err;
- }
+ if ((count < 11) || (count > 256))
+ return -EINVAL;

memsize = sizeof(struct binfmt_entry) + count;
- if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER))) {
- err = -ENOMEM;
- goto _err;
- }
+ if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER)))
+ return -ENOMEM;

sp = buffer + 1;
del = buffer[0];
@@ -313,8 +305,7 @@
!(e->proc_name) || !(e->interpreter) ||
entry_proc_setup(e)) {
kfree(e);
- err = -EINVAL;
- goto _err;
+ return -EINVAL;
}

write_lock(&entries_lock);
@@ -323,9 +314,6 @@
write_unlock(&entries_lock);

return count;
-_err:
- MOD_DEC_USE_COUNT;
- return err;
}

/*
@@ -340,7 +328,6 @@
char *dp;
int elen, i;

- MOD_INC_USE_COUNT;
#ifndef VERBOSE_STATUS
if (data) {
read_lock(&entries_lock);
@@ -400,7 +387,6 @@
*eof = (elen <= count) ? 1 : 0;
*start = page + off;

- MOD_DEC_USE_COUNT;
return elen;
}

@@ -414,7 +400,6 @@
struct binfmt_entry *e;
int res = count;

- MOD_INC_USE_COUNT;
if (((buffer[0] == '1') || (buffer[0] == '0')) &&
((count == 1) || ((count == 2) && (buffer[1] == '\n')))) {
if (data) {
@@ -434,7 +419,6 @@
} else {
res = -EINVAL;
}
- MOD_DEC_USE_COUNT;
return res;
}

@@ -499,6 +483,7 @@
unregister_binfmt(&misc_format);
remove_proc_entry("register", bm_dir);
remove_proc_entry("status", bm_dir);
+ clear_entries();
remove_proc_entry("sys/fs/binfmt_misc", NULL);
}
#endif