diff -up policycoreutils-2.0.86/restorecond/restorecond_user.conf.sandbox policycoreutils-2.0.86/restorecond/restorecond_user.conf --- policycoreutils-2.0.86/restorecond/restorecond_user.conf.sandbox 2011-06-13 13:47:06.000000000 -0400 +++ policycoreutils-2.0.86/restorecond/restorecond_user.conf 2011-06-13 13:47:27.000000000 -0400 @@ -4,4 +4,4 @@ ~/local/* ~/.fonts/* ~/.cache/* - +~/.config/* diff -up policycoreutils-2.0.86/sandbox/sandbox.8.sandbox policycoreutils-2.0.86/sandbox/sandbox.8 --- policycoreutils-2.0.86/sandbox/sandbox.8.sandbox 2011-07-07 14:42:18.000000000 -0400 +++ policycoreutils-2.0.86/sandbox/sandbox.8 2012-01-03 11:09:22.391519370 -0500 @@ -3,11 +3,11 @@ sandbox \- Run cmd under an SELinux sandbox .SH SYNOPSIS .B sandbox -[-l level ] [[-M | -X] -H homedir -T tempdir ] [-I includefile ] [ -W windowmanager ] [ -w windowsize ] [[-i file ]...] [ -t type ] cmd +[-C] [-c] [ -d DPI ] [-l level ] [[-M | -X] -H homedir -T tempdir ] [-I includefile ] [ -W windowmanager ] [ -w windowsize ] [[-i file ]...] [ -t type ] cmd .br .B sandbox -[-l level ] [[-M | -X] -H homedir -T tempdir ] [-I includefile ] [ -W windowmanager ] [ -w windowsize ] [[-i file ]...] [ -t type ] -S +[-C] [-c] [ -d DPI ] [-l level ] [[-M | -X] -H homedir -T tempdir ] [-I includefile ] [ -W windowmanager ] [ -w windowsize ] [[-i file ]...] [ -t type ] -S .br .SH DESCRIPTION .PP @@ -49,7 +49,7 @@ Use alternate tempory directory to mount Run a full desktop session, Requires level, and home and tmpdir. .TP \fB\-w windowsize\fR -Specifies the windowsize when creating an X based Sandbox. The default windowsize is 1000x700. +Specifies the windowsize when creating an X based Sandbox. The default windowsize is 1000x700. .TP \fB\-W windowmanager\fR Select alternative window manager to run within @@ -60,8 +60,14 @@ Default to /usr/bin/matchbox-window-mana Create an X based Sandbox for gui apps, temporary files for $HOME and /tmp, secondary Xserver, defaults to sandbox_x_t .TP -\fB\-C\fR +\fB\-d\fR +Set the DPI value for the sanbox X Server. Defaults to the current X Sever DPI. +.TP +\fB\-c\fR Use control groups to control this copy of sandbox. Specify parameters in /etc/sysconfig/sandbox. Max memory usage and cpu usage are to be specified in percent. You can specify which CPUs to use by numbering them 0,1,2... etc. +.TP +\fB\-C\fR +Use capabilities within the sandbox. By default applications executed within the sandbox will not be allowed to use capabilities (setuid apps), with the -C flag, you can use programs requiring capabilities. .PP .SH "SEE ALSO" .TP @@ -69,7 +75,7 @@ runcon(1), seunshare(8), selinux(8) .PP .SH AUTHOR -This manual page was written by +This manual page was written by .I Dan Walsh and .I Thomas Liu diff -up policycoreutils-2.0.86/sandbox/sandbox.sandbox policycoreutils-2.0.86/sandbox/sandbox --- policycoreutils-2.0.86/sandbox/sandbox.sandbox 2011-06-13 13:44:44.000000000 -0400 +++ policycoreutils-2.0.86/sandbox/sandbox 2012-01-03 11:08:43.619495043 -0500 @@ -25,7 +25,7 @@ import selinux import signal from tempfile import mkdtemp import pwd -import commands +import commands import setools PROGNAME = "policycoreutils" @@ -88,9 +88,7 @@ def copyfile(file, srcdir, dest): except shutil.Error, elist: for e in elist.message: - # ignore files that are missing - if not e[2].startswith("[Errno 2]"): - sys.stderr.write(e[2]) + sys.stderr.write(e[2]) SAVE_FILES[file] = (dest, os.path.getmtime(dest)) @@ -120,10 +118,30 @@ def reserve(level): sock.bind("\0%s" % level) fcntl.fcntl(sock.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC) +def get_range(): + try: + level =selinux.getcon_raw()[1].split(":")[4] + lowc,highc = level.split(".") + low = int(lowc[1:]) + high = int(highc[1:])+1 + if high - low == 0: + raise IndexError + + return low,high + except IndexError: + raise ValueError(_("User account must be setup with an MCS Range")) + def gen_mcs(): - while True: - i1 = random.randrange(0, 1024) - i2 = random.randrange(0, 1024) + low, high = get_range() + + level = None + ctr = 0 + total = high-low + total = (total * (total - 1))/2 + while ctr < total: + ctr += 1 + i1 = random.randrange(low, high) + i2 = random.randrange(low, high) if i1 == i2: continue if i1 > i2: @@ -136,7 +154,10 @@ def gen_mcs(): except socket.error: continue break - return level + if level: + return level + raise ValueError(_("Failed to find any unused category sets. Consider a larger MCS range for this user.")) + def fullpath(cmd): for i in [ "/", "./", "../" ]: @@ -170,7 +191,7 @@ class Sandbox: if not os.path.exists(SEUNSHARE): raise ValueError(_(""" -%s is required for the action you want to perform. +%s is required for the action you want to perform. """) % SEUNSHARE) def __mount_callback(self, option, opt, value, parser): @@ -181,12 +202,12 @@ class Sandbox: setattr(parser.values, option.dest, True) if not os.path.exists(SEUNSHARE): raise ValueError(_(""" -%s is required for the action you want to perform. +%s is required for the action you want to perform. """) % SEUNSHARE) if not os.path.exists(SANDBOXSH): raise ValueError(_(""" -%s is required for the action you want to perform. +%s is required for the action you want to perform. """) % SANDBOXSH) def __validdir(self, option, opt, value, parser): @@ -246,26 +267,25 @@ kill -TERM $WM_PID 2> /dev/null def usage(self, message = ""): error_exit("%s\n%s" % (self.__parser.usage, message)) - + def __parse_options(self): from optparse import OptionParser types = "" try: types = _(""" -Policy defines the following types for use with the -t: +Policy defines the following types for use with the -t: \t%s """) % "\n\t".join(setools.seinfo(setools.ATTRIBUTE, "sandbox_type")[0]['types']) except RuntimeError: pass usage = _(""" -sandbox [-h] [-l level ] [-[X|M] [-H homedir] [-T tempdir]] [-I includefile ] [-W windowmanager ] [ -w windowsize ] [[-i file ] ...] [ -t type ] command +sandbox [-h] [-c] [-l level ] [-[X|M] [-H homedir] [-T tempdir]] [-I includefile ] [-W windowmanager ] [ -w windowsize ] [[-i file ] ...] [ -t type ] command -sandbox [-h] [-l level ] [-[X|M] [-H homedir] [-T tempdir]] [-I includefile ] [-W windowmanager ] [ -w windowsize ] [[-i file ] ...] [ -t type ] -S +sandbox [-h] [-c] [-l level ] [-[X|M] [-H homedir] [-T tempdir]] [-I includefile ] [-W windowmanager ] [ -w windowsize ] [[-i file ] ...] [ -t type ] -S %s """) % types - parser = OptionParser(version=self.VERSION, usage=usage) parser.disable_interspersed_args() parser.add_option("-i", "--include", @@ -281,6 +301,10 @@ sandbox [-h] [-l level ] [-[X|M] [-H hom action="callback", callback=self.__mount_callback, help=_("mount new home and/or tmp directory")) + parser.add_option("-d", "--dpi", + dest="dpi", action="store", + help=_("dots per inch for X display")) + parser.add_option("-S", "--session", action="store_true", dest="session", default=False, help=_("run complete desktop session within sandbox")) @@ -291,17 +315,17 @@ sandbox [-h] [-l level ] [-[X|M] [-H hom parser.add_option("-H", "--homedir", action="callback", callback=self.__validdir, type="string", - dest="homedir", + dest="homedir", help=_("alternate home directory to use for mounting")) - parser.add_option("-T", "--tmpdir", dest="tmpdir", + parser.add_option("-T", "--tmpdir", dest="tmpdir", type="string", action="callback", callback=self.__validdir, help=_("alternate /tmp directory to use for mounting")) parser.add_option("-w", "--windowsize", dest="windowsize", type="string", default=DEFAULT_WINDOWSIZE, - help="size of the sandbox window") + help="size of the sandbox window") parser.add_option("-W", "--windowmanager", dest="wm", type="string", @@ -311,9 +335,13 @@ sandbox [-h] [-l level ] [-[X|M] [-H hom parser.add_option("-l", "--level", dest="level", help=_("MCS/MLS level for the sandbox")) - parser.add_option("-C", "--cgroups", - action="store_true", dest="usecgroup", default=False, - help="Use cgroups to limit this sandbox.") + parser.add_option("-c", "--cgroups", + action="store_true", dest="usecgroup", default=False, + help=_("Use cgroups to limit this sandbox.")) + + parser.add_option("-C", "--capabilities", + action="store_true", dest="usecaps", default=False, + help="Allow apps requiring capabilities to run within the sandbox.") self.__parser=parser @@ -366,8 +394,8 @@ sandbox [-h] [-l level ] [-[X|M] [-H hom con = selinux.getcon()[1].split(":") self.__execcon = "%s:%s:%s:%s" % (con[0], con[1], self.setype, level) - self.__filecon = "%s:%s:%s:%s" % (con[0], "object_r", - "%s_file_t" % self.setype[:-2], + self.__filecon = "%s:%s:%s:%s" % (con[0], "object_r", + "%s_file_t" % self.setype[:-2], level) def __setup_dir(self): if self.__options.level or self.__options.session: @@ -392,12 +420,20 @@ sandbox [-h] [-l level ] [-[X|M] [-H hom def __execute(self): try: cmds = [ SEUNSHARE, "-Z", self.__execcon ] - if self.__options.usecgroup == True: + if self.__options.usecgroup: cmds.append('-c') + if self.__options.usecaps: + cmds.append('-C') if self.__mount: cmds += [ "-t", self.__tmpdir, "-h", self.__homedir ] if self.__options.X_ind: + if self.__options.dpi: + dpi = self.__options.dpi + else: + import gtk + dpi = str(gtk.settings_get_default().props.gtk_xft_dpi/1024) + xmodmapfile = self.__homedir + "/.xmodmap" xd = open(xmodmapfile,"w") subprocess.Popen(["/usr/bin/xmodmap","-pke"],stdout=xd).wait() @@ -405,7 +441,7 @@ sandbox [-h] [-l level ] [-[X|M] [-H hom self.__setup_sandboxrc(self.__options.wm) - cmds += [ "--", SANDBOXSH, self.__options.windowsize ] + cmds += [ "--", SANDBOXSH, self.__options.windowsize, dpi ] else: cmds += [ "--" ] + self.__paths return subprocess.Popen(cmds).wait() diff -up policycoreutils-2.0.86/sandbox/sandboxX.sh.sandbox policycoreutils-2.0.86/sandbox/sandboxX.sh --- policycoreutils-2.0.86/sandbox/sandboxX.sh.sandbox 2011-06-13 13:44:44.000000000 -0400 +++ policycoreutils-2.0.86/sandbox/sandboxX.sh 2012-01-03 11:10:04.985546365 -0500 @@ -1,10 +1,12 @@ -#!/bin/bash -context=`id -Z | secon -t ` -export TITLE="`grep ^#TITLE: ~/.sandboxrc | /usr/bin/cut -b8-80` ($context)" -[ $# -eq 1 ] && export SCREENSIZE="$1" || export SCREENSIZE="1000x700" +#!/bin/bash +trap "" TERM +context=`id -Z | secon -t -l -P` +export TITLE="Sandbox $context -- `grep ^#TITLE: ~/.sandboxrc | /usr/bin/cut -b8-80`" +[ -z $1 ] && export SCREENSIZE="1000x700" || export SCREENSIZE="$1" +[ -z $2 ] && export DPI="96" || export DPI="$2" trap "exit 0" HUP -(/usr/bin/Xephyr -nolisten tcp -title "$TITLE" -terminate -screen $SCREENSIZE -displayfd 5 5>&1 2>/dev/null) | while read D; do +(/usr/bin/Xephyr -title "$TITLE" -terminate -screen $SCREENSIZE -dpi $DPI -displayfd 5 5>&1 2>/dev/null) | while read D; do export DISPLAY=:$D cat > ~/seremote << __EOF #!/bin/sh @@ -13,7 +15,7 @@ __EOF chmod +x ~/seremote /usr/share/sandbox/start $HOME/.sandboxrc export EXITCODE=$? - kill -HUP 0 + kill -TERM 0 break done exit 0 diff -up policycoreutils-2.0.86/sandbox/seunshare.8.sandbox policycoreutils-2.0.86/sandbox/seunshare.8 --- policycoreutils-2.0.86/sandbox/seunshare.8.sandbox 2011-07-07 14:41:16.000000000 -0400 +++ policycoreutils-2.0.86/sandbox/seunshare.8 2012-01-03 11:10:36.498566587 -0500 @@ -3,11 +3,11 @@ seunshare \- Run cmd with alternate homedir, tmpdir and/or SELinux context .SH SYNOPSIS .B seunshare -[ -v ] [ -t tmpdir ] [ -h homedir ] [ -Z context ] -- executable [args] +[ -v ] [ -c ] [ -C ] [ -k ] [ -t tmpdir ] [ -h homedir ] [ -Z context ] -- executable [args] .br .SH DESCRIPTION .PP -Run the +Run the .I executable within the specified context, using the alternate home directory and /tmp directory. The seunshare command unshares from the default namespace, then mounts the specified homedir and tmpdir over the default homedir and /tmp. Finally it tells the kernel to execute the application under the specified SELinux context. @@ -18,9 +18,15 @@ Alternate homedir to be used by the appl \fB\-t\ tmpdir Use alternate tempory directory to mount on /tmp. tmpdir must be owned by the user. .TP -\fB\-c cgroups\fR +\fB\-c --cgroups\fR Use cgroups to control this copy of seunshare. Specify parameters in /etc/sysconfig/sandbox. Max memory usage and cpu usage are to be specified in percent. You can specify which CPUs to use by numbering them 0,1,2... etc. .TP +\fB\-C --capabilities\fR +Allow apps executed within the namespace to use capabilities. Default is no capabilities. +.TP +\fB\-k --kill\fR +Kill all processes with matching MCS level. +.TP \fB\-Z\ context Use alternate SELinux context while runing the executable. .TP @@ -28,10 +34,10 @@ Use alternate SELinux context while runi Verbose output .SH "SEE ALSO" .TP -runcon(1), sandbox(8), selinux(8) +runcon(1), sandbox(8), selinux(8) .PP .SH AUTHOR -This manual page was written by +This manual page was written by .I Dan Walsh and .I Thomas Liu diff -up policycoreutils-2.0.86/sandbox/seunshare.c.sandbox policycoreutils-2.0.86/sandbox/seunshare.c --- policycoreutils-2.0.86/sandbox/seunshare.c.sandbox 2011-06-13 13:44:44.000000000 -0400 +++ policycoreutils-2.0.86/sandbox/seunshare.c 2012-01-03 11:08:59.081504712 -0500 @@ -5,8 +5,9 @@ #define _GNU_SOURCE #include -#include +#include #include +#include #include #include #include @@ -18,7 +19,6 @@ #include #include #include -#include #include #include #include /* for getopt_long() form of getopt() */ @@ -29,6 +29,7 @@ #include #include /* for context-mangling functions */ +#include #ifdef USE_NLS #include /* for setlocale() */ @@ -42,8 +43,8 @@ #define MS_REC 1<<14 #endif -#ifndef MS_PRIVATE -#define MS_PRIVATE 1<<18 +#ifndef MS_SLAVE +#define MS_SLAVE 1<<19 #endif #ifndef PACKAGE @@ -52,21 +53,22 @@ #define BUF_SIZE 1024 #define DEFAULT_PATH "/usr/bin:/bin" - -#define USAGE_STRING _("USAGE: seunshare [ -v ] [ -c ] -t tmpdir -h homedir [-Z context] -- executable [args]") +#define USAGE_STRING _("USAGE: seunshare [ -v ] [ -C ] [ -c ] [ -k ] [ -t tmpdir ] [ -h homedir ] [ -Z CONTEXT ] -- executable [args] ") static int verbose = 0; +static int child = 0; +static capng_select_t cap_set = CAPNG_SELECT_BOTH; /** * This function will drop all capabilities. */ static int drop_caps() { - if (capng_have_capabilities(CAPNG_SELECT_BOTH) == CAPNG_NONE) + if (capng_have_capabilities(cap_set) == CAPNG_NONE) return 0; - capng_clear(CAPNG_SELECT_BOTH); - if (capng_lock() == -1 || capng_apply(CAPNG_SELECT_BOTH) == -1) { + capng_clear(cap_set); + if (capng_lock() == -1 || capng_apply(cap_set) == -1) { fprintf(stderr, _("Failed to drop all capabilities\n")); return -1; } @@ -86,6 +88,13 @@ static int drop_privs(uid_t uid) } /** + * If the user sends a siginto to seunshare, kill the child's session + */ +void handler(int sig) { + if (child > 0) kill(-child,sig); +} + +/** * Take care of any signal setup. */ static int set_signal_handles(void) @@ -101,11 +110,16 @@ static int set_signal_handles(void) (void)sigprocmask(SIG_SETMASK, &empty, NULL); /* Terminate on SIGHUP */ - if (signal(SIGHUP, SIG_IGN) == SIG_ERR) { + if (signal(SIGHUP, SIG_DFL) == SIG_ERR) { perror("Unable to set SIGHUP handler"); return -1; } + if (signal(SIGINT, handler) == SIG_ERR) { + perror("Unable to set SIGINT handler"); + return -1; + } + return 0; } @@ -192,7 +206,7 @@ static int verify_directory(const char * struct stat sb; 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; @@ -241,7 +255,7 @@ static int verify_shell(const char *shel */ static int seunshare_mount(const char *src, const char *dst, struct stat *src_st) { - int flags = MS_REC; + int flags = 0; int is_tmp = 0; if (verbose) @@ -253,14 +267,6 @@ static int seunshare_mount(const char *s } /* 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 | flags, NULL) < 0) { - fprintf(stderr, _("Failed to make %s private: %s\n"), dst, strerror(errno)); - return -1; - } if (mount(src, dst, NULL, MS_BIND | flags, NULL) < 0) { fprintf(stderr, _("Failed to mount %s on %s: %s\n"), src, dst, strerror(errno)); return -1; @@ -274,14 +280,6 @@ static int seunshare_mount(const char *s if (verbose) printf(_("Mounting /tmp on /var/tmp\n")); - 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; @@ -308,12 +306,12 @@ static int sandbox_error(const char *str static int match(const char *string, char *pattern) { int status; - regex_t re; + regex_t re; if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB) != 0) { return 0; } status = regexec(&re, string, (size_t)0, NULL, 0); - regfree(&re); + regfree(&re); if (status != 0) { return 0; } @@ -334,8 +332,9 @@ static int setup_cgroups() char buf[BUF_SIZE]; char *tok = NULL; int rc = -1; - const char* fname = "/etc/sysconfig/sandbox"; - + char *str = NULL; + const char* fname = "/etc/sysconfig/sandbox"; + if ((fp = fopen(fname, "rt")) == NULL) { fprintf(stderr, "Error opening sandbox config file."); return rc; @@ -343,12 +342,15 @@ static int setup_cgroups() while(fgets(buf, BUF_SIZE, fp) != NULL) { /* Skip comments */ if (buf[0] == '#') continue; - + /* Copy the string, ignoring whitespace */ int len = strlen(buf); - char *str = malloc((len + 1) * sizeof(char)); - - int ind = 0; + free(str); + str = malloc((len + 1) * sizeof(char)); + if (!str) + goto err; + + int ind = 0; int i; for (i = 0; i < len; i++) { char cur = buf[i]; @@ -358,7 +360,7 @@ static int setup_cgroups() } } str[ind] = '\0'; - + tok = strtok(str, "=\n"); if (tok != NULL) { if (!strcmp(tok, "CPUAFFINITY")) { @@ -382,7 +384,7 @@ static int setup_cgroups() fprintf(stderr, "Error parsing config file."); goto err; } - + } else if (!strcmp(tok, "CPUUSAGE")) { tok = strtok(NULL, "=\n"); if (match(tok, "^[0-9]+\%")) { @@ -400,14 +402,14 @@ static int setup_cgroups() continue; } } - + } if (mem == NULL) { long phypz = sysconf(_SC_PHYS_PAGES); long psize = sysconf(_SC_PAGE_SIZE); memusage = phypz * psize * (float) memusage / 100.0; } - + cgroup_init(); int64_t current_runtime = 0; @@ -423,8 +425,8 @@ static int setup_cgroups() cgroup_get_cgroup(curr); cgroup_get_value_int64(cgroup_get_controller(curr, "cpu"), "cpu.rt_runtime_us", ¤t_runtime); cgroup_get_value_int64(cgroup_get_controller(curr, "cpu"), "cpu.rt_period_us", ¤t_period); - } - + } + ret = cgroup_get_current_controller_path(getpid(), "memory", &curr_mem_path); if (ret) { sandbox_error("Error while trying to get current controller path.\n"); @@ -432,33 +434,33 @@ static int setup_cgroups() struct cgroup *curr = cgroup_new_cgroup(curr_mem_path); cgroup_get_cgroup(curr); cgroup_get_value_int64(cgroup_get_controller(curr, "memory"), "memory.limit_in_bytes", ¤t_mem); - } - + } + if (((float) cpupercentage) / 100.0> (float)current_runtime / (float) current_period) { sandbox_error("CPU usage restricted!\n"); goto err; - } - - if (mem == NULL) { + } + + if (mem == NULL) { if (memusage > current_mem) { sandbox_error("Attempting to use more memory than allowed!"); goto err; } } - + long nprocs = sysconf(_SC_NPROCESSORS_ONLN); - - struct sched_param sp; + + struct sched_param sp; sp.sched_priority = sched_get_priority_min(SCHED_FIFO); sched_setscheduler(getpid(), SCHED_FIFO, &sp); struct cgroup *sandbox_group = cgroup_new_cgroup(cgroupname); cgroup_add_controller(sandbox_group, "memory"); cgroup_add_controller(sandbox_group, "cpu"); - + if (mem == NULL) { if (memusage > 0) { cgroup_set_value_uint64(cgroup_get_controller(sandbox_group, "memory"), "memory.limit_in_bytes", memusage); - } + } } else { cgroup_set_value_string(cgroup_get_controller(sandbox_group, "memory"), "memory.limit_in_bytes", mem); } @@ -470,13 +472,13 @@ static int setup_cgroups() if (cpus != NULL) { cgroup_set_value_string(cgroup_get_controller(sandbox_group, "cpu"), "cgroup.procs",cpus); } - + uint64_t allocated_mem; if (cgroup_get_value_uint64(cgroup_get_controller(sandbox_group, "memory"), "memory.limit_in_bytes", &allocated_mem) > current_mem) { sandbox_error("Attempting to use more memory than allowed!\n"); goto err; } - + rc = cgroup_create_cgroup(sandbox_group, 1); if (rc != 0) { sandbox_error("Failed to create group. Ensure that cgconfig service is running. \n"); @@ -487,13 +489,15 @@ static int setup_cgroups() rc = 0; err: + fclose(fp); + free(str); free(mem); free(cgroupname); free(cpus); return rc; } -/* +/* If path is empy or ends with "/." or "/.. return -1 else return 0; */ static int bad_path(const char *path) { @@ -515,7 +519,7 @@ static int bad_path(const char *path) { return 0; } -static int rsynccmd(const char * src, const char *dst, char **cmdbuf) +static int rsynccmd(const char * src, const char *dst, char **cmdbuf) { char *buf = NULL; char *newbuf = NULL; @@ -559,7 +563,7 @@ static int rsynccmd(const char * src, co newbuf = NULL; } - if (buf) { + if (buf) { if (asprintf(&newbuf, "/usr/bin/rsync -trlHDq %s '%s'", buf, dst) == -1) { fprintf(stderr, "Out of memory\n"); goto err; @@ -674,8 +678,12 @@ static char *create_tmpdir(const char *s if (verify_directory(tmpdir, NULL, out_st) < 0) { goto err; } - if (check_owner_uid(0, tmpdir, out_st) < 0) goto err; - if (check_owner_gid(getgid(), tmpdir, out_st) < 0) goto err; + + if (check_owner_uid(0, tmpdir, out_st) < 0) + goto err; + + if (check_owner_gid(getgid(), tmpdir, out_st) < 0) + goto err; /* change permissions of the temporary directory */ if ((fd_t = open(tmpdir, O_RDONLY)) < 0) { @@ -702,7 +710,7 @@ static char *create_tmpdir(const char *s /* copy selinux context */ if (execcon) { - if (fsetfilecon(fd_t, con) == -1) { + if (fsetfilecon(fd_t, con) == -1) { fprintf(stderr, _("Failed to set context of the directory %s: %s\n"), tmpdir, strerror(errno)); goto err; } @@ -734,12 +742,77 @@ good: return tmpdir; } +#define PROC_BASE "/proc" + +static int +killall (security_context_t execcon) +{ + DIR *dir; + security_context_t scon; + struct dirent *de; + pid_t *pid_table, pid, self; + int i; + int pids, max_pids; + int running = 0; + self = getpid(); + if (!(dir = opendir(PROC_BASE))) { + return -1; + } + max_pids = 256; + pid_table = malloc(max_pids * sizeof (pid_t)); + if (!pid_table) { + (void)closedir(dir); + return -1; + } + pids = 0; + context_t con; + con = context_new(execcon); + const char *mcs = context_range_get(con); + printf("mcs=%s\n", mcs); + while ((de = readdir (dir)) != NULL) { + if (!(pid = (pid_t)atoi(de->d_name)) || pid == self) + continue; + + if (pids == max_pids) { + if (!(pid_table = realloc(pid_table, 2*pids*sizeof(pid_t)))) { + (void)closedir(dir); + return -1; + } + max_pids *= 2; + } + pid_table[pids++] = pid; + } + + (void)closedir(dir); + + for (i = 0; i < pids; i++) { + pid_t id = pid_table[i]; + + if (getpidcon(id, &scon) == 0) { + + context_t pidcon = context_new(scon); + /* Attempt to kill remaining processes */ + if (strcmp(context_range_get(pidcon), mcs) == 0) + kill(id, SIGKILL); + + context_free(pidcon); + freecon(scon); + } + running++; + } + + context_free(con); + free(pid_table); + return running; +} + int main(int argc, char **argv) { int status = -1; security_context_t execcon = NULL; int clflag; /* holds codes for command line flags */ int usecgroups = 0; + int kill_all = 0; char *homedir_s = NULL; /* homedir spec'd by user in argv[] */ char *tmpdir_s = NULL; /* tmpdir spec'd by user in argv[] */ @@ -752,18 +825,21 @@ int main(int argc, char **argv) { const struct option long_options[] = { {"homedir", 1, 0, 'h'}, {"tmpdir", 1, 0, 't'}, + {"kill", 1, 0, 'k'}, {"verbose", 1, 0, 'v'}, {"cgroups", 1, 0, 'c'}, {"context", 1, 0, 'Z'}, + {"capabilities", 1, 0, 'C'}, {NULL, 0, 0, 0} }; uid_t uid = getuid(); - +/* if (!uid) { fprintf(stderr, _("Must not be root")); return -1; } +*/ #ifdef USE_NLS setlocale(LC_ALL, ""); @@ -783,7 +859,7 @@ int main(int argc, char **argv) { } while (1) { - clflag = getopt_long(argc, argv, "cvh:t:Z:", long_options, NULL); + clflag = getopt_long(argc, argv, "Ccvh:t:Z:", long_options, NULL); if (clflag == -1) break; @@ -791,6 +867,9 @@ int main(int argc, char **argv) { case 't': tmpdir_s = optarg; break; + case 'k': + kill_all = 1; + break; case 'h': homedir_s = optarg; break; @@ -800,6 +879,9 @@ int main(int argc, char **argv) { case 'c': usecgroups = 1; break; + case 'C': + cap_set = CAPNG_SELECT_CAPS; + break; case 'Z': execcon = optarg; break; @@ -824,9 +906,11 @@ int main(int argc, char **argv) { return -1; } - if (set_signal_handles()) return -1; + if (set_signal_handles()) + return -1; - if (usecgroups && setup_cgroups() < 0) return -1; + if (usecgroups && setup_cgroups() < 0) + return -1; /* set fsuid to ruid */ /* Changing fsuid is usually required when user-specified directory is @@ -851,7 +935,7 @@ int main(int argc, char **argv) { } /* spawn child process */ - int child = fork(); + child = fork(); if (child == -1) { perror(_("Unable to fork")); goto err; @@ -859,6 +943,7 @@ int main(int argc, char **argv) { if (child == 0) { char *display = NULL; + char *LANG = NULL; int rc = -1; if (unshare(CLONE_NEWNS) < 0) { @@ -866,6 +951,13 @@ int main(int argc, char **argv) { goto childerr; } + /* Remount / as SLAVE so that nothing mounted in the namespace + shows up in the parent */ + if (mount("none", "/", NULL, MS_SLAVE | MS_REC , NULL) < 0) { + perror(_("Failed to make / a SLAVE mountpoint\n")); + goto childerr; + } + /* assume fsuid==ruid after this point */ setfsuid(uid); @@ -884,12 +976,23 @@ int main(int argc, char **argv) { goto childerr; } } + + /* construct a new environment */ + if ((LANG = getenv("LANG")) != NULL) { + if ((LANG = strdup(LANG)) == NULL) { + perror(_("Out of memory")); + goto childerr; + } + } + if ((rc = clearenv()) != 0) { perror(_("Failed to clear environment")); goto childerr; } - if (display) + if (display) rc |= setenv("DISPLAY", display, 1); + if (LANG) + rc |= setenv("LANG", LANG, 1); rc |= setenv("HOME", pwd->pw_dir, 1); rc |= setenv("SHELL", pwd->pw_shell, 1); rc |= setenv("USER", pwd->pw_name, 1); @@ -899,7 +1002,7 @@ int main(int argc, char **argv) { 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); @@ -910,13 +1013,12 @@ int main(int argc, char **argv) { perror(_("Failed to change dir to homedir")); goto childerr; } - setsid(); - execv(argv[optind], argv + optind); fprintf(stderr, _("Failed to execute command %s: %s\n"), argv[optind], strerror(errno)); childerr: free(display); + free(LANG); exit(-1); } @@ -926,10 +1028,15 @@ childerr: waitpid(child, &status, 0); status_to_retval(status, status); + /* Make sure all child processes exit */ + kill(-child,SIGTERM); + + if (execcon && kill_all) + killall(execcon); + if (tmpdir_r) cleanup_tmpdir(tmpdir_r, tmpdir_s, pwd, 1); err: free(tmpdir_r); return status; } -