From 1da0399e2542102fb18416974601063b7b9e2063 Mon Sep 17 00:00:00 2001 From: Dan Walsh Date: Wed, 30 Mar 2011 14:42:36 -0400 Subject: [PATCH] rsynccmd should run outside of execcon --- policycoreutils-gui.patch | 14 +- policycoreutils-rhat.patch | 1214 ++++++++++++++++++++++++------------ policycoreutils.spec | 71 ++- 3 files changed, 873 insertions(+), 426 deletions(-) diff --git a/policycoreutils-gui.patch b/policycoreutils-gui.patch index e8d8904..20b77b0 100644 --- a/policycoreutils-gui.patch +++ b/policycoreutils-gui.patch @@ -12745,7 +12745,7 @@ diff --exclude-from=exclude -N -u -r nsapolicycoreutils/gui/templates/__init__.p + diff --exclude-from=exclude -N -u -r nsapolicycoreutils/gui/templates/network.py policycoreutils-2.0.85/gui/templates/network.py --- nsapolicycoreutils/gui/templates/network.py 1969-12-31 19:00:00.000000000 -0500 -+++ policycoreutils-2.0.85/gui/templates/network.py 2011-02-23 14:40:42.636005375 -0500 ++++ policycoreutils-2.0.85/gui/templates/network.py 2011-03-16 17:00:52.485669534 -0400 @@ -0,0 +1,80 @@ +te_port_types=""" +type TEMPLATETYPE_port_t; @@ -12759,13 +12759,13 @@ diff --exclude-from=exclude -N -u -r nsapolicycoreutils/gui/templates/network.py + +te_tcp="""\ +allow TEMPLATETYPE_t self:tcp_socket create_stream_socket_perms; -+corenet_tcp_sendrecv_all_if(TEMPLATETYPE_t) -+corenet_tcp_sendrecv_all_nodes(TEMPLATETYPE_t) ++corenet_tcp_sendrecv_generic_if(TEMPLATETYPE_t) ++corenet_tcp_sendrecv_generic_node(TEMPLATETYPE_t) +corenet_tcp_sendrecv_all_ports(TEMPLATETYPE_t) +""" + +te_in_tcp="""\ -+corenet_tcp_bind_all_nodes(TEMPLATETYPE_t) ++corenet_tcp_bind_generic_node(TEMPLATETYPE_t) +""" + +te_in_need_port_tcp="""\ @@ -12778,13 +12778,13 @@ diff --exclude-from=exclude -N -u -r nsapolicycoreutils/gui/templates/network.py + +te_udp="""\ +allow TEMPLATETYPE_t self:udp_socket { create_socket_perms listen }; -+corenet_udp_sendrecv_all_if(TEMPLATETYPE_t) -+corenet_udp_sendrecv_all_nodes(TEMPLATETYPE_t) ++corenet_udp_sendrecv_generic_if(TEMPLATETYPE_t) ++corenet_udp_sendrecv_generic_node(TEMPLATETYPE_t) +corenet_udp_sendrecv_all_ports(TEMPLATETYPE_t) +""" + +te_in_udp="""\ -+corenet_udp_bind_all_nodes(TEMPLATETYPE_t) ++corenet_udp_bind_generic_node(TEMPLATETYPE_t) +""" + +te_in_need_port_udp="""\ diff --git a/policycoreutils-rhat.patch b/policycoreutils-rhat.patch index ec8fd42..e49a441 100644 --- a/policycoreutils-rhat.patch +++ b/policycoreutils-rhat.patch @@ -192,7 +192,7 @@ index 6178cc8..b6f386d 100644 .PP .SH AUTHOR diff --git a/policycoreutils/audit2allow/sepolgen-ifgen b/policycoreutils/audit2allow/sepolgen-ifgen -index 03f95a1..5986b23 100644 +index 03f95a1..dad2009 100644 --- a/policycoreutils/audit2allow/sepolgen-ifgen +++ b/policycoreutils/audit2allow/sepolgen-ifgen @@ -1,4 +1,4 @@ @@ -220,11 +220,12 @@ index 03f95a1..5986b23 100644 def parse_options(): from optparse import OptionParser -@@ -44,14 +49,43 @@ def parse_options(): +@@ -44,14 +49,58 @@ def parse_options(): help="filename to store output") parser.add_option("-i", "--interfaces", dest="headers", default=defaults.headers(), help="location of the interface header files") + parser.add_option("-a", "--attribute_info", dest="attribute_info") ++ parser.add_option("-p", "--policy", dest="policy_path") parser.add_option("-v", "--verbose", action="store_true", default=False, help="print debuging output") parser.add_option("-d", "--debug", action="store_true", default=False, @@ -235,9 +236,23 @@ index 03f95a1..5986b23 100644 return options -+def get_attrs(): ++def get_policy(): ++ i = selinux.security_policyvers() ++ p = selinux.selinux_binary_policy_path() + "." + str(i) ++ while i > 0 and not os.path.exists(p): ++ i = i - 1 ++ p = selinux.selinux_binary_policy_path() + "." + str(i) ++ if i > 0: ++ return p ++ return None ++ ++def get_attrs(policy_path): + try: -+ policy_path = selinux.selinux_binary_policy_path() + "." + str(selinux.security_policyvers()) ++ if not policy_path: ++ policy_path = get_policy() ++ if not policy_path: ++ sys.stderr.write("No installed policy to check\n") ++ return None + outfile = tempfile.NamedTemporaryFile() + except IOError, e: + sys.stderr.write("could not open attribute output file\n") @@ -264,14 +279,14 @@ index 03f95a1..5986b23 100644 def main(): options = parse_options() -@@ -68,6 +102,14 @@ def main(): +@@ -68,6 +117,14 @@ def main(): else: log = None + # Get the attibutes from the binary + attrs = None + if not options.no_attrs: -+ attrs = get_attrs() ++ attrs = get_attrs(options.policy_path) + if attrs is None: + return 1 + @@ -279,7 +294,7 @@ index 03f95a1..5986b23 100644 try: headers = refparser.parse_headers(options.headers, output=log, debug=options.debug) except ValueError, e: -@@ -76,7 +118,7 @@ def main(): +@@ -76,7 +133,7 @@ def main(): return 1 if_set = interfaces.InterfaceSet(output=log) @@ -414,7 +429,7 @@ index b149dcb..0c14c94 100644 .SH "SEE ALSO" .BR restorecon (8), diff --git a/policycoreutils/restorecond/restorecond.c b/policycoreutils/restorecond/restorecond.c -index 58774e6..77c8013 100644 +index 58774e6..a588e5e 100644 --- a/policycoreutils/restorecond/restorecond.c +++ b/policycoreutils/restorecond/restorecond.c @@ -30,9 +30,11 @@ @@ -853,7 +868,7 @@ index 58774e6..77c8013 100644 /* Register sighandlers */ sa.sa_flags = 0; -@@ -467,36 +174,56 @@ int main(int argc, char **argv) +@@ -467,36 +174,59 @@ int main(int argc, char **argv) set_matchpathcon_flags(MATCHPATHCON_NOTRANS); @@ -891,6 +906,9 @@ index 58774e6..77c8013 100644 + + uid_t uid = getuid(); + struct passwd *pwd = getpwuid(uid); ++ if (!pwd) ++ exitApp("getpwuid"); ++ + homedir = pwd->pw_dir; + if (uid != 0) { + if (run_as_user) @@ -1022,10 +1040,10 @@ index 0000000..f88a29a + diff --git a/policycoreutils/restorecond/user.c b/policycoreutils/restorecond/user.c new file mode 100644 -index 0000000..272479a +index 0000000..8cf2f20 --- /dev/null +++ b/policycoreutils/restorecond/user.c -@@ -0,0 +1,239 @@ +@@ -0,0 +1,242 @@ +/* + * restorecond + * @@ -1245,12 +1263,12 @@ index 0000000..272479a +#ifdef HAVE_DBUS + if (dbus_server(loop) != 0) +#endif /* HAVE_DBUS */ -+ if (local_server(loop) != 0) -+ return 0; ++ if (local_server(loop)) ++ goto end; + + read_config(master_fd, watch_file); + -+ if (watch_list_isempty()) return 0; ++ if (watch_list_isempty()) goto end; + + set_matchpathcon_flags(MATCHPATHCON_NOTRANS); + @@ -1262,6 +1280,9 @@ index 0000000..272479a + io_channel_callback, NULL, NULL); + + g_main_loop_run (loop); ++ ++end: ++ g_main_loop_unref (loop); + return 0; +} + @@ -1281,7 +1302,7 @@ index f182c22..feddb5a 100644 return changed; diff --git a/policycoreutils/restorecond/watch.c b/policycoreutils/restorecond/watch.c new file mode 100644 -index 0000000..c0caab2 +index 0000000..20a861f --- /dev/null +++ b/policycoreutils/restorecond/watch.c @@ -0,0 +1,270 @@ @@ -1337,7 +1358,7 @@ index 0000000..c0caab2 + char *dir = dirname(x); + ptr = firstDir; + -+ if (exclude(path)) return; ++ if (exclude(path)) goto end; + + globbuf.gl_offs = 1; + if (glob(path, @@ -1357,8 +1378,7 @@ index 0000000..c0caab2 + while (ptr != NULL) { + if (strcmp(dir, ptr->dir) == 0) { + strings_list_add(&ptr->files, file); -+ free(x); -+ return; ++ goto end; + } + prev = ptr; + ptr = ptr->next; @@ -1370,11 +1390,10 @@ index 0000000..c0caab2 + ptr->wd = inotify_add_watch(fd, dir, IN_CREATE | IN_MOVED_TO); + if (ptr->wd == -1) { + free(ptr); -+ free(x); + if (! run_as_user) + syslog(LOG_ERR, "Unable to watch (%s) %s\n", + path, strerror(errno)); -+ return; ++ goto end; + } + + ptr->dir = strdup(dir); @@ -1390,7 +1409,9 @@ index 0000000..c0caab2 + if (debug_mode) + printf("%d: Dir=%s, File=%s\n", ptr->wd, ptr->dir, file); + ++end: + free(x); ++ return; +} + +/* @@ -1621,7 +1642,7 @@ index ff0ee7c..0c8a085 100644 test: @python test_sandbox.py -v diff --git a/policycoreutils/sandbox/sandbox b/policycoreutils/sandbox/sandbox -index 48a26c2..79cbb2d 100644 +index 48a26c2..29c99ed 100644 --- a/policycoreutils/sandbox/sandbox +++ b/policycoreutils/sandbox/sandbox @@ -1,5 +1,6 @@ @@ -1632,7 +1653,7 @@ index 48a26c2..79cbb2d 100644 # Authors: Josh Cogliati # # Copyright (C) 2009,2010 Red Hat -@@ -19,15 +20,18 @@ +@@ -19,15 +20,17 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # @@ -1646,14 +1667,14 @@ index 48a26c2..79cbb2d 100644 +import setools PROGNAME = "policycoreutils" - HOMEDIR=pwd.getpwuid(os.getuid()).pw_dir +-HOMEDIR=pwd.getpwuid(os.getuid()).pw_dir - +SEUNSHARE = "/usr/sbin/seunshare" +SANDBOXSH = "/usr/share/sandbox/sandboxX.sh" import gettext gettext.bindtextdomain(PROGNAME, "/usr/share/locale") gettext.textdomain(PROGNAME) -@@ -41,6 +45,7 @@ except IOError: +@@ -41,6 +44,7 @@ except IOError: import __builtin__ __builtin__.__dict__['_'] = unicode @@ -1661,7 +1682,7 @@ index 48a26c2..79cbb2d 100644 DEFAULT_TYPE = "sandbox_t" DEFAULT_X_TYPE = "sandbox_x_t" SAVE_FILES = {} -@@ -63,15 +68,15 @@ def error_exit(msg): +@@ -63,15 +67,15 @@ def error_exit(msg): sys.stderr.flush() sys.exit(1) @@ -1681,7 +1702,7 @@ index 48a26c2..79cbb2d 100644 if not os.path.exists(newdir): os.makedirs(newdir) dest = newdir + "/" + bname -@@ -81,9 +86,10 @@ def copyfile(file, dir, dest): +@@ -81,9 +85,10 @@ def copyfile(file, dir, dest): shutil.copytree(file, dest) else: shutil.copy2(file, dest) @@ -1694,14 +1715,9 @@ index 48a26c2..79cbb2d 100644 SAVE_FILES[file] = (dest, os.path.getmtime(dest)) -@@ -158,13 +164,13 @@ class Sandbox: - - def __validate_mount(self): - if self.__options.level: -- if not self.__options.homedir or not self.__options.tmpdir: -- self.usage(_("Homedir and tempdir required for level mounts")) -+ if not self.__options.homedir: -+ self.usage(_("Homedir required for level mounts")) +@@ -161,10 +166,10 @@ class Sandbox: + if not self.__options.homedir or not self.__options.tmpdir: + self.usage(_("Homedir and tempdir required for level mounts")) - if not os.path.exists("/usr/sbin/seunshare"): + if not os.path.exists(SEUNSHARE): @@ -1713,7 +1729,7 @@ index 48a26c2..79cbb2d 100644 def __mount_callback(self, option, opt, value, parser): self.__mount = True -@@ -172,6 +178,15 @@ class Sandbox: +@@ -172,6 +177,15 @@ class Sandbox: def __x_callback(self, option, opt, value, parser): self.__mount = True setattr(parser.values, option.dest, True) @@ -1729,7 +1745,7 @@ index 48a26c2..79cbb2d 100644 def __validdir(self, option, opt, value, parser): if not os.path.isdir(value): -@@ -194,6 +209,8 @@ class Sandbox: +@@ -194,6 +208,8 @@ class Sandbox: self.__include(option, opt, i[:-1], parser) except IOError, e: sys.stderr.write(str(e)) @@ -1738,7 +1754,7 @@ index 48a26c2..79cbb2d 100644 fd.close() def __copyfiles(self): -@@ -212,13 +229,15 @@ class Sandbox: +@@ -212,13 +228,15 @@ class Sandbox: /etc/gdm/Xsession """) else: @@ -1756,7 +1772,7 @@ index 48a26c2..79cbb2d 100644 kill -TERM $WM_PID 2> /dev/null """ % (command, wm, command)) fd.close() -@@ -226,14 +245,25 @@ kill -TERM $WM_PID 2> /dev/null +@@ -226,14 +244,25 @@ kill -TERM $WM_PID 2> /dev/null def usage(self, message = ""): error_exit("%s\n%s" % (self.__parser.usage, message)) @@ -1775,9 +1791,9 @@ index 48a26c2..79cbb2d 100644 + usage = _(""" -sandbox [-h] [-[X|M] [-l level ] [-H homedir] [-T tempdir]] [-I includefile ] [-W windowmanager ] [[-i file ] ...] [ -t type ] command -+sandbox [-h] [-l level ] [-[X|M] [-H homedir] ] [-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 ] command + -+sandbox [-h] [-l level ] [-[X|M] [-H homedir] ] [-I includefile ] [-W windowmanager ] [ -w windowsize ] [[-i file ] ...] [ -t type ] -S ++sandbox [-h] [-l level ] [-[X|M] [-H homedir] [-T tempdir]] [-I includefile ] [-W windowmanager ] [ -w windowsize ] [[-i file ] ...] [ -t type ] -S +%s +""") % types @@ -1786,21 +1802,18 @@ index 48a26c2..79cbb2d 100644 parser = OptionParser(version=self.VERSION, usage=usage) parser.disable_interspersed_args() -@@ -263,10 +293,9 @@ sandbox [-h] [-[X|M] [-l level ] [-H homedir] [-T tempdir]] [-I includefile ] [- - dest="homedir", - help=_("alternate home directory to use for mounting")) +@@ -268,6 +297,10 @@ sandbox [-h] [-[X|M] [-l level ] [-H homedir] [-T tempdir]] [-I includefile ] [- + action="callback", callback=self.__validdir, + help=_("alternate /tmp directory to use for mounting")) -- 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") - ++ parser.add_option("-W", "--windowmanager", dest="wm", type="string", -@@ -276,13 +305,17 @@ sandbox [-h] [-[X|M] [-l level ] [-H homedir] [-T tempdir]] [-I includefile ] [- + default="/usr/bin/matchbox-window-manager -use_titlebar no", +@@ -276,13 +309,17 @@ sandbox [-h] [-[X|M] [-l level ] [-H homedir] [-T tempdir]] [-I includefile ] [- parser.add_option("-l", "--level", dest="level", help=_("MCS/MLS level for the sandbox")) @@ -1819,50 +1832,40 @@ index 48a26c2..79cbb2d 100644 if self.__options.setype: self.setype = self.__options.setype -@@ -292,13 +325,14 @@ sandbox [-h] [-[X|M] [-l level ] [-H homedir] [-T tempdir]] [-I includefile ] [- - if self.__options.session: - if not self.__options.setype: - self.setype = selinux.getcon()[1].split(":")[2] -- if not self.__options.homedir or not self.__options.tmpdir: -- self.usage(_("You must specify a Homedir and tempdir when setting up a session sandbox")) -+ if not self.__options.homedir: -+ self.usage(_("You must specify a Homedir when setting up a session sandbox")) - if len(cmds) > 0: - self.usage(_("Commands are not allowed in a session sandbox")) - self.__options.X_ind = True +@@ -300,6 +337,10 @@ sandbox [-h] [-[X|M] [-l level ] [-H homedir] [-T tempdir]] [-I includefile ] [- self.__homedir = self.__options.homedir -- self.__tmpdir = self.__options.tmpdir -+ elif self.__options.level: -+ self.__homedir = self.__options.homedir + self.__tmpdir = self.__options.tmpdir else: ++ if self.__options.level: ++ self.__homedir = self.__options.homedir ++ self.__tmpdir = self.__options.tmpdir ++ if len(cmds) == 0: self.usage(_("Command required")) -@@ -323,9 +357,8 @@ sandbox [-h] [-[X|M] [-l level ] [-H homedir] [-T tempdir]] [-I includefile ] [- - - 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], -- level) -+ self.__filecon = "%s:object_r:sandbox_file_t:%s" % (con[0],level) -+ + cmds[0] = fullpath(cmds[0]) +@@ -329,44 +370,43 @@ sandbox [-h] [-[X|M] [-l level ] [-H homedir] [-T tempdir]] [-I includefile ] [- def __setup_dir(self): if self.__options.level or self.__options.session: return -@@ -339,34 +372,33 @@ sandbox [-h] [-[X|M] [-l level ] [-H homedir] [-T tempdir]] [-I includefile ] [- +- sandboxdir = HOMEDIR + "/.sandbox" +- if not os.path.exists(sandboxdir): +- os.mkdir(sandboxdir) + + if self.__options.homedir: + selinux.chcon(self.__options.homedir, self.__filecon, recursive=True) + self.__homedir = self.__options.homedir else: selinux.setfscreatecon(self.__filecon) - self.__homedir = mkdtemp(dir=sandboxdir, prefix=".sandbox") -+ self.__tmpdir = self.__homedir + "/.sandboxtmp"; -+ if not os.path.exists(self.__tmpdir): -+ os.makedirs(self.__tmpdir) +- self.__homedir = mkdtemp(dir=sandboxdir, prefix=".sandbox") ++ self.__homedir = mkdtemp(dir="/tmp", prefix=".sandbox_home_") -- if self.__options.tmpdir: -- selinux.chcon(self.__options.tmpdir, self.__filecon, recursive=True) -- self.__tmpdir = self.__options.tmpdir -- else: -- selinux.setfscreatecon(self.__filecon) + if self.__options.tmpdir: + selinux.chcon(self.__options.tmpdir, self.__filecon, recursive=True) + self.__tmpdir = self.__options.tmpdir + else: + selinux.setfscreatecon(self.__filecon) - self.__tmpdir = mkdtemp(dir="/tmp", prefix=".sandbox") ++ self.__tmpdir = mkdtemp(dir="/tmp", prefix=".sandbox_tmp_") selinux.setfscreatecon(None) self.__copyfiles() @@ -1887,7 +1890,7 @@ index 48a26c2..79cbb2d 100644 - cmds = [ '/usr/sbin/seunshare', "-t", self.__tmpdir, "-h", self.__homedir, "--", self.__execcon ] + self.__paths - rc = subprocess.Popen(cmds).wait() - return rc -+ cmds += [ "-h", self.__homedir ] ++ cmds += [ "-t", self.__tmpdir, "-h", self.__homedir ] + + if self.__options.X_ind: + xmodmapfile = self.__homedir + "/.xmodmap" @@ -1904,17 +1907,7 @@ index 48a26c2..79cbb2d 100644 selinux.setexeccon(self.__execcon) rc = subprocess.Popen(self.__cmds).wait() -@@ -383,8 +415,7 @@ sandbox [-h] [-[X|M] [-l level ] [-H homedir] [-T tempdir]] [-I includefile ] [- - - if self.__homedir and not self.__options.homedir: - shutil.rmtree(self.__homedir) -- if self.__tmpdir and not self.__options.tmpdir: -- shutil.rmtree(self.__tmpdir) -+ - def main(self): - try: - self.__parse_options() -@@ -404,7 +435,7 @@ if __name__ == '__main__': +@@ -404,7 +444,7 @@ if __name__ == '__main__': sandbox = Sandbox() rc = sandbox.main() except OSError, error: @@ -1924,7 +1917,7 @@ index 48a26c2..79cbb2d 100644 error_exit(error.args[0]) except KeyError, error: diff --git a/policycoreutils/sandbox/sandbox.8 b/policycoreutils/sandbox/sandbox.8 -index 1479364..7b4318a 100644 +index 1479364..73d33b3 100644 --- a/policycoreutils/sandbox/sandbox.8 +++ b/policycoreutils/sandbox/sandbox.8 @@ -1,10 +1,13 @@ @@ -1936,43 +1929,28 @@ index 1479364..7b4318a 100644 .B sandbox -[-l level ] [[-M | -X] -H homedir -T tempdir ] [-I includefile ] [ -W windowmanager ] [[-i file ]...] [ -t type ] cmd -[-l level ] [[-M | -X] -H homedir -T tempdir ] [-I includefile ] [ -W windowmanager ] [[-i file ]...] [ -t type ] -S -+[-l level ] [[-M | -X] -H homedir ] [-I includefile ] [ -W windowmanager ] [ -w windowsize ] [[-i file ]...] [ -t type ] cmd ++[-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 ] [-I includefile ] [ -W windowmanager ] [ -w windowsize ] [[-i file ]...] [ -t type ] -S ++[-l level ] [[-M | -X] -H homedir -T tempdir ] [-I includefile ] [ -W windowmanager ] [ -w windowsize ] [[-i file ]...] [ -t type ] -S .br .SH DESCRIPTION .PP -@@ -18,11 +21,11 @@ package installed, you can use the -X option and the -M option. - .B sandbox -X - allows you to run X applications within a sandbox. These applications will start up their own X Server and create a temporary home directory and /tmp. The default SELinux policy does not allow any capabilities or network access. It also prevents all access to the users other processes and files. Files specified on the command that are in the home directory or /tmp will be copied into the sandbox directories. - --If directories are specified with -H or -T the directory will have its context modified with chcon(1) unless a level is specified with -l. If the MLS/MCS security level is specified, the user is responsible to set the correct labels. -+If directories are specified with -H option the directory will have its context modified with chcon(1) unless a level is specified with -l. If the MLS/MCS security level is specified, the user is responsible to set the correct labels. - .PP +@@ -42,6 +45,12 @@ Use alternate sandbox type, defaults to sandbox_t or sandbox_x_t for -X. + \fB\-T\ tmpdir + Use alternate tempory directory to mount on /tmp. Defaults to tmpfs. Requires -X or -M. .TP - \fB\-H\ homedir --Use alternate homedir to mount over your home directory. Defaults to temporary. Requires -X or -M. -+Use alternate homedir to mount over your home directory. The /tmp dir will be prepopulated from homedir/.sandboxtmp directory if it exists. Defaults to temporary. Requires -X or -M. - .TP - \fB\-i file\fR - Copy this file into the appropriate temporary sandbox directory. Command can be repeated. -@@ -39,8 +42,11 @@ Create a Sandbox with temporary files for $HOME and /tmp. - \fB\-t type\fR - Use alternate sandbox type, defaults to sandbox_t or sandbox_x_t for -X. - .TP --\fB\-T\ tmpdir --Use alternate tempory directory to mount on /tmp. Defaults to tmpfs. Requires -X or -M. +\fB\-S +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. - .TP ++.TP \fB\-W windowmanager\fR Select alternative window manager to run within -@@ -50,8 +56,17 @@ Default to /usr/bin/matchbox-window-manager. + .B sandbox -X. +@@ -50,8 +59,17 @@ Default to /usr/bin/matchbox-window-manager. \fB\-X\fR Create an X based Sandbox for gui apps, temporary files for $HOME and /tmp, secondary Xserver, defaults to sandbox_x_t @@ -2105,29 +2083,31 @@ index 8338203..e501b03 100644 break diff --git a/policycoreutils/sandbox/seunshare.8 b/policycoreutils/sandbox/seunshare.8 new file mode 100644 -index 0000000..bab85d2 +index 0000000..e7b8991 --- /dev/null +++ b/policycoreutils/sandbox/seunshare.8 -@@ -0,0 +1,35 @@ +@@ -0,0 +1,37 @@ +.TH SEUNSHARE "8" "May 2010" "seunshare" "User Commands" +.SH NAME +seunshare \- Run cmd with alternate homedir, tmpdir and/or SELinux context +.SH SYNOPSIS +.B seunshare -+[ -v ] [ -c ] [ -Z context ] -h homedir -- executable [args] ++[ -v ] [ -t tmpdir ] [ -h homedir ] [ -Z context ] -- executable [args] +.br +.SH DESCRIPTION +.PP +Run the +.I executable -+within the specified context, using the alternate home directory. The seunshare command unshares from the default namespace, then mounts the specified homedir over the default homedir. It also mounts a tmpfs files system on /tmp and /var/tmp over /tmp, populated from the .sandboxtmp directory in the specified homedir. Finally it tells the kernel to execute the application under the specified SELinux context. ++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. + +.TP +\fB\-h homedir\fR -+Alternate homedir to be used by the application. Homedir must be owned by the user. tmpdir will be populated from .sandboxdir within homedir if it exists. ++Alternate homedir to be used by the application. Homedir must be owned by the user. +.TP -+ -+\fB\-c\fR ++\fB\-t\ tmpdir ++Use alternate tempory directory to mount on /tmp. tmpdir must be owned by the user. ++.TP ++\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\-Z\ context @@ -2145,10 +2125,10 @@ index 0000000..bab85d2 +and +.I Thomas Liu diff --git a/policycoreutils/sandbox/seunshare.c b/policycoreutils/sandbox/seunshare.c -index ec692e7..f2325ba 100644 +index ec692e7..49dad71 100644 --- a/policycoreutils/sandbox/seunshare.c +++ b/policycoreutils/sandbox/seunshare.c -@@ -1,28 +1,34 @@ +@@ -1,28 +1,35 @@ +/* + * Authors: Dan Walsh + * Authors: Thomas Liu @@ -2161,6 +2141,7 @@ index ec692e7..f2325ba 100644 #include #include #include ++#include #include -#define _GNU_SOURCE #include @@ -2188,7 +2169,7 @@ index ec692e7..f2325ba 100644 #ifdef USE_NLS #include /* for setlocale() */ #include /* for gettext() */ -@@ -39,6 +45,12 @@ +@@ -39,29 +46,47 @@ #define MS_PRIVATE 1<<18 #endif @@ -2197,88 +2178,227 @@ index ec692e7..f2325ba 100644 +#endif + +#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]") ++ ++static int verbose = 0; ++ + /** - * This function will drop all capabilities - * Returns zero on success, non-zero otherwise -@@ -46,9 +58,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() { ++ if (capng_have_capabilities(CAPNG_SELECT_BOTH) == CAPNG_NONE) ++ return 0; 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; -+ - /* Change uid */ - if (setresuid(uid, uid, uid)) { - fprintf(stderr, _("Error changing uid, aborting.\n")); -@@ -90,18 +102,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. + } +- 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 verify_mount(const char *mntdir, struct passwd *pwd) { -+ int rc = -1; + static int set_signal_handles(void) + { +@@ -75,8 +100,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 +109,103 @@ 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); ++ } ++ ++ waitpid(child, &status, 0); ++ status_to_retval(status, status); ++ return status; ++} ++ ++/** ++ * Check file/directory ownership, struct stat * must be passed to the ++ * functions. ++ */ ++static int check_owner_uid(uid_t uid, const char *file, struct stat *st) { ++ if (S_ISLNK(st->st_mode)) { ++ fprintf(stderr, _("Error: %s must not be a symbolic link\n"), file); ++ return -1; ++ } ++ if (st->st_uid != uid) { ++ fprintf(stderr, _("Error: %s not owned by UID %d\n"), file, uid); ++ return -1; ++ } ++ return 0; ++} ++ ++static int check_owner_gid(gid_t gid, const char *file, struct stat *st) { ++ if (S_ISLNK(st->st_mode)) { ++ fprintf(stderr, _("Error: %s must not be a symbolic link\n"), file); ++ return -1; ++ } ++ if (st->st_gid != gid) { ++ fprintf(stderr, _("Error: %s not owned by GID %d\n"), file, gid); ++ return -1; ++ } ++ return 0; ++} ++ ++#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) ++ + /** +- * 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. ++ * 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_mount(const char *mntdir, struct passwd *pwd) { ++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 ) { -+ fprintf(stderr, _("Invalid mount point %s, you can not mount from the /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 (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(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; +- syslog(LOG_AUTHPRIV | LOG_ALERT, "%s attempted to mount an invalid directory, %s", pwd->pw_name, mntdir); +- perror(_("Invalid mount point, reporting to administrator")); ++ if (st_in && !equal_stats(st_in, st_out)) { ++ fprintf(stderr, _("Error: %s was replaced by a different directory\n"), dir); + return -1; + } + -+ if (fstat(fd, &sb) == -1) { -+ fprintf(stderr, _("Invalid mount point: can not stat %s: %s\n"), mntdir, strerror(errno)); -+ goto err; -+ } -+ if (! S_ISDIR(sb.st_mode)) { -+ fprintf(stderr, _("Invalid mount point: %s is not a directory: %s\n"), mntdir, strerror(errno)); -+ goto err; - } - 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; -+ goto err; - } -- return 0; -+ rc = 0; -+err: -+ close(fd); -+ return rc; + return 0; } - /** -@@ -131,45 +162,317 @@ static int verify_shell(const char *shell_name) +@@ -123,7 +228,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 +236,525 @@ 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) { -+ -+ const char *dst = pwd->pw_dir; - if (verbose) - printf("Mount %s on %s\n", src, dst); -- if (mount(dst, dst, NULL, MS_BIND | MS_REC, NULL) < 0) { -+ ++/** ++ * 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; ++ + if (verbose) +- 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); ++ ++ 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)); @@ -2286,104 +2406,47 @@ index ec692e7..f2325ba 100644 } - if (verify_mount(dst, pwd) < 0) -+ if (verify_mount(dst, pwd) < 0) - return -1; ++ /* verify whether we mounted what we expected to mount */ ++ if (verify_directory(dst, src_st, NULL) < 0) return -1; ++ ++ /* bind mount /tmp on /var/tmp too */ ++ if (is_tmp) { ++ 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; ++ } ++ } + + return 0; ++ +} + -+static char *seunshare_mount_tmp(const char *srcdir) { -+ -+ char * tmpdir = NULL; -+ int rc = -1; -+ if (verbose) -+ printf("Mount tmpfs on /tmp\n"); -+ -+ 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; -+ } -+ -+ if (mount("/var/tmp", "/var/tmp", NULL, MS_PRIVATE | flags, NULL) < 0) { -+ fprintf(stderr, _("Failed to make /tmp private: %s\n"), strerror(errno)); -+ goto err; -+ } -+ -+ if (seteuid(0)) { -+ fprintf(stderr, _("Error changing uid, aborting.\n")); -+ goto err; -+ } -+ if (setegid(0)) { -+ fprintf(stderr, _("Error changing gid, aborting.\n")); -+ goto err; -+ } -+ char template[] = "/tmp/.sandboxXXXXXX"; -+ tmpdir = mkdtemp(template); -+ if (! tmpdir) { -+ fprintf(stderr, _("Failed to make temporary directory: %s\n"), strerror(errno)); -+ goto err; -+ } -+ -+ 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("/tmp", "/var/tmp", NULL, MS_BIND | flags, NULL) < 0) { -+ fprintf(stderr, _("Failed to mount /tmp on /var/tmp: %s\n"), strerror(errno)); -+ goto err; -+ } -+ -+ if (chmod("/tmp/dan", strtol("1777",0,8))) { -+ fprintf(stderr, _("Unable to change mode on /tmp, aborting.\n")); -+ goto err; -+ } -+ -+ if (is_selinux_enabled() > 0) { -+ 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)); -+ freecon(filecon); -+ goto err; -+ } -+ freecon(filecon); -+ } -+ -+ rc = 0; -+err: -+ if (rc < 0) { -+ unlink(tmpdir); -+ return NULL; -+ } -+ return tmpdir; - } - --#define USAGE_STRING _("USAGE: seunshare [ -v ] [ -t tmpdir ] [ -h homedir ] -- CONTEXT executable [args] ") -+#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) { @@ -2397,7 +2460,11 @@ index ec692e7..f2325ba 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 */ @@ -2406,12 +2473,12 @@ index ec692e7..f2325ba 100644 + FILE* fp; + char buf[BUF_SIZE]; + char *tok = NULL; -+ ++ int rc = -1; + const char* fname = "/etc/sysconfig/sandbox"; + + if ((fp = fopen(fname, "rt")) == NULL) { + fprintf(stderr, "Error opening sandbox config file."); -+ return -1; ++ return rc; + } + while(fgets(buf, BUF_SIZE, fp) != NULL) { + /* Skip comments */ @@ -2438,6 +2505,7 @@ index ec692e7..f2325ba 100644 + tok = strtok(NULL, "=\n"); + cpus = strdup(tok); + if (!strcmp(cpus, "ALL")) { ++ free(cpus); + cpus = NULL; + } + } else if (!strcmp(tok, "MEMUSAGE")) { @@ -2452,7 +2520,7 @@ index ec692e7..f2325ba 100644 + } + } else { + fprintf(stderr, "Error parsing config file."); -+ return -1; ++ goto err; + } + + } else if (!strcmp(tok, "CPUUSAGE")) { @@ -2463,7 +2531,7 @@ index ec692e7..f2325ba 100644 + cpupercentage = atoi(tok); + } else { + fprintf(stderr, "Error parsing config file."); -+ return -1; ++ goto err; + } + } else if (!strcmp(tok, "NAME")) { + tok = strtok(NULL, "=\n"); @@ -2508,13 +2576,13 @@ index ec692e7..f2325ba 100644 + + if (((float) cpupercentage) / 100.0> (float)current_runtime / (float) current_period) { + sandbox_error("CPU usage restricted!\n"); -+ return -1; ++ goto err; + } + + if (mem == NULL) { + if (memusage > current_mem) { + sandbox_error("Attempting to use more memory than allowed!"); -+ return -1; ++ goto err; + } + } + @@ -2546,44 +2614,297 @@ index ec692e7..f2325ba 100644 + 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"); -+ return -1; ++ goto err; + } + -+ int r = cgroup_create_cgroup(sandbox_group, 1); -+ if (r != 0) { ++ rc = cgroup_create_cgroup(sandbox_group, 1); ++ if (rc != 0) { + sandbox_error("Failed to create group. Ensure that cgconfig service is running. \n"); -+ return -1; ++ goto err; + } + + cgroup_attach_task(sandbox_group); ++ ++ rc = 0; ++err: ++ 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) { ++ const char *ptr; ++ ptr = path; ++ while (*ptr) ptr++; ++ if (ptr == path) return -1; // ptr null ++ ptr--; ++ if (ptr != path && *ptr == '.') { ++ ptr--; ++ if (*ptr == '/') return -1; // path ends in /. ++ if (*ptr == '.') { ++ if (ptr != path) { ++ ptr--; ++ if (*ptr == '/') return -1; // path ends in /.. ++ } ++ } ++ } + return 0; ++} ++ ++static int rsynccmd(const char * src, const char *dst, char **cmdbuf) ++{ ++ char *buf = NULL; ++ char *newbuf = NULL; ++ glob_t fglob; ++ fglob.gl_offs = 0; ++ int flags = GLOB_PERIOD; ++ unsigned int i = 0; ++ int rc = -1; ++ ++ /* match glob for all files in src dir */ ++ if (asprintf(&buf, "%s/*", src) == -1) { ++ fprintf(stderr, "Out of memory\n"); ++ return -1; ++ } ++ ++ if (glob(buf, flags, NULL, &fglob) != 0) { ++ free(buf); buf = NULL; + return -1; ++ } ++ ++ free(buf); buf = NULL; ++ ++ for ( i=0; i < fglob.gl_pathc; i++) { ++ const char *path = fglob.gl_pathv[i]; ++ ++ if (bad_path(path)) continue; ++ ++ if (!buf) { ++ if (asprintf(&newbuf, "\'%s\'", path) == -1) { ++ fprintf(stderr, "Out of memory\n"); ++ goto err; ++ } ++ } else { ++ if (asprintf(&newbuf, "%s \'%s\'", buf, path) == -1) { ++ fprintf(stderr, "Out of memory\n"); ++ goto err; ++ } ++ } ++ ++ free(buf); buf = newbuf; ++ newbuf = NULL; ++ } ++ ++ if (buf) { ++ if (asprintf(&newbuf, "/usr/bin/rsync -trlHDq %s '%s'", buf, dst) == -1) { ++ fprintf(stderr, "Out of memory\n"); ++ goto err; ++ } ++ *cmdbuf=newbuf; ++ } ++ else { ++ *cmdbuf=NULL; ++ } ++ rc = 0; ++ ++err: ++ free(buf); buf = NULL; ++ globfree(&fglob); ++ 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; ++ } ++ ++ /* 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; ++ ++ /* 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); ++ ++ return 0; ++} ++ ++/** ++ * 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; ++ ++ /* get selinux context */ ++ if (execcon) { ++ setfsuid(pwd->pw_uid); ++ 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; ++ } ++ ++ /* ok to not reach this if there is an error */ ++ 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; ++ } ++ ++ /* temporary directory must be owned by root:user */ ++ 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; ++ ++ /* 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; ++ } ++ ++ /* copy selinux context */ ++ 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; ++ } ++ } ++ ++ setfsuid(pwd->pw_uid); ++ ++ if (rsynccmd(src, tmpdir, &cmdbuf) < 0) { ++ goto err; ++ } ++ ++ /* ok to not reach this if there is an error */ ++ setfsuid(0); ++ ++ if (cmdbuf && 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); con = NULL; ++ if (fd_t >= 0) close(fd_t); ++ if (fd_s >= 0) close(fd_s); ++ return tmpdir; +} int main(int argc, char **argv) { - int rc; -+ int rc = -1; int status = -1; -- -- security_context_t scontext; + security_context_t execcon = NULL; -+ char *tmpdir = 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 +483,12 @@ int main(int argc, char **argv) { +@@ -180,6 +765,12 @@ int main(int argc, char **argv) { return -1; } @@ -2596,24 +2917,31 @@ index ec692e7..f2325ba 100644 struct passwd *pwd=getpwuid(uid); if (!pwd) { perror(_("getpwduid failed")); -@@ -192,76 +501,88 @@ int main(int argc, char **argv) { +@@ -187,34 +778,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)); @@ -2624,25 +2952,24 @@ index ec692e7..f2325ba 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 +810,84 @@ 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; } @@ -2650,31 +2977,19 @@ index ec692e7..f2325ba 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 (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; } @@ -2690,78 +3005,146 @@ index ec692e7..f2325ba 100644 - if (tmpdir_s && seunshare_mount(tmpdir_s, "/tmp", pwd) < 0) - return -1; - } -+ if ((tmpdir = seunshare_mount_tmp(homedir_s)) == NULL) return -1; +- +- if (drop_capabilities(uid)) { +- perror(_("Failed to drop all capabilities")); ++ if (set_signal_handles()) return -1; + -+ /* you must mount the homedir first, since the tmpdir will use -+ the file context from the homedir to set its label*/ -+ if (seunshare_mount_home(homedir_s, pwd) < 0) return -1; - - if (drop_capabilities(uid)) { - perror(_("Failed to drop all capabilities")); ++ if (usecgroups && setup_cgroups() < 0) return -1; ++ ++ /* set fsuid to ruid */ ++ /* Changing fsuid is usually required when user-specified directory is ++ * on an NFS mount. It's also desired to avoid leaking info about ++ * existence of the files not accessible to the user. */ ++ 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; ++ setfsuid(0); ++ ++ /* 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; } -+ /* Since we have dropped capabilities and we have reset the UID, -+ the system call below should be safe */ -+ char *cpbuf=NULL; -+ if (asprintf(&cpbuf, "/bin/cp -RTp %s/.sandboxtmp /tmp 2> /dev/null", pwd->pw_dir) < 0) { -+ fprintf(stderr, _("Failed to allocate copy command: %s\n"), strerror(errno)); -+ return -1; -+ } -+ -+ rc = system(cpbuf); -+ free(cpbuf); -+ if (rc < 0) { -+ fprintf(stderr, _("Failed to copy %s to /tmp: %s\n"), tmpdir_s, strerror(errno)); -+ return -1; -+ } -+ ++ /* spawn child process */ int child = fork(); if (child == -1) { perror(_("Unable to fork")); -@@ -286,11 +607,15 @@ int main(int argc, char **argv) { - exit(-1); +- return -1; ++ goto err; + } + +- 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); ++ /* assume fsuid==ruid after this point */ ++ 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 +630,16 @@ int main(int argc, char **argv) { - perror(_("Failed to change dir to homedir")); - exit(-1); - } -- setsid(); - execv(argv[optind], argv + optind); - free(display); - perror("execv"); - exit(-1); - } else { - waitpid(child, &status, 0); -+ rc = system("rm -rf /tmp"); -+ if (rc < 0) { -+ fprintf(stderr, _("Failed to cleanup /tmp: %s\n"), strerror(errno)); -+ } - } - + if (display) + rc |= setenv("DISPLAY", display, 1); + rc |= setenv("HOME", pwd->pw_dir, 1); +@@ -300,22 +895,41 @@ 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); ++ 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"); + exit(-1); +- } else { +- waitpid(child, &status, 0); + } + - free(tmpdir_s); - free(homedir_s); -- ++ drop_caps(); + ++ /* 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 @@ -3833,7 +4216,7 @@ index 70d1a20..fb6a79b 100644 +.br Examples by Thomas Bleher . diff --git a/policycoreutils/semanage/seobject.py b/policycoreutils/semanage/seobject.py -index b7d257b..d5920aa 100644 +index b7d257b..4462c9e 100644 --- a/policycoreutils/semanage/seobject.py +++ b/policycoreutils/semanage/seobject.py @@ -25,51 +25,17 @@ import pwd, grp, string, selinux, tempfile, os, re, sys, stat @@ -4215,18 +4598,18 @@ index b7d257b..d5920aa 100644 def list(self, heading = 1, locallist = 0): if heading: print "%-30s %-8s %s\n" % (_("SELinux Port Type"), _("Proto"), _("Port Number")) -@@ -958,21 +1094,35 @@ class portRecords(semanageRecords): +@@ -958,21 +1094,36 @@ class portRecords(semanageRecords): class nodeRecords(semanageRecords): def __init__(self, store = ""): semanageRecords.__init__(self,store) -- -- def __add(self, addr, mask, proto, serange, ctype): + self.protocol = ["ipv4", "ipv6"] + + def validate(self, addr, mask, protocol): -+ newaddr="" -+ newmask="" ++ newaddr=addr ++ newmask=mask + newprotocol="" + +- def __add(self, addr, mask, proto, serange, ctype): if addr == "": raise ValueError(_("Node Address is required")) @@ -4241,14 +4624,14 @@ index b7d257b..d5920aa 100644 + # verify valid comination + if len(mask) == 0 or mask[0] == "/": + i = IP(addr + mask) -+ else: -+ i = IP(addr + "/" + mask) -+ newaddr = i.strNormal(0) -+ newmask = str(i.netmask()) -+ if protocol == "": ++ newaddr = i.strNormal(0) ++ newmask = str(i.netmask()) ++ if newmask == "0.0.0.0" and i.version() == 6: ++ newmask = "::" ++ + protocol = "ipv%d" % i.version() -+ -+ try: ++ ++ try: + newprotocol = self.protocol.index(protocol) + except: raise ValueError(_("Unknown or missing protocol")) @@ -4261,7 +4644,7 @@ index b7d257b..d5920aa 100644 if is_mls_enabled == 1: if serange == "": -@@ -991,11 +1141,13 @@ class nodeRecords(semanageRecords): +@@ -991,11 +1142,13 @@ class nodeRecords(semanageRecords): (rc, exists) = semanage_node_exists(self.sh, k) if exists: @@ -4276,7 +4659,7 @@ index b7d257b..d5920aa 100644 rc = semanage_node_set_addr(self.sh, node, proto, addr) (rc, con) = semanage_context_create(self.sh) -@@ -1005,8 +1157,7 @@ class nodeRecords(semanageRecords): +@@ -1005,8 +1158,7 @@ class nodeRecords(semanageRecords): rc = semanage_node_set_mask(self.sh, node, proto, mask) if rc < 0: raise ValueError(_("Could not set mask for %s") % addr) @@ -4286,7 +4669,7 @@ index b7d257b..d5920aa 100644 rc = semanage_context_set_user(self.sh, con, "system_u") if rc < 0: raise ValueError(_("Could not set user in addr context for %s") % addr) -@@ -1042,18 +1193,8 @@ class nodeRecords(semanageRecords): +@@ -1042,18 +1194,8 @@ class nodeRecords(semanageRecords): self.commit() def __modify(self, addr, mask, proto, serange, setype): @@ -4306,7 +4689,7 @@ index b7d257b..d5920aa 100644 if serange == "" and setype == "": raise ValueError(_("Requires setype or serange")) -@@ -1068,12 +1209,11 @@ class nodeRecords(semanageRecords): +@@ -1068,12 +1210,11 @@ class nodeRecords(semanageRecords): if not exists: raise ValueError(_("Addr %s is not defined") % addr) @@ -4320,7 +4703,7 @@ index b7d257b..d5920aa 100644 if serange != "": semanage_context_set_mls(self.sh, con, untranslate(serange)) if setype != "": -@@ -1092,18 +1232,8 @@ class nodeRecords(semanageRecords): +@@ -1092,18 +1233,8 @@ class nodeRecords(semanageRecords): self.commit() def __delete(self, addr, mask, proto): @@ -4340,7 +4723,7 @@ index b7d257b..d5920aa 100644 (rc, k) = semanage_node_key_create(self.sh, addr, mask, proto) if rc < 0: -@@ -1132,6 +1262,16 @@ class nodeRecords(semanageRecords): +@@ -1132,6 +1263,16 @@ class nodeRecords(semanageRecords): self.__delete(addr, mask, proto) self.commit() @@ -4357,7 +4740,7 @@ index b7d257b..d5920aa 100644 def get_all(self, locallist = 0): ddict = {} if locallist : -@@ -1145,15 +1285,20 @@ class nodeRecords(semanageRecords): +@@ -1145,15 +1286,20 @@ class nodeRecords(semanageRecords): con = semanage_node_get_con(node) addr = semanage_node_get_addr(self.sh, node) mask = semanage_node_get_mask(self.sh, node) @@ -4383,7 +4766,7 @@ index b7d257b..d5920aa 100644 def list(self, heading = 1, locallist = 0): if heading: print "%-18s %-18s %-5s %-5s\n" % ("IP Address", "Netmask", "Protocol", "Context") -@@ -1193,7 +1338,8 @@ class interfaceRecords(semanageRecords): +@@ -1193,7 +1339,8 @@ class interfaceRecords(semanageRecords): if rc < 0: raise ValueError(_("Could not check if interface %s is defined") % interface) if exists: @@ -4393,7 +4776,7 @@ index b7d257b..d5920aa 100644 (rc, iface) = semanage_iface_create(self.sh) if rc < 0: -@@ -1307,6 +1453,16 @@ class interfaceRecords(semanageRecords): +@@ -1307,6 +1454,16 @@ class interfaceRecords(semanageRecords): self.__delete(interface) self.commit() @@ -4410,7 +4793,7 @@ index b7d257b..d5920aa 100644 def get_all(self, locallist = 0): ddict = {} if locallist: -@@ -1322,6 +1478,15 @@ class interfaceRecords(semanageRecords): +@@ -1322,6 +1479,15 @@ class interfaceRecords(semanageRecords): return ddict @@ -4426,7 +4809,7 @@ index b7d257b..d5920aa 100644 def list(self, heading = 1, locallist = 0): if heading: print "%-30s %s\n" % (_("SELinux Interface"), _("Context")) -@@ -1338,6 +1503,48 @@ class interfaceRecords(semanageRecords): +@@ -1338,6 +1504,48 @@ class interfaceRecords(semanageRecords): class fcontextRecords(semanageRecords): def __init__(self, store = ""): semanageRecords.__init__(self, store) @@ -4475,7 +4858,7 @@ index b7d257b..d5920aa 100644 def createcon(self, target, seuser = "system_u"): (rc, con) = semanage_context_create(self.sh) -@@ -1364,6 +1571,8 @@ class fcontextRecords(semanageRecords): +@@ -1364,6 +1572,8 @@ class fcontextRecords(semanageRecords): def validate(self, target): if target == "" or target.find("\n") >= 0: raise ValueError(_("Invalid file specification")) @@ -4484,7 +4867,7 @@ index b7d257b..d5920aa 100644 def __add(self, target, type, ftype = "", serange = "", seuser = "system_u"): self.validate(target) -@@ -1388,7 +1597,8 @@ class fcontextRecords(semanageRecords): +@@ -1388,7 +1598,8 @@ class fcontextRecords(semanageRecords): raise ValueError(_("Could not check if file context for %s is defined") % target) if exists: @@ -4494,7 +4877,7 @@ index b7d257b..d5920aa 100644 (rc, fcontext) = semanage_fcontext_create(self.sh) if rc < 0: -@@ -1504,9 +1714,16 @@ class fcontextRecords(semanageRecords): +@@ -1504,9 +1715,16 @@ class fcontextRecords(semanageRecords): raise ValueError(_("Could not delete the file context %s") % target) semanage_fcontext_key_free(k) @@ -4511,7 +4894,7 @@ index b7d257b..d5920aa 100644 (rc,k) = semanage_fcontext_key_create(self.sh, target, file_types[ftype]) if rc < 0: raise ValueError(_("Could not create a key for %s") % target) -@@ -1561,12 +1778,22 @@ class fcontextRecords(semanageRecords): +@@ -1561,12 +1779,22 @@ class fcontextRecords(semanageRecords): return ddict @@ -4536,7 +4919,7 @@ index b7d257b..d5920aa 100644 for k in keys: if fcon_dict[k]: if is_mls_enabled: -@@ -1575,6 +1802,12 @@ class fcontextRecords(semanageRecords): +@@ -1575,6 +1803,12 @@ class fcontextRecords(semanageRecords): print "%-50s %-18s %s:%s:%s " % (k[0], k[1], fcon_dict[k][0], fcon_dict[k][1],fcon_dict[k][2]) else: print "%-50s %-18s <>" % (k[0], k[1]) @@ -4549,7 +4932,7 @@ index b7d257b..d5920aa 100644 class booleanRecords(semanageRecords): def __init__(self, store = ""): -@@ -1587,6 +1820,18 @@ class booleanRecords(semanageRecords): +@@ -1587,6 +1821,18 @@ class booleanRecords(semanageRecords): self.dict["1"] = 1 self.dict["0"] = 0 @@ -4568,7 +4951,7 @@ index b7d257b..d5920aa 100644 def __mod(self, name, value): (rc, k) = semanage_bool_key_create(self.sh, name) if rc < 0: -@@ -1606,9 +1851,10 @@ class booleanRecords(semanageRecords): +@@ -1606,9 +1852,10 @@ class booleanRecords(semanageRecords): else: raise ValueError(_("You must specify one of the following values: %s") % ", ".join(self.dict.keys()) ) @@ -4582,7 +4965,7 @@ index b7d257b..d5920aa 100644 rc = semanage_bool_modify_local(self.sh, k, b) if rc < 0: raise ValueError(_("Could not modify boolean %s") % name) -@@ -1691,8 +1937,12 @@ class booleanRecords(semanageRecords): +@@ -1691,8 +1938,12 @@ class booleanRecords(semanageRecords): value = [] name = semanage_bool_get_name(boolean) value.append(semanage_bool_get_value(boolean)) @@ -4597,7 +4980,7 @@ index b7d257b..d5920aa 100644 ddict[name] = value return ddict -@@ -1706,6 +1956,16 @@ class booleanRecords(semanageRecords): +@@ -1706,6 +1957,16 @@ class booleanRecords(semanageRecords): else: return _("unknown") @@ -4647,10 +5030,10 @@ index 0000000..211580d +relabel: ; diff --git a/policycoreutils/sepolgen-ifgen/sepolgen-ifgen-attr-helper.c b/policycoreutils/sepolgen-ifgen/sepolgen-ifgen-attr-helper.c new file mode 100644 -index 0000000..995b270 +index 0000000..8f5c8e0 --- /dev/null +++ b/policycoreutils/sepolgen-ifgen/sepolgen-ifgen-attr-helper.c -@@ -0,0 +1,230 @@ +@@ -0,0 +1,233 @@ +/* Authors: Frank Mayer + * and Karl MacMillan + * @@ -4821,6 +5204,7 @@ index 0000000..995b270 + + if (policydb_init(policydb)) { + fprintf(stderr, "Out of memory!\n"); ++ free(policydb); + return NULL; + } + @@ -4828,6 +5212,7 @@ index 0000000..995b270 + if (ret) { + fprintf(stderr, + "error(s) encountered while parsing configuration\n"); ++ free(policydb); + return NULL; + } + @@ -4850,13 +5235,13 @@ index 0000000..995b270 + + if (argc != 3) { + usage(argv[0]); -+ exit(1); ++ return -1; + } + + /* Open the policy. */ + p = load_policy(argv[1]); + if (p == NULL) { -+ exit(1); ++ return -1; + } + + /* Open the output policy. */ @@ -4865,6 +5250,7 @@ index 0000000..995b270 + fprintf(stderr, "error opening output file\n"); + policydb_destroy(p); + free(p); ++ return -1; + } + + /* Find all of the attributes and output their access. */ diff --git a/policycoreutils.spec b/policycoreutils.spec index 8338986..0fe7c9a 100644 --- a/policycoreutils.spec +++ b/policycoreutils.spec @@ -1,5 +1,5 @@ %define libauditver 1.4.2-1 -%define libsepolver 2.0.41-3 +%define libsepolver 2.0.42-3 %define libsemanagever 2.0.43-4 %define libselinuxver 2.0.90-3 %define sepolgenver 1.0.23 @@ -7,7 +7,7 @@ Summary: SELinux policy core utilities Name: policycoreutils Version: 2.0.85 -Release: 12%{?dist} +Release: 28%{?dist} License: GPLv2 Group: System Environment/Base # Based on git repository with tag 20101221 @@ -119,6 +119,7 @@ Requires: /usr/bin/make Requires(pre): python >= 2.6 Obsoletes: policycoreutils < 2.0.61-2 Requires: setools-libs-python >= 3.3.7-6 +Requires: python-IPy %description python The policycoreutils-python package contains the management tools use to manage an SELinux environment. @@ -156,7 +157,7 @@ exit 0 Summary: SELinux sandbox utilities Group: System Environment/Base Requires: policycoreutils-python = %{version}-%{release} -Requires: xorg-x11-server-Xephyr +Requires: xorg-x11-server-Xephyr /usr/bin/rsync /usr/bin/xmodmap Requires: matchbox-window-manager Requires(post): /sbin/chkconfig BuildRequires: libcap-ng-devel @@ -168,7 +169,7 @@ The policycoreutils-python package contains the scripts to create graphical sand %defattr(-,root,root,-) %{_datadir}/sandbox/sandboxX.sh %{_datadir}/sandbox/start -%attr(0755,root,root) %caps(cap_setpcap,cap_fowner,cap_dac_override,cap_sys_admin,cap_sys_nice=pe) %{_sbindir}/seunshare +%attr(0755,root,root) %caps(cap_setpcap,cap_setuid,cap_fowner,cap_dac_override,cap_sys_admin,cap_sys_nice=pe) %{_sbindir}/seunshare %{_mandir}/man8/seunshare.8* %{_mandir}/man5/sandbox.conf.5* @@ -180,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 @@ -329,8 +331,67 @@ fi exit 0 %changelog -* Wed Feb 23 2011 Dan Walsh 2.0.85-12 +* Tue Mar 29 2011 Dan Walsh 2.0.85-28 +- rsynccmd should run outside of execcon + +* Thu Mar 24 2011 Dan Walsh 2.0.85-27 +- Fix semange node handling of ipv6 addresses + +* Wed Mar 23 2011 Dan Walsh 2.0.85-26 +- Fix sepolgen-ifgen call, add -p option + +* Wed Mar 23 2011 Dan Walsh 2.0.85-25 +- Fix sepolgen-ifgen call + +* Fri Mar 18 2011 Dan Walsh 2.0.85-24 +- Fix rsync command to work if the directory is old. +- Fix all tests + +* Wed Mar 16 2011 Dan Walsh 2.0.85-23 +- Fix sepolgen to generate network polcy using generic_if and genric_node versus all_if and all_node + +* Wed Mar 16 2011 Dan Walsh 2.0.85-22 +- Return to original seunshare man page + +* Fri Mar 11 2011 Dan Walsh 2.0.85-21 +- change default location of HOMEDIR in sandbox to /tmp/.sandbox_home_* +- This will allow default sandboxes to work on NFS homedirs without allowing + access to homedir data + +* Fri Mar 11 2011 Dan Walsh 2.0.85-20 +- Change sepolgen-ifgen to search all available policy files +- Exit in restorecond if it can not find a UID in the passwd database + +* Wed Mar 9 2011 Dan Walsh 2.0.85-19 +- Fix portspage in system-config-selinux to not crash +- More fixes for seunshare from Tomas Hoger + +* Tue Mar 8 2011 Dan Walsh 2.0.85-18 +- put back in old handling of -T in sandbox command +- Put back setsid in seunshare +- Fix rsync to maintain times + +* Tue Mar 8 2011 Dan Walsh 2.0.85-17 +- Use rewritten seunshare from thoger + +* Mon Mar 7 2011 Dan Walsh 2.0.85-16 +- Require python-IPy for policycoreutils-python package +- Fixes for sepologen + - Usage statement needs -n name + - Names with _ are being prevented + - dbus apps should get _chat interface + +* Thu Mar 3 2011 Dan Walsh 2.0.85-15 +- Fix error message in seunshare, check for tmpdir existance before unlink. + +* Fri Feb 25 2011 Dan Walsh 2.0.85-13 - Rewrite seunshare to make sure /tmp is mounted stickybit owned by root +- Only allow names in polgengui that contain letters and numbers +- Fix up node handling in semanage command +- Update translations + +* Wed Feb 09 2011 Fedora Release Engineering - 2.0.85-12 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild * Thu Feb 3 2011 Dan Walsh 2.0.85-11 - Fix sandbox policy creation with udp connect ports