[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