Subject: per-user /tmp
To: None <tech-security@netbsd.org>
From: Elad Efrat <elad@NetBSD.org>
List: tech-security
Date: 02/03/2007 19:23:26
This is a multi-part message in MIME format.
--------------000602050607070207080607
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

hi,

attached are some diffs & instructions on how we can add support for
per-user /tmp directories. the motivation is of course to avoid /tmp
races.

1. enable magic links:

	# sysctl -w vfs.generic.magiclinks=1

2. decide on a directory that should be the per-user /tmp base, and
   set the symlink:

	# rmdir /tmp
	# mkdir /rtmp
	# ln -s /rtmp/@uid /tmp

   note that /rtmp in this case should be the mount-point if /tmp is
   a tmpfs or something.

3. each user using /tmp should have a directory under /rtmp named after
   the uid, set 0700. for example:

	# mkdir /rtmp/1000 -m 0700
	# chown user:user /rtmp/1000

   the attached login.diff will help doing that automatically for users
   when they login. it will read a string variable 'per-user-tmp' from
   login.conf during login, creating the directory (if it's not already
   there).

   for example:

	# from login.conf:
	default:\
		:per-user-tmp=/rtmp:

   will set /rtmp as the per-user /tmp base.

4. if the above goes in, it will of course be disabled by default.

thoughts?

-e.

--------------000602050607070207080607
Content-Type: text/plain;
 name="login.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="login.diff"

Index: login.c
===================================================================
RCS file: /usr/cvs/src/usr.bin/login/login.c,v
retrieving revision 1.94
diff -u -p -r1.94 login.c
--- login.c	17 Jan 2007 00:21:43 -0000	1.94
+++ login.c	2 Feb 2007 06:22:14 -0000
@@ -188,6 +188,7 @@ main(int argc, char *argv[])
 #ifdef LOGIN_CAP
 	char *shell = NULL;
 	login_cap_t *lc = NULL;
+	char *per_user_tmp;
 #endif
 
 	tbuf[0] = '\0';
@@ -596,6 +597,22 @@ main(int argc, char *argv[])
 		environ = envinit;
 
 #ifdef LOGIN_CAP
+	/* Create per-user temporary directories if needed. */
+	per_user_tmp = login_getcapstr(lc, "per-user-tmp", NULL, NULL);
+	if (per_user_tmp != NULL) {
+		char *tmp_dir;
+
+		/* Ignore errors here. */
+		if (asprintf(&tmp_dir, "%s/%u", per_user_tmp,
+		    pwd->pw_uid) != -1) {
+			(void)mkdir(tmp_dir, S_IRWXU);
+			(void)chown(tmp_dir, pwd->pw_uid, pwd->pw_gid);
+			free(tmp_dir);
+		}
+	}
+#endif /* LOGIN_CAP */
+
+#ifdef LOGIN_CAP
 	if (nested == NULL && setusercontext(lc, pwd, pwd->pw_uid,
 	    LOGIN_SETLOGIN) != 0) {
 		syslog(LOG_ERR, "setusercontext failed");
Index: login_pam.c
===================================================================
RCS file: /usr/cvs/src/usr.bin/login/login_pam.c,v
retrieving revision 1.17
diff -u -p -r1.17 login_pam.c
--- login_pam.c	17 Apr 2006 16:29:44 -0000	1.17
+++ login_pam.c	2 Feb 2007 06:20:21 -0000
@@ -144,6 +144,7 @@ main(int argc, char *argv[])
 	int status;
 	char *saved_term;
 	char **pamenv;
+	char *per_user_tmp;
 
 	tbuf[0] = '\0';
 	pwprompt = NULL;
@@ -643,6 +644,20 @@ skip_auth:
 		free(pamenv);
 	}
 
+	/* Create per-user temporary directories if needed. */
+	per_user_tmp = login_getcapstr(lc, "per-user-tmp", NULL, NULL);
+	if (per_user_tmp != NULL) {
+		char *tmp_dir;
+
+		/* Ignore errors here. */
+		if (asprintf(&tmp_dir, "%s/%u", per_user_tmp,
+		    pwd->pw_uid) != -1) {
+			(void)mkdir(tmp_dir, S_IRWXU);
+			(void)chown(tmp_dir, pwd->pw_uid, pwd->pw_gid);
+			free(tmp_dir);
+		}
+	}
+
 	/* This drops root privs */
 	if (setusercontext(lc, pwd, pwd->pw_uid,
 	    (LOGIN_SETALL & ~LOGIN_SETLOGIN)) != 0) {

--------------000602050607070207080607--