[policycoreutils/f15/master] Use rewritten seunshare from thoger

Daniel J Walsh dwalsh at fedoraproject.org
Tue Mar 8 21:51:40 UTC 2011


commit 93a6f1fc9da4d28d29fde02cb56bad7eac32899b
Author: Dan Walsh <dwalsh at redhat.com>
Date:   Tue Mar 8 16:51:35 2011 -0500

    Use rewritten seunshare from thoger

 policycoreutils-rhat.patch |  774 +++++++++++++++++++++++++++++---------------
 policycoreutils.spec       |    6 +-
 2 files changed, 516 insertions(+), 264 deletions(-)
---
diff --git a/policycoreutils-rhat.patch b/policycoreutils-rhat.patch
index a196b20..fa5d2a8 100644
--- a/policycoreutils-rhat.patch
+++ b/policycoreutils-rhat.patch
@@ -2147,7 +2147,7 @@ index 0000000..6063d6a
 +and
 +.I Thomas Liu <tliu at fedoraproject.org>
 diff --git a/policycoreutils/sandbox/seunshare.c b/policycoreutils/sandbox/seunshare.c
-index ec692e7..56eb165 100644
+index ec692e7..490c914 100644
 --- a/policycoreutils/sandbox/seunshare.c
 +++ b/policycoreutils/sandbox/seunshare.c
 @@ -1,28 +1,34 @@
@@ -2190,7 +2190,7 @@ index ec692e7..56eb165 100644
  #ifdef USE_NLS
  #include <locale.h>		/* for setlocale() */
  #include <libintl.h>		/* for gettext() */
-@@ -39,6 +45,13 @@
+@@ -39,29 +45,45 @@
  #define MS_PRIVATE 1<<18
  #endif
  
@@ -2199,91 +2199,222 @@ index ec692e7..56eb165 100644
 +#endif
 +
 +#define BUF_SIZE 1024
-+static char template[] = "/tmp/.sandboxXXXXXX";
++#define DEFAULT_PATH "/usr/bin:/bin"
++
++#define USAGE_STRING _("USAGE: seunshare [ -v ] [ -c ] -t tmpdir -h homedir [-Z context] -- executable [args]")
++
++static int verbose = 0;
++
 +
  /**
-  * This function will drop all capabilities 
-  * Returns zero on success, non-zero otherwise
-@@ -46,9 +59,9 @@
- static int drop_capabilities(uid_t uid)
+- * This function will drop all capabilities 
+- * Returns zero on success, non-zero otherwise
++ * This function will drop all capabilities.
+  */
+-static int drop_capabilities(uid_t uid)
++static int drop_caps()
  {
  	capng_clear(CAPNG_SELECT_BOTH);
 -
- 	if (capng_lock() < 0) 
+-	if (capng_lock() < 0) 
+-		return -1;
+-	/* Change uid */
+-	if (setresuid(uid, uid, uid)) {
+-		fprintf(stderr, _("Error changing uid, aborting.\n"));
++	if (capng_lock() == -1 || capng_apply(CAPNG_SELECT_BOTH) == -1) {
++		fprintf(stderr, _("Failed to drop all capabilities\n"));
+ 		return -1;
+ 	}
+-	return capng_apply(CAPNG_SELECT_BOTH);
++	return 0;
+ }
+ 
+-#define DEFAULT_PATH "/usr/bin:/bin"
+-static	int verbose = 0;
++/**
++ * This function will drop all privileges.
++ */
++static int drop_privs(uid_t uid)
++{
++	if (drop_caps() == -1 || setresuid(uid, uid, uid) == -1) {
++		fprintf(stderr, _("Failed to drop privileges\n"));
++		return -1;
++	}
++	return 0;
++}
+ 
+ /**
+- * Take care of any signal setup
++ * Take care of any signal setup.
+  */
+ static int set_signal_handles(void)
+ {
+@@ -75,8 +97,8 @@ static int set_signal_handles(void)
+ 
+ 	(void)sigprocmask(SIG_SETMASK, &empty, NULL);
+ 
+-	/* Terminate on SIGHUP. */
+-	if (signal(SIGHUP, SIG_DFL) == SIG_ERR) {
++	/* Terminate on SIGHUP */
++	if (signal(SIGHUP, SIG_IGN) == SIG_ERR) {
+ 		perror("Unable to set SIGHUP handler");
  		return -1;
+ 	}
+@@ -84,23 +106,100 @@ static int set_signal_handles(void)
+ 	return 0;
+ }
+ 
++#define status_to_retval(status,retval) do { \
++	if ((status) == -1) \
++		retval = -1; \
++	else if (WIFEXITED((status))) \
++		retval = WEXITSTATUS((status)); \
++	else if (WIFSIGNALED((status))) \
++		retval = 128 + WTERMSIG((status)); \
++	else \
++		retval = -1; \
++	} while(0)
++
++/**
++ * Spawn external command using system() with dropped privileges.
++ * TODO: avoid system() and use exec*() instead
++ */
++static int spawn_command(const char *cmd, uid_t uid){
++	int child;
++	int status = -1;
++
++	if (verbose > 1)
++		printf("spawn_command: %s\n", cmd);
++
++	child = fork();
++	if (child == -1) {
++		perror(_("Unable to fork"));
++		return status;
++	}
++
++	if (child == 0) {
++		if (drop_privs(uid) != 0) exit(-1);
++
++		status = system(cmd);
++		status_to_retval(status, status);
++		exit(status);
++	}
 +
- 	/* Change uid */
- 	if (setresuid(uid, uid, uid)) {
- 		fprintf(stderr, _("Error changing uid, aborting.\n"));
-@@ -90,18 +103,37 @@ static int set_signal_handles(void)
-  * If so, it returns 0. If it can not figure this out or they are different, it returns -1.
++	waitpid(child, &status, 0);
++	status_to_retval(status, status);
++	return status;
++}
++
+ /**
+- * This function makes sure the mounted directory is owned by the user executing
+- * seunshare.
+- * If so, it returns 0. If it can not figure this out or they are different, it returns -1.
++ * Check file/directory ownership, struct stat * must be passed to the
++ * functions.
   */
- static int verify_mount(const char *mntdir, struct passwd *pwd) {
-+	int rc = -1;
+-static int verify_mount(const char *mntdir, struct passwd *pwd) {
++#define check_owner_common(f,st) do { \
++	if (lstat(f, st) == -1) { \
++		fprintf(stderr, _("Failed to stat %s: %s\n"), f, strerror(errno)); \
++		return -1; \
++	} \
++	if (S_ISLNK(st->st_mode)) { \
++		fprintf(stderr, _("Error: %s must not be a symbolic link\n"), f); \
++		return -1; \
++	} \
++	} while(0)
++
++static int check_owner_uid(uid_t uid, const char *file, struct stat *st) {
++	check_owner_common(file, st);
++	return (st->st_uid == uid ? 0 : -1);
++}
++
++static int check_owner_gid(gid_t gid, const char *file, struct stat *st) {
++	check_owner_common(file, st);
++	return (st->st_gid == gid ? 0 : -1);
++}
++
++#define equal_stats(one,two) \
++	((one)->st_dev == (two)->st_dev && (one)->st_ino == (two)->st_ino && \
++	 (one)->st_uid == (two)->st_uid && (one)->st_gid == (two)->st_gid && \
++	 (one)->st_mode == (two)->st_mode)
++
++/**
++ * Sanity check specified directory.  Store stat info for future comparison, or
++ * compare with previously saved info to detect replaced directories.
++ * Note: This function does not perform owner checks.
++ */
++static int verify_directory(const char *dir, struct stat *st_in, struct stat *st_out) {
  	struct stat sb;
 -	if (stat(mntdir, &sb) == -1) {
 -		fprintf(stderr, _("Invalid mount point %s: %s\n"), mntdir, strerror(errno));
--		return -1;
-+	if ((strncmp(mntdir, "/tmp", 4) == 0 ) || (strncmp(mntdir, "/var/tmp", 8) == 0 )) {
-+		fprintf(stderr, _("Invalid mount point %s, you can not mount from the /tmp or /var/tmp directory\n"), mntdir);
-+		return rc;
-+	}
-+
-+	int fd = open(mntdir,  O_RDONLY);
-+	if (fd < 0) {
-+		fprintf(stderr, _("Invalid mount point: %s does not exist\n"), mntdir);
-+		return rc;
-+	}
 +
-+	if (fstat(fd, &sb) == -1) {
-+		fprintf(stderr, _("Invalid mount point: can not stat %s: %s\n"), mntdir, strerror(errno));
-+		goto err;
++	if (st_out == NULL) st_out = &sb;
++	
++	if (lstat(dir, st_out) == -1) {
++		fprintf(stderr, _("Failed to stat %s: %s\n"), dir, strerror(errno));
++		return -1;
 +	}
-+	if (! S_ISDIR(sb.st_mode)) {
-+		fprintf(stderr, _("Invalid mount point: %s is not a directory: %s\n"), mntdir, strerror(errno));
-+		goto err;
++	if (! S_ISDIR(st_out->st_mode)) {
++		fprintf(stderr, _("Error: %s is not a directory: %s\n"), dir, strerror(errno));
+ 		return -1;
  	}
- 	if (sb.st_uid != pwd->pw_uid) {
- 		errno = EPERM;
+-	if (sb.st_uid != pwd->pw_uid) {
+-		errno = EPERM;
 -		syslog(LOG_AUTHPRIV | LOG_ALERT, "%s attempted to mount an invalid directory, %s", pwd->pw_name, mntdir);
 -		perror(_("Invalid mount point, reporting to administrator"));
--		return -1;
-+		syslog(LOG_AUTHPRIV | LOG_ALERT, "%s attempted to mount an invalid directory not owned by user, %s", pwd->pw_name, mntdir);
-+		perror(_("Invalid mount point, not owned by user reporting to administrator"));
-+		goto err;
++	if (st_in && !equal_stats(st_in, st_out)) {
++		fprintf(stderr, _("Error: %s was replaced by a different directory\n"), dir);
+ 		return -1;
  	}
--	return 0;
-+	rc =  0;
-+err:
-+	close(fd);
-+	return rc;
++
+ 	return 0;
  }
  
- /**
-@@ -131,45 +163,356 @@ static int verify_shell(const char *shell_name)
+@@ -123,7 +222,7 @@ static int verify_shell(const char *shell_name)
+ 
+ 		/* check the shell skipping newline char */
+ 		if (!strcmp(shell_name, buf)) {
+-			rc = 1;
++			rc = 0;
+ 			break;
+ 		}
+ 	}
+@@ -131,45 +230,443 @@ static int verify_shell(const char *shell_name)
  	return rc;
  }
  
 -static int seunshare_mount(const char *src, const char *dst, struct passwd *pwd) {
-+static int seunshare_mount_home(const char *src,  struct passwd *pwd) {
++/**
++ * Mount directory and check that we mounted the right directory.
++ */
++static int seunshare_mount(const char *src, const char *dst, struct stat *src_st)
++{
++	int flags = MS_REC;
++	int is_tmp = 0;
 +
-+	const char *dst = pwd->pw_dir;
  	if (verbose)
- 		printf("Mount %s on %s\n", src, dst);
+-		printf("Mount %s on %s\n", src, dst);
 -	if (mount(dst, dst,  NULL, MS_BIND | MS_REC, NULL) < 0) {
++		printf(_("Mounting %s on %s\n"), src, dst);
 +
-+	int flags = MS_REC;
++	if (strcmp("/tmp", dst) == 0) {
++		flags = flags | MS_NODEV | MS_NOSUID | MS_NOEXEC;
++		is_tmp = 1;
++	}
++
++	/* mount directory */
 +	if (mount(dst, dst,  NULL, MS_BIND | flags, NULL) < 0) {
  		fprintf(stderr, _("Failed to mount %s on %s: %s\n"), dst, dst, strerror(errno));
  		return -1;
  	}
- 
+-
 -	if (mount(dst, dst, NULL, MS_PRIVATE | MS_REC, NULL) < 0) {
 +	if (mount(dst, dst, NULL, MS_PRIVATE | flags, NULL) < 0) {
  		fprintf(stderr, _("Failed to make %s private: %s\n"), dst, strerror(errno));
  		return -1;
  	}
- 
+-
 -	if (mount(src, dst, NULL, MS_BIND | MS_REC, NULL) < 0) {
 +	if (mount(src, dst, NULL, MS_BIND | flags, NULL) < 0) {
  		fprintf(stderr, _("Failed to mount %s on %s: %s\n"), src, dst, strerror(errno));
@@ -2291,84 +2422,48 @@ index ec692e7..56eb165 100644
  	}
  
 -	if (verify_mount(dst, pwd) < 0) 
-+	if (verify_mount(dst, pwd) < 0)
- 		return -1;
-+
-+	return 0;
- }
- 
--#define USAGE_STRING _("USAGE: seunshare [ -v ] [ -t tmpdir ] [ -h homedir ] -- CONTEXT executable [args] ")
-+static int set_label(char *srcdir) {
-+	int rc = -1;
-+	security_context_t filecon = NULL;
-+	if (getfilecon(srcdir, &filecon) <  0) {
-+		fprintf(stderr, _("Failed to get context of %s: %s\n"), srcdir, strerror(errno));
-+		goto err;
-+	}
-+	rc =setfilecon("/tmp", filecon);
-+	if (rc < 0) {
-+		fprintf(stderr, _("Failed to set context %s on /tmp: %s\n"), filecon, strerror(errno));
-+		goto err;
-+	}
-+	rc = 0;
-+err:
-+	freecon(filecon);
-+	return rc;
-+}
- 
--int main(int argc, char **argv) {
--	int rc;
-+static int seunshare_mount_tmp(const char *tmpdir) {
-+
-+	int rc = -1;
-+	if (verbose)
-+		printf("Mount %s on /tmp\n", tmpdir);
-+
-+	int flags = MS_REC | MS_NODEV | MS_NOSUID | MS_NOEXEC;
-+	if (mount("/tmp", "/tmp",  NULL, MS_BIND | flags, NULL) < 0) {
-+		fprintf(stderr, _("Failed to mount /tmp on /tmp: %s\n"), strerror(errno));
-+		goto err;
-+	}
-+
-+	if (mount("/tmp", "/tmp", NULL, MS_PRIVATE | flags, NULL) < 0) {
-+		fprintf(stderr, _("Failed to make /tmp private: %s\n"), strerror(errno));
-+		goto err;
-+	}
-+
-+	if (mount("/var/tmp", "/var/tmp",  NULL, MS_BIND | flags, NULL) < 0) {
-+		fprintf(stderr, _("Failed to mount /var/tmp on /var/tmp: %s\n"), strerror(errno));
-+		goto err;
-+	}
+-		return -1;
++	/* verify whether we mounted what we expected to mount */
++	if (verify_directory(dst, src_st, NULL) < 0) return -1;
 +
-+	if (mount("/var/tmp", "/var/tmp", NULL, MS_PRIVATE | flags, NULL) < 0) {
-+		fprintf(stderr, _("Failed to make /var/tmp private: %s\n"), strerror(errno));
-+		goto err;
-+	}
++	/* bind mount /tmp on /var/tmp too */
++	if (is_tmp) {
++		if (verbose)
++			printf(_("Mounting /tmp on /var/tmp\n"));
 +
-+	if (mount(tmpdir, "/tmp", NULL, MS_BIND | flags, NULL ) < 0) {
-+		fprintf(stderr, _("Failed to mount %s on /tmp: %s\n"), tmpdir, strerror(errno));
-+		goto err;
++		if (mount("/var/tmp", "/var/tmp",  NULL, MS_BIND | flags, NULL) < 0) {
++			fprintf(stderr, _("Failed to mount /var/tmp on /var/tmp: %s\n"), strerror(errno));
++			return -1;
++		}
++		if (mount("/var/tmp", "/var/tmp", NULL, MS_PRIVATE | flags, NULL) < 0) {
++			fprintf(stderr, _("Failed to make /var/tmp private: %s\n"), strerror(errno));
++			return -1;
++		}
++		if (mount("/tmp", "/var/tmp",  NULL, MS_BIND | flags, NULL) < 0) {
++			fprintf(stderr, _("Failed to mount /tmp on /var/tmp: %s\n"), strerror(errno));
++			return -1;
++		}
 +	}
 +
-+	if (mount("/tmp", "/var/tmp",  NULL, MS_BIND | flags, NULL) < 0) {
-+		fprintf(stderr, _("Failed to mount /tmp on /var/tmp: %s\n"), strerror(errno));
-+		goto err;
-+	}
++	return 0;
 +
-+	rc = 0;
-+err:
-+	return rc;
 +}
 +
-+#define USAGE_STRING _("USAGE: seunshare [ -v ] [ -c ] -h homedir [-Z CONTEXT] --  executable [args] ")
-+
-+int sandbox_error(const char *string) {
++/**
++ * Error logging used by cgroups code.
++ */
++static int sandbox_error(const char *string)
++{
 +	fprintf(stderr, string);
 +	syslog(LOG_AUTHPRIV | LOG_ALERT, string);
 +	exit(-1);
 +}
 +
-+int match(const char *string, char *pattern) {
++/**
++ * Regular expression match.
++ */
++static int match(const char *string, char *pattern)
++{
 +	int status;
 +	regex_t re; 
 +	if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB) != 0) {
@@ -2382,7 +2477,11 @@ index ec692e7..56eb165 100644
 +	return 1;
 +}
 +
-+int setup_cgroups() {
++/**
++ * Apply cgroups settings from the /etc/sysconfig/sandbox config file.
++ */
++static int setup_cgroups()
++{
 +	char *cpus = NULL;	/* which CPUs to use */
 +	char *cgroupname = NULL;/* name for the cgroup */
 +	char *mem = NULL;	/* string for memory amount to pass to cgroup */
@@ -2549,85 +2648,198 @@ index ec692e7..56eb165 100644
 +	free(cgroupname);
 +	free(cpus);
 +	return rc;
-+}
+ }
+ 
+-#define USAGE_STRING _("USAGE: seunshare [ -v ] [ -t tmpdir ] [ -h homedir ] -- CONTEXT executable [args] ")
++/**
++ * Clean up runtime temporary directory.  Returns 0 if no problem was detected,
++ * >0 if some error was detected, but errors here are treated as non-fatal and
++ * left to tmpwatch to finish incomplete cleanup.
++ */
++static int cleanup_tmpdir(const char *tmpdir, const char *src,
++	struct passwd *pwd, int copy_content)
++{
++	char *cmdbuf = NULL;
++	int rc = 0;
++
++	/* rsync files back */
++	if (copy_content) {
++		if (asprintf(&cmdbuf, "/usr/bin/rsync --exclude=.X11-unix -utrlHDq --delete '%s/' '%s/'", tmpdir, src) == -1) {
++			fprintf(stderr, _("Out of memory\n"));
++			cmdbuf = NULL;
++			rc++;
++		}
++		if (cmdbuf && spawn_command(cmdbuf, pwd->pw_uid) != 0) {
++			fprintf(stderr, _("Failed to copy files from the runtime temporary directory\n"));
++			rc++;
++		}
++		free(cmdbuf); cmdbuf = NULL;
++	}
 +
-+/*
-+  seunshare will create a tmpdi  in /tmp, with root ownership
-+  Then the process forks and waits for it child to exit to attempt to 
-+  remove the directory. If it fails to remove the directory we will need to
-+  rely on tmpreaper/tmpwatch to clean it up.
-+*/
++	/* remove files from the runtime temporary directory */
++	if (asprintf(&cmdbuf, "/bin/rm -r '%s/' 2>/dev/null", tmpdir) == -1) {
++		fprintf(stderr, _("Out of memory\n"));
++		cmdbuf = NULL;
++		rc++;
++	}
++	/* this may fail if there's root-owned file left in the runtime tmpdir */
++	if (cmdbuf && spawn_command(cmdbuf, pwd->pw_uid) != 0) rc++;
++	free(cmdbuf); cmdbuf = NULL;
 +
-+static char *gen_tmpdir() {
++	/* remove runtime temporary directory */
++	setfsuid(0);
++	if (rmdir(tmpdir) == -1)
++		fprintf(stderr, _("Failed to remove directory %s: %s\n"), tmpdir, strerror(errno));
++	setfsuid(pwd->pw_uid);
 +
-+	char * tmpdir = NULL;
- 	int status = -1;
-+	int rootchild = 0;
++	return 0;
++}
 +
-+	if (seteuid(0)) {
-+		fprintf(stderr, _("Error changing uid, aborting.\n"));
++/**
++ * seunshare will create a tmpdir in /tmp, with root ownership.  The parent
++ * process waits for it child to exit to attempt to remove the directory.  If
++ * it fails to remove the directory, we will need to rely on tmpreaper/tmpwatch
++ * to clean it up.
++ */
++static char *create_tmpdir(const char *src, struct stat *src_st,
++	struct stat *out_st, struct passwd *pwd, security_context_t execcon)
++{
++	char *tmpdir = NULL;
++	char *cmdbuf = NULL;
++	int fd_t = -1, fd_s = -1;
++	struct stat tmp_st;
++	security_context_t con = NULL;
++
++	/* copy selinux context */
++	if (execcon) {
++		if ((fd_s = open(src, O_RDONLY)) < 0) {
++			fprintf(stderr, _("Failed to open directory %s: %s\n"), src, strerror(errno));
++			goto err;
++		}
++		if (fstat(fd_s, &tmp_st) == -1) {
++			fprintf(stderr, _("Failed to stat directory %s: %s\n"), src, strerror(errno));
++			goto err;
++		}
++		if (!equal_stats(src_st, &tmp_st)) {
++			fprintf(stderr, _("Error: %s was replaced by a different directory\n"), src);
++			goto err;
++		}
++		if (fgetfilecon(fd_s, &con) == -1) {
++			fprintf(stderr, _("Failed to get context of the directory %s: %s\n"), src, strerror(errno));
++			goto err;
++		}
++	}
++
++	setfsuid(0);
++	if (asprintf(&tmpdir, "/tmp/.sandbox-%s-XXXXXX", pwd->pw_name) == -1) {
++		fprintf(stderr, _("Out of memory\n"));
++		tmpdir = NULL;
++		goto err;
++	}
++	if (mkdtemp(tmpdir) == NULL) {
++		fprintf(stderr, _("Failed to create temporary directory: %s\n"), strerror(errno));
 +		goto err;
 +	}
 +
-+	tmpdir = mkdtemp(template);
-+	if  (! tmpdir) {
-+		fprintf(stderr, _("Failed to make temporary directory: %s\n"), strerror(errno));
++	/* temporary directory must be owned by root:user */
++	if (verify_directory(tmpdir, NULL, out_st) < 0) {
 +		goto err;
 +	}
- 
--	security_context_t scontext;
-+	if (chmod(tmpdir, 01770)) {
-+		fprintf(stderr, _("Unable to change mode on /tmp: %s\n"), strerror(errno));
-+		rmdir(tmpdir);
-+		tmpdir=NULL;
++	if (check_owner_uid(0, tmpdir, out_st) < 0) {
++		fprintf(stderr, _("Error: %s not owned by UID %d\n"), tmpdir, 0);
++		goto err;
++	}
++	if (check_owner_gid(getgid(), tmpdir, out_st) < 0) {
++		fprintf(stderr, _("Error: %s not owned by GID %d\n"), tmpdir, getgid());
 +		goto err;
 +	}
 +
-+	rootchild = fork();
-+	if (rootchild == -1) {
-+		perror(_("Unable to fork"));
++	/* change permissions of the temporary directory */
++	if ((fd_t = open(tmpdir, O_RDONLY)) < 0) {
++		fprintf(stderr, _("Failed to open directory %s: %s\n"), tmpdir, strerror(errno));
++		goto err;
++	}
++	if (fstat(fd_t, &tmp_st) == -1) {
++		fprintf(stderr, _("Failed to stat directory %s: %s\n"), tmpdir, strerror(errno));
++		goto err;
++	}
++	if (!equal_stats(out_st, &tmp_st)) {
++		fprintf(stderr, _("Error: %s was replaced by a different directory\n"), tmpdir);
++		goto err;
++	}
++	if (fchmod(fd_t, 01770) == -1) {
++		fprintf(stderr, _("Unable to change mode on %s: %s\n"), tmpdir, strerror(errno));
++		goto err;
++	}
++	/* re-stat again to pick change mode */
++	if (fstat(fd_t, out_st) == -1) {
++		fprintf(stderr, _("Failed to stat directory %s: %s\n"), tmpdir, strerror(errno));
 +		goto err;
 +	}
 +
-+	if (rootchild) {
-+		capng_clear(CAPNG_SELECT_BOTH);
-+		if ((capng_lock() != 0) || 
-+		    capng_apply(CAPNG_SELECT_BOTH)) {
-+			perror(_("Failed to drop all capabilities"));
-+			exit(-1);
++	if (execcon) {
++		if (fsetfilecon(fd_t, con) == -1) {	
++			fprintf(stderr, _("Failed to set context of the directory %s: %s\n"), tmpdir, strerror(errno));
++			goto err;
 +		}
-+		waitpid(rootchild, &status, 0);
-+		if(rmdir(tmpdir) < 0)
-+			fprintf(stderr, _("Unlinking %s: %s\n"), tmpdir, strerror(errno));
-+		exit(0);
 +	}
++
++	/* copy files to the new temporary directory */
++	/* XXX: when using -aHAXq args here, rsync tries to chmod/chown/...
++	 * /tmp/.sandbox-$USER-XXXXXX, --ignore-existing does not help */
++	if (asprintf(&cmdbuf, "/usr/bin/rsync -rlHDq '%s/' '%s/'", src, tmpdir) == -1) {
++		fprintf(stderr, _("Out of memory\n"));
++		cmdbuf = NULL;
++		goto err;
++	}
++	if (spawn_command(cmdbuf, pwd->pw_uid) != 0) {
++		fprintf(stderr, _("Failed to populate runtime temporary directory\n"));
++		cleanup_tmpdir(tmpdir, src, pwd, 0);
++		goto err;
++	}
++
++	goto good;
 +err:
++	free(tmpdir);
++	tmpdir = NULL;
++good:
++	free(cmdbuf); cmdbuf = NULL;
++	freecon(con);
++	if (fd_t >= 0) close(fd_t);
++	if (fd_s >= 0) close(fd_s);
 +	return tmpdir;
 +}
-+
-+int main(int argc, char **argv) {
-+	int rc = -1;
-+	int status = -1;
+ 
+ int main(int argc, char **argv) {
+-	int rc;
+ 	int status = -1;
 +	security_context_t execcon = NULL;
-+	char *tmpdir = NULL;
-+	char *cpbuf=NULL;
  
- 	int flag_index;		/* flag index in argv[] */
+-	security_context_t scontext;
+-
+-	int flag_index;		/* flag index in argv[] */
  	int clflag;		/* holds codes for command line flags */
- 	char *tmpdir_s = NULL;	/* tmpdir spec'd by user in argv[] */
- 	char *homedir_s = NULL;	/* homedir spec'd by user in argv[] */
+-	char *tmpdir_s = NULL;	/* tmpdir spec'd by user in argv[] */
 +	int usecgroups = 0;
++
+ 	char *homedir_s = NULL;	/* homedir spec'd by user in argv[] */
++	char *tmpdir_s = NULL;	/* tmpdir spec'd by user in argv[] */
++	char *tmpdir_r = NULL;	/* tmpdir created by seunshare */
++
++	struct stat st_homedir;
++	struct stat st_tmpdir_s;
++	struct stat st_tmpdir_r;
  
  	const struct option long_options[] = {
  		{"homedir", 1, 0, 'h'},
--		{"tmpdir", 1, 0, 't'},
+ 		{"tmpdir", 1, 0, 't'},
  		{"verbose", 1, 0, 'v'},
 +		{"cgroups", 1, 0, 'c'},
 +		{"context", 1, 0, 'Z'},
  		{NULL, 0, 0, 0}
  	};
  
-@@ -180,6 +523,12 @@ int main(int argc, char **argv) {
+@@ -180,6 +677,12 @@ int main(int argc, char **argv) {
  		return -1;
  	}
  
@@ -2640,24 +2852,31 @@ index ec692e7..56eb165 100644
  	struct passwd *pwd=getpwuid(uid);
  	if (!pwd) {
  		perror(_("getpwduid failed"));
-@@ -192,80 +541,99 @@ int main(int argc, char **argv) {
+@@ -187,34 +690,30 @@ int main(int argc, char **argv) {
+ 	}
+ 
+ 	if (verify_shell(pwd->pw_shell) < 0) {
+-		fprintf(stderr, _("Error!  Shell is not valid.\n"));
++		fprintf(stderr, _("Error: User shell is not valid\n"));
+ 		return -1;
  	}
  
  	while (1) {
 -		clflag = getopt_long(argc, argv, "h:t:", long_options,
-+		clflag = getopt_long(argc, argv, "cvh:Z:", long_options,
- 				     &flag_index);
+-				     &flag_index);
++		clflag = getopt_long(argc, argv, "cvh:t:Z:", long_options, NULL);
  		if (clflag == -1)
  			break;
  
  		switch (clflag) {
--		case 't':
+ 		case 't':
 -			if (!(tmpdir_s = realpath(optarg, NULL))) {
 -				fprintf(stderr, _("Invalid mount point %s: %s\n"), optarg, strerror(errno));
 -				return -1;
 -			}
 -			if (verify_mount(tmpdir_s, pwd) < 0) return -1;
--			break;
++			tmpdir_s = optarg;
+ 			break;
  		case 'h':
 -			if (!(homedir_s = realpath(optarg, NULL))) {
 -				fprintf(stderr, _("Invalid mount point %s: %s\n"), optarg, strerror(errno));
@@ -2668,25 +2887,24 @@ index ec692e7..56eb165 100644
 +			homedir_s = optarg;
  			break;
  		case 'v':
- 			verbose = 1;
- 			break;
+-			verbose = 1;
++			verbose++;
++			break;
 +		case 'c':
 +			usecgroups = 1;
 +			break;
 +		case 'Z':
-+			execcon = strdup(optarg);
-+			break;
++			execcon = optarg;
+ 			break;
  		default:
  			fprintf(stderr, "%s\n", USAGE_STRING);
- 			return -1;
- 		}
+@@ -223,76 +722,81 @@ int main(int argc, char **argv) {
  	}
  
--	if (! homedir_s && ! tmpdir_s) {
+ 	if (! homedir_s && ! tmpdir_s) {
 -		fprintf(stderr, _("Error: tmpdir and/or homedir required \n"),
 -			"%s\n", USAGE_STRING);
-+	if (! homedir_s ) {
-+		fprintf(stderr, _("Error: homedir required \n %s\n"),USAGE_STRING);
++		fprintf(stderr, _("Error: tmpdir and/or homedir required\n %s\n"), USAGE_STRING);
  		return -1;
  	}
  
@@ -2694,33 +2912,19 @@ index ec692e7..56eb165 100644
 -		fprintf(stderr, _("Error: context and executable required \n"),
 -			"%s\n", USAGE_STRING);
 +	if (argc - optind < 1) {
-+		fprintf(stderr, _("Error: executable required \n %s \n"), USAGE_STRING);
++		fprintf(stderr, _("Error: executable required\n %s\n"), USAGE_STRING);
  		return -1;
  	}
  
 -	scontext = argv[optind++];
 -	
- 	if (set_signal_handles())
- 		return -1;
- 
-+	if (usecgroups && setup_cgroups() < 0) return  -1;
-+
-+	/* on NFS machines you need to setfsuid to be able to access files 
-+	   on homedir, if this fails on a non NFS machine, we don't care, 
-+	   if it fails on an NFS machine, the code below will fail.
-+	*/
-+	if (setfsuid(uid) < 0) {
-+		fprintf(stderr, _("setfsuid failed. %s"), strerror(errno));
-+		return -1;
-+	}
-+
-+	if (verify_mount(pwd->pw_dir, pwd) < 0)	return -1;
-+	if (verify_mount(homedir_s, pwd) < 0)	return -1;
-+
-+	if (! (tmpdir = gen_tmpdir())) return -1;
-+
-         if (unshare(CLONE_NEWNS) < 0) {
- 		perror(_("Failed to unshare"));
+-	if (set_signal_handles())
+-		return -1;
+-
+-        if (unshare(CLONE_NEWNS) < 0) {
+-		perror(_("Failed to unshare"));
++	if (execcon && is_selinux_enabled() != 1) {
++		fprintf(stderr, _("Error: execution context specified, but SELinux is not enabled\n"));
  		return -1;
  	}
  
@@ -2735,38 +2939,34 @@ index ec692e7..56eb165 100644
 -				
 -		if (tmpdir_s && seunshare_mount(tmpdir_s, "/tmp", pwd) < 0)
 -				return -1;
-+	if (seunshare_mount_tmp(tmpdir) < 0) return -1;
-+
-+	if (seunshare_mount_home(homedir_s, pwd) < 0) return -1;
-+
-+	if (asprintf(&tmpdir_s, "%s/.sandboxtmp", pwd->pw_dir) < 0) {
-+		fprintf(stderr, _("Failed to allocate tmpdir path: %s\n"), strerror(errno));
-+		return -1;
- 	}
- 
-+	if (execcon && is_selinux_enabled() > 0)
-+		set_label(tmpdir_s);
-+
- 	if (drop_capabilities(uid)) {
- 		perror(_("Failed to drop all capabilities"));
--		return -1;
-+		goto err;
-+	}
+-	}
++	if (set_signal_handles()) return -1;
 +
-+	/* Since we have dropped capabilities and we have reset the UID,
-+	   the system call below should be safe */
-+	if (asprintf(&cpbuf, "/usr/bin/rsync -tr %s/* %s/.??* /tmp/ 2>/dev/null", tmpdir_s, tmpdir_s) < 0) {
-+		fprintf(stderr, _("Failed to allocate copy command: %s\n"), strerror(errno));
-+		goto err;
-+	}
++	if (usecgroups && setup_cgroups() < 0) return  -1;
 +
-+	rc = system(cpbuf);
-+	free(cpbuf);
-+	if (rc < 0) {
-+		fprintf(stderr, _("Failed to copy  %s to /tmp: %s\n"), tmpdir_s, strerror(errno));
-+		goto err;
++	/* On NFS machines you need to setfsuid to be able to access files 
++	   on homedir, if this fails on a non NFS machine, we don't care, 
++	   if it fails on an NFS machine, the code below will fail. */
++	setfsuid(uid);
++
++	/* verify homedir and tmpdir */
++	if (homedir_s && (
++		verify_directory(homedir_s, NULL, &st_homedir) < 0 ||
++		check_owner_uid(uid, homedir_s, &st_homedir))) return -1;
++	if (tmpdir_s && (
++		verify_directory(tmpdir_s, NULL, &st_tmpdir_s) < 0 ||
++		check_owner_uid(uid, tmpdir_s, &st_tmpdir_s))) return -1;
+ 
+-	if (drop_capabilities(uid)) {
+-		perror(_("Failed to drop all capabilities"));
++	/* create runtime tmpdir */
++	if (tmpdir_s && (tmpdir_r = create_tmpdir(tmpdir_s, &st_tmpdir_s,
++						  &st_tmpdir_r, pwd, execcon)) == NULL) {
++		fprintf(stderr, _("Failed to create runtime temporary directory\n"));
+ 		return -1;
  	}
  
++	/* spawn child process */
  	int child = fork();
  	if (child == -1) {
  		perror(_("Unable to fork"));
@@ -2774,59 +2974,107 @@ index ec692e7..56eb165 100644
 +		goto err;
  	}
  
- 	if (!child) {
-@@ -286,11 +654,15 @@ int main(int argc, char **argv) {
- 			exit(-1);
+-	if (!child) {
+-		char *display=NULL;
+-		/* Construct a new environment */
+-		char *d = getenv("DISPLAY");
+-		if (d) {
+-			display =  strdup(d);
+-			if (!display) {
+-				perror(_("Out of memory"));
+-				exit(-1);
+-			}
++	if (child == 0) {
++		char *display = NULL;
++		int rc = -1;
++
++		if (unshare(CLONE_NEWNS) < 0) {
++			perror(_("Failed to unshare"));
++			goto childerr;
+ 		}
+ 
+-		if ((rc = clearenv())) {
+-			perror(_("Unable to clear environment"));
+-			free(display);
+-			exit(-1);
++		setfsuid(uid);
++
++		/* mount homedir and tmpdir, in this order */
++		if (homedir_s && seunshare_mount(homedir_s, pwd->pw_dir,
++			&st_homedir) != 0) goto childerr;
++		if (tmpdir_s &&	seunshare_mount(tmpdir_r, "/tmp",
++			&st_tmpdir_r) != 0) goto childerr;
++
++		if (drop_privs(uid) != 0) goto childerr;
++
++		/* construct a new environment */
++		if ((display = getenv("DISPLAY")) != NULL) {
++			if ((display = strdup(display)) == NULL) {
++				perror(_("Out of memory"));
++				goto childerr;
++			}
  		}
- 		
+-		
 -		if (setexeccon(scontext)) {
 -			fprintf(stderr, _("Could not set exec context to %s.\n"),
 -				scontext);
 -			free(display);
 -			exit(-1);
-+		if (execcon) {
-+			if (setexeccon(execcon)) {
-+				fprintf(stderr, _("Could not set exec context to %s.\n"),
-+					execcon);
-+				free(display);
-+				free(execcon);
-+				exit(-1);
-+			}
-+			free(execcon);
++		if ((rc = clearenv()) != 0) {
++			perror(_("Failed to clear environment"));
++			goto childerr;
  		}
- 
+-
  		if (display) 
-@@ -305,17 +677,26 @@ int main(int argc, char **argv) {
+ 			rc |= setenv("DISPLAY", display, 1);
+ 		rc |= setenv("HOME", pwd->pw_dir, 1);
+@@ -300,22 +804,39 @@ int main(int argc, char **argv) {
+ 		rc |= setenv("USER", pwd->pw_name, 1);
+ 		rc |= setenv("LOGNAME", pwd->pw_name, 1);
+ 		rc |= setenv("PATH", DEFAULT_PATH, 1);
++		if (rc != 0) {
++			fprintf(stderr, _("Failed to construct environment\n"));
++			goto childerr;
++		}
+ 		
++		/* selinux context */
++		if (execcon && setexeccon(execcon) != 0) {
++			fprintf(stderr, _("Could not set exec context to %s.\n"), execcon);
++			goto childerr;
++		}
++
+ 		if (chdir(pwd->pw_dir)) {
  			perror(_("Failed to change dir to homedir"));
- 			exit(-1);
+-			exit(-1);
++			goto childerr;
  		}
 -		setsid();
++
  		execv(argv[optind], argv + optind);
++		fprintf(stderr, _("Failed to execute command %s: %s\n"), argv[optind], strerror(errno));
++childerr:
  		free(display);
- 		perror("execv");
+-		perror("execv");
  		exit(-1);
- 	} else {
- 		waitpid(child, &status, 0);
-+		if (asprintf(&cpbuf, "/usr/bin/rsync --delete --exclude=.X11-unix -utr /tmp/ %s 2>/dev/null", tmpdir_s) < 0) {
-+			fprintf(stderr, _("Failed to allocate copy command: %s\n"), strerror(errno));
-+		} else {
-+			rc = system(cpbuf);
-+			free(cpbuf);
-+			if (rc < 0) {
-+				fprintf(stderr, _("Failed to copy  /tmp to %s: %s\n"), tmpdir_s, strerror(errno));
-+			}
-+		}
-+		if (system("rm -rf /tmp 2>/dev/null") < 0) {
-+			fprintf(stderr, _("Failed to cleanup /tmp: %s\n"), strerror(errno));
-+		} 
+-	} else {
+-		waitpid(child, &status, 0);
  	}
--
-+err:
- 	free(tmpdir_s);
+ 
+-	free(tmpdir_s);
 -	free(homedir_s);
--
++	// XXX: drop some caps here?
+ 
++	/* parent waits for child exit to do the cleanup */
++	waitpid(child, &status, 0);
++	status_to_retval(status, status);
++
++	if (tmpdir_r) cleanup_tmpdir(tmpdir_r, tmpdir_s, pwd, 1);
++
++err:
++	free(tmpdir_r);
  	return status;
  }
++
 diff --git a/policycoreutils/sandbox/start b/policycoreutils/sandbox/start
 new file mode 100644
 index 0000000..52950d7
diff --git a/policycoreutils.spec b/policycoreutils.spec
index d12a576..916e7c0 100644
--- a/policycoreutils.spec
+++ b/policycoreutils.spec
@@ -7,7 +7,7 @@
 Summary: SELinux policy core utilities
 Name:	 policycoreutils
 Version: 2.0.85
-Release: 16%{?dist}
+Release: 17%{?dist}
 License: GPLv2
 Group:	 System Environment/Base
 # Based on git repository with tag 20101221
@@ -181,6 +181,7 @@ exit 0
 if [ $1 -eq 1 ]; then
    /sbin/chkconfig sandbox --add
 fi
+
 %preun sandbox
 if [ $1 -eq 0 ]; then
    /sbin/chkconfig sandbox --del
@@ -330,6 +331,9 @@ fi
 exit 0
 
 %changelog
+* Tue Mar 8 2011 Dan Walsh <dwalsh at redhat.com> 2.0.85-17
+- Use rewritten seunshare from thoger
+
 * Mon Mar 7 2011 Dan Walsh <dwalsh at redhat.com> 2.0.85-16
 - Require python-IPy for policycoreutils-python package
 - Fixes for sepologen 


More information about the scm-commits mailing list