feature request & patch submit: chroot(2) in sshd

Birger Toedtmann birger at takatukaland.de
Mon Oct 30 21:30:28 EST 2000


On Sun, Oct 29, 2000 at 04:07:35PM -0500, Hank Leininger wrote:
> On 2000-10-29, Birger Toedtmann <birger at takatukaland.de> wrote:
> 
> > On Sun, Oct 29, 2000 at 01:52:58AM -0500, Hank Leininger wrote:
> 
> > > Aren't you missing a 'chdir("/")' in there?  Else you leak '.'
> > > outside the chroot jail.  (Unless a chdir is guaranteed to be done
> > > between here, and when user processes get control?)
> 
> > Well, right beneath this code session.c switches uid/gid and then sets
> > the environment. $HOME is set to pw->pw_dir (already set to "/") and
> > $HOME/.ssh/environment gets its share. After this, the chdir() is
> > made....
> 
> Ah.  OK, so there is a chdir() guaranteed.  Although you raise a good
> point:
> 
> > ...hmmm - do you think one might be able to fool .ssh/environment into
> > leaking information about "."?
> 
> I'm really not sure.  But for warm-and-fuzzy, obviously-correct behavior,
> I'd vote for an explicit chdir(pw->pw_dir) right after pw->pw_dir = "/" as
> you suggest.  Consider the alternative -- we might audit the behavior of
> ..ssh/environment usage now and deem it safe, only to have others decide
> later, for whatever seems like good reasons at the time, to break our
> assumptions wrt its safety in the face of things getting reordered, odd
> custom shells, forced commands from authorized_keys, scp's, and whatnot. 
> Better IMHO to have the fact that it is Done Right localized and hard to
> break accidentally by other subtle means.
[...]

Alright, this seems reasonable. So I tested around a bit with some weird
outcome. The new patch includes a chdir() right after chroot(). I set the
home of my prisoner to 644 just to have a closer look. Whoops - first chdir()
succeeded, the second did not! I think with uid=0 chdir()ing to a 644 sounds
quite ok, whereas uid!=0 makes some difference. Maschine is a linux box.

BTW: I (stupendously) oversaw the chroot.diff within contrib/ which does 
something similar upon a "/./"-criterion regarding the homedir section of 
user credentials. Now I'm not quite sure about the usefulness of either 
patch but we use the UseChroot/ChrootGroup one quite sucessfully on a web 
application server maintained via ssh by its customers.

Regards,

-- 
  Birger Tödtmann, Bielefeld, Germany.
  00 83 E2 57 EC 60 0B 1C  D3 18 AE 2A 40 55 81 22
-------------- next part --------------
Common subdirectories: openssh-2.2.0p1/contrib and openssh-2.2.0p1chroot/contrib
diff -u openssh-2.2.0p1/servconf.c openssh-2.2.0p1chroot/servconf.c
--- openssh-2.2.0p1/servconf.c	Fri Aug 18 05:59:06 2000
+++ openssh-2.2.0p1chroot/servconf.c	Mon Oct 30 12:03:49 2000
@@ -68,6 +68,8 @@
 #endif
 	options->permit_empty_passwd = -1;
 	options->use_login = -1;
+	options->use_chroot = -1;
+	options->chroot_group = -1;
 	options->num_allow_users = 0;
 	options->num_deny_users = 0;
 	options->num_allow_groups = 0;
@@ -158,6 +160,10 @@
 		options->permit_empty_passwd = 0;
 	if (options->use_login == -1)
 		options->use_login = 0;
+	if (options->use_chroot == -1)
+		options->use_chroot = 0;
+	if (options->chroot_group == -1)
+		options->chroot_group = 0;
 	if (options->protocol == SSH_PROTO_UNKNOWN)
 		options->protocol = SSH_PROTO_1|SSH_PROTO_2;
 	if (options->gateway_ports == -1)
@@ -189,6 +195,7 @@
 	sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset,
 	sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
 	sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
+	sUseChroot, sChrootGroup,
 	sIgnoreUserKnownHosts, sHostDSAKeyFile, sCiphers, sProtocol, sPidFile,
 	sGatewayPorts, sDSAAuthentication, sXAuthLocation, sSubsystem, sMaxStartups
 } ServerOpCodes;
@@ -236,6 +243,8 @@
 	{ "strictmodes", sStrictModes },
 	{ "permitemptypasswords", sEmptyPasswd },
 	{ "uselogin", sUseLogin },
+	{ "usechroot", sUseChroot },
+	{ "chrootgroup", sChrootGroup },
 	{ "randomseed", sRandomSeedFile },
 	{ "keepalive", sKeepAlives },
 	{ "allowusers", sAllowUsers },
@@ -540,6 +549,14 @@
 		case sUseLogin:
 			intptr = &options->use_login;
 			goto parse_flag;
+
+		case sUseChroot:
+			intptr = &options->use_chroot;
+			goto parse_flag;
+
+		case sChrootGroup:
+			intptr = &options->chroot_group;
+			goto parse_int;
 
 		case sGatewayPorts:
 			intptr = &options->gateway_ports;
diff -u openssh-2.2.0p1/servconf.h openssh-2.2.0p1chroot/servconf.h
--- openssh-2.2.0p1/servconf.h	Fri Aug 18 05:59:06 2000
+++ openssh-2.2.0p1chroot/servconf.h	Mon Oct 30 12:03:49 2000
@@ -87,6 +87,9 @@
 	int     permit_empty_passwd;	/* If false, do not permit empty
 					 * passwords. */
 	int     use_login;	/* If true, login(1) is used */
+	int     use_chroot;      /* If true, do a chroot to homedir */
+	int     chroot_group;      /* If nonzero, chroot only when equal 
+				      to gid */
 	unsigned int num_allow_users;
 	char   *allow_users[MAX_ALLOW_USERS];
 	unsigned int num_deny_users;
diff -u openssh-2.2.0p1/session.c openssh-2.2.0p1chroot/session.c
--- openssh-2.2.0p1/session.c	Wed Aug 30 00:21:22 2000
+++ openssh-2.2.0p1chroot/session.c	Mon Oct 30 12:06:58 2000
@@ -948,6 +948,26 @@
 	}
 #endif /* USE_PAM */
 
+	/* Do a chroot, if configured. */
+	if (options.use_chroot) {
+	  	if ((!options.chroot_group)
+	      			|| (options.chroot_group == pw->pw_gid)) {
+	    		debug("Doing chroot to %s.",pw->pw_dir);
+	    		if (chroot(pw->pw_dir) < 0) {
+	      			log("Requested chroot failed: [%d] %s\n",
+		  		errno,strerror(errno));
+	      			exit(1);
+	    		}
+			debug("Doing chdir to / within chroot dir %s.",pw->pw_dir);
+			pw->pw_dir = "/";
+			if (chdir(pw->pw_dir) < 0) {
+				log("Unable to chdir to home directory /: [%d] %s\n",
+				errno,strerror(errno));
+				exit(1);
+			};
+	  	}
+	}
+
 	/* Set login name, uid, gid, and groups. */
 	/* Login(1) does this as well, and it needs uid 0 for the "-h"
 	   switch, so we let login(1) to this for us. */
diff -u openssh-2.2.0p1/sshd.8 openssh-2.2.0p1chroot/sshd.8
--- openssh-2.2.0p1/sshd.8	Tue Aug 29 02:33:51 2000
+++ openssh-2.2.0p1chroot/sshd.8	Mon Oct 30 12:03:50 2000
@@ -290,6 +290,15 @@
 Only user names are valid; a numerical user ID isn't recognized.
 By default login is allowed regardless of the user name.
 .Pp
+.It Cm ChrootGroup
+Only useful when
+.Cm UseChroot
+is set to
+.Dq yes . 
+Specifies which group of users
+.Nm sshd
+should drop into a chrooted homedir (a.k.a. sandbox) upon login. 
+Only numerical gid's are allowed.
 .It Cm Ciphers
 Specifies the ciphers allowed for protocol version 2.
 Multiple ciphers must be comma-separated.
@@ -597,6 +606,12 @@
 The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2,
 LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7.
 The default is AUTH.
+.It Cm UseChroot
+Do a chroot(2) into the users homedirectory after successful login.
+If option
+.Cm ChrootGroup
+is not set, this applies for all users. The default is
+.Dq no .
 .It Cm UseLogin
 Specifies whether
 .Xr login 1


More information about the openssh-unix-dev mailing list