amended "secure fd 0,1,2" patch

Pavel Kankovsky (peak@kerberos.troja.mff.cuni.cz)
Tue, 7 Jul 1998 19:56:15 +0200 (MET DST)


Being highly motivated by Alan Cox's words ("Ok. Im convinced.") I have
found some free time and made a new version of the patch. This one should
handle close-on-exec properly, and should free all fd's it has allocated
when execve() fails.

BTW: Alan, will 2.0.35+ fix this problem?

struct inode * ext2_new_inode (..., int * err)
{
... declarations ...

if (!dir || !(inode = get_empty_inode ()))
return NULL; /* *err uninitialized here */
...
}

--Pavel Kankovsky aka Peak [ Boycott Microsoft--http://www.vcnet.com/bms ]
"You can't be truly paranoid unless you're sure they have already got you."

*** Here is the amended patch ***

--- ./fs/exec.c.fds Mon Apr 20 22:02:45 1998
+++ ./fs/exec.c Tue Jul 7 17:11:14 1998
@@ -47,6 +47,9 @@
#ifdef CONFIG_KERNELD
#include <linux/kerneld.h>
#endif
+#ifdef CONFIG_SECURE_FD_0_1_2
+#include <linux/major.h>
+#endif

asmlinkage int sys_exit(int exit_code);
asmlinkage int sys_brk(unsigned long);
@@ -424,6 +427,77 @@
return 0;
}

+#ifdef CONFIG_SECURE_FD_0_1_2
+
+/* make sure fd's 0, 1, and 2 are open to prevent nasty
+ * security problems -- 98/07/01 peak */
+
+static inline int tweak_fd_open_null(struct linux_binprm * bprm)
+{
+ struct file * f = NULL;
+ struct inode * i = NULL;
+
+ i = get_empty_inode();
+ if (!i)
+ return -ENOMEM; /* see 2.1.108 ext2_new_inode() */
+ f = get_empty_filp();
+ if (!f)
+ goto bailout;
+ i->i_rdev = MKDEV(MEM_MAJOR, 3); /* /dev/null */
+ i->i_op = &chrdev_inode_operations;
+ f->f_flags = O_RDWR;
+ f->f_mode = FMODE_READ | FMODE_WRITE;
+ f->f_inode = i;
+ f->f_pos = 0;
+ f->f_reada = 0;
+ f->f_op = i->i_op->default_file_ops;
+ f->f_op->open(i, f); /* chrdev_open */
+
+ bprm->tweak_fd_null = f;
+
+ return 0;
+
+bailout:
+ --i->i_count;
+ iput(i);
+ return -ENFILE;
+}
+
+static int tweak_fd_0_1_2(struct linux_binprm * bprm, struct files_struct * files)
+{
+ int fd, check_me, retval;
+
+ for (fd = 0; fd <= 2; ++fd) {
+ if (files->fd[fd])
+ continue;
+ check_me = get_unused_fd();
+ if (check_me != fd) {
+ retval = -EMFILE;
+ goto bailout;
+ }
+ if (!bprm->tweak_fd_null) {
+ /* fake open("/dev/null", O_RDWR) */
+ retval = tweak_fd_open_null(bprm);
+ if (retval)
+ goto bailout;
+ } else {
+ /* fake dup2() */
+ ++bprm->tweak_fd_null->f_count;
+ }
+ files->fd[fd] = bprm->tweak_fd_null;
+ bprm->tweak_fd_mask |= (1 << fd);
+ }
+
+ return 0;
+
+bailout:
+ if (check_me >= 0)
+ put_unused_fd(check_me);
+ return retval;
+}
+
+#endif /* CONFIG_SECURE_FD_0_1_2 */
+
/*
* These functions flushes out all traces of the currently running executable
* so that a new one can be started
@@ -497,6 +571,12 @@
flush_old_signals(current->sig);
flush_old_files(current->files);

+#ifdef CONFIG_SECURE_FD_0_1_2
+ /* take care of close-on-exec files */
+ if (bprm->e_uid != current->euid || bprm->e_gid != current->egid)
+ return tweak_fd_0_1_2(bprm, current->files);
+#endif
+
return 0;
}

@@ -559,6 +639,12 @@
if (!suser())
return -EPERM;
}
+#ifdef CONFIG_SECURE_FD_0_1_2
+ /* warning: must be done BEFORE binfmt calls open_inode() */
+ retval = tweak_fd_0_1_2(bprm, current->files);
+ if (retval)
+ return retval;
+#endif
}

memset(bprm->buf,0,sizeof(bprm->buf));
@@ -677,6 +763,10 @@
return bprm.argc;
if ((bprm.envc = count(envp)) < 0)
return bprm.envc;
+#ifdef CONFIG_SECURE_FD_0_1_2
+ bprm.tweak_fd_mask = 0;
+ bprm.tweak_fd_null = NULL;
+#endif

retval = prepare_binprm(&bprm);

@@ -700,5 +790,11 @@
iput(bprm.inode);
for (i=0 ; i<MAX_ARG_PAGES ; i++)
free_page(bprm.page[i]);
+#ifdef CONFIG_SECURE_FD_0_1_2
+ /* recover from fd tweaking */
+ for (i = 0; i <= 2; ++i)
+ if (bprm.tweak_fd_mask << i)
+ (void) sys_close(i);
+#endif
return(retval);
}
--- ./include/linux/binfmts.h.fds Wed Oct 15 23:56:43 1997
+++ ./include/linux/binfmts.h Tue Jul 7 17:07:36 1998
@@ -24,6 +24,8 @@
char * filename; /* Name of binary */
unsigned long loader, exec;
int dont_iput; /* binfmt handler has put inode */
+ int tweak_fd_mask;
+ struct file * tweak_fd_null; /* /dev/null */
};

/*
--- ./security/Common.in.fds Mon Apr 20 22:02:57 1998
+++ ./security/Common.in Wed Jul 1 14:52:59 1998
@@ -9,3 +9,4 @@
bool 'Restricted /proc' CONFIG_SECURE_PROC
bool 'Improved securelevel support' CONFIG_SECURE_LEVEL
bool 'Unofficial bugfixes' CONFIG_SECURE_BUGFIX
+bool 'Special handling of fd 0, 1 & 2' CONFIG_SECURE_FD_0_1_2

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