[prev in list] [next in list] [prev in thread] [next in thread] 

List:       linux-kernel
Subject:    [RFC][PATCH] scripts with stdin replaced
From:       Richard Guenther <zxmpm11 () student ! uni-tuebingen ! de>
Date:       1999-07-03 11:39:09
[Download RAW message or body]

Hi!

The following patch extends binfmt_misc to substitute stdin
of the wrapper with the to be executed binary. This could
be used f.e. to implement suid-perl scripts without having
suidperl:
echo ':suidperl:MIS::#suidperl::/usr/bin/perl:' >
/proc/sys/fs/binfmt_misc/register
prepend the to be executed script with '#suidperl' and make
it 6755.

Replacing stdin deals with the race conditions that prevent
scripts from being suid in the first place. Of course it
prevents the script from reading stdin, too.

Richard.

PS: this is just a quick patch to show that it is easy to
    implement and to get comments about the semantics.
    the patch has to be verified to be correct regarding to
    permissions/file handling

--
Richard Guenther <richard.guenther@student.uni-tuebingen.de>
PGP: 2E829319 - 2F 83 FC 93 E9 E4 19 E2 93 7A 32 42 45 37 23 57
WWW: http://www.anatom.uni-tuebingen.de/~richi/


--- linux-2.2.0/fs/binfmt_misc.c.original	Fri Jul  2 17:40:37 1999
+++ linux-2.2.0/fs/binfmt_misc.c	Fri Jul  2 18:59:32 1999
@@ -18,9 +18,14 @@
 #include <linux/config.h>
 #include <linux/module.h>
 
+#include <asm/current.h>
+#include <linux/sched.h>
 #include <linux/kernel.h>
+#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/mm.h>
 #include <linux/malloc.h>
 #include <linux/binfmts.h>
 #include <linux/init.h>
@@ -57,6 +62,8 @@
 };
 
 #define ENTRY_ENABLED 1		/* the old binfmt_entry.enabled */
+#define ENTRY_SUBST_CAP 6       /* substitute uid/gid/cap from binary */
+#define ENTRY_SUBST_STDIN 7	/* replace stdin of interpreter with binary */
 #define	ENTRY_MAGIC 8		/* not filename detection */
 
 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs);
@@ -187,8 +194,10 @@
 	struct dentry * dentry;
 	char iname[128];
 	char *iname_addr = iname;
-	int retval;
-
+	int retval, flags;
+	int newstdin, e_uid, e_gid;
+	kernel_cap_t cap_inheritable, cap_permitted, cap_effective;
+	
 	MOD_INC_USE_COUNT;
 	retval = -ENOEXEC;
 	if (!enabled)
@@ -200,18 +209,36 @@
 	if (fmt) {
 		strncpy(iname, fmt->interpreter, 127);
 		iname[127] = '\0';
+		flags = fmt->flags;
 	}
 	read_unlock(&entries_lock);
 	if (!fmt)
 		goto _ret;
 
+	/* replace stdin of interpreter with file to be executed */
+	if (flags & ENTRY_SUBST_STDIN) {
+		if (fcheck(0)) {
+			printk(KERN_DEBUG "closing old stdin\n");
+			sys_close(0);
+		}
+		newstdin = open_dentry(bprm->dentry, O_RDONLY);
+		printk(KERN_DEBUG "file got id %i\n", newstdin);
+		e_uid = bprm->e_uid;
+		e_gid = bprm->e_gid;
+		cap_inheritable = bprm->cap_inheritable;
+	 	cap_permitted = bprm->cap_permitted;
+		cap_effective = bprm->cap_effective;
+	}
+
 	dput(bprm->dentry);
 	bprm->dentry = NULL;
 
 	/* Build args for interpreter */
 	remove_arg_zero(bprm);
-	bprm->p = copy_strings(1, &bprm->filename, bprm->page, bprm->p, 2);
-	bprm->argc++;
+	if (!(flags & ENTRY_SUBST_STDIN)) {
+		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++;
 	retval = -E2BIG;
@@ -226,8 +253,18 @@
 	bprm->dentry = dentry;
 
 	retval = prepare_binprm(bprm);
-	if (retval >= 0)
+	if (retval >= 0) {
+		/* allow set-uid binaries for stdin input */
+		if (flags & ENTRY_SUBST_STDIN
+		    && flags & ENTRY_SUBST_CAP) {
+			bprm->e_uid = e_uid;
+			bprm->e_gid = e_gid;
+			bprm->cap_inheritable = cap_inheritable;
+			bprm->cap_permitted = cap_permitted;
+			bprm->cap_effective = cap_effective;
+		}
 		retval = search_binary_handler(bprm, regs);
+	}
 _ret:
 	MOD_DEC_USE_COUNT;
 	return retval;
@@ -277,7 +314,7 @@
 
 /*
  * This registers a new binary format, it recognises the syntax
- * ':name:type:offset:magic:mask:interpreter:'
+ * ':name:flags:offset:magic:mask:interpreter:'
  * where the ':' is the IFS, that can be chosen with the first char
  */
 static int proc_write_register(struct file *file, const char *buffer,
@@ -307,11 +344,28 @@
 
 	/* we can use bit 3 of type for ext/magic
 	   flag due to the nice encoding of E and M */
-	if ((*sp & ~('E' | 'M')) || (sp[1] != del))
-		err = -EINVAL;
-	else
-		e->flags = (*sp++ & (ENTRY_MAGIC | ENTRY_ENABLED));
-	cnt -= 2; sp++;
+	e->flags = ENTRY_ENABLED;
+	while (*sp != del && err == 0) {
+		switch (*sp) {
+			case 'E':
+				e->flags &= ~ENTRY_MAGIC;
+				break;
+			case 'M':
+				e->flags |= ENTRY_MAGIC;
+				break;
+			case 'I':
+				e->flags |= ENTRY_SUBST_STDIN;
+				break;
+			case 'S':
+				e->flags |= ENTRY_SUBST_CAP;
+				break;
+			default:
+				err = -EINVAL;
+				break;
+		}
+		sp++; cnt--;
+	}
+	sp++; cnt--;
 
 	e->offset = 0;
 	while (cnt-- && isdigit(*sp))


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic