From b91e98e2c2ef18c788e01e6fcb0b7627db708e70 Mon Sep 17 00:00:00 2001 From: Dan Walsh Date: Mon, 19 Sep 2011 07:40:39 -0400 Subject: [PATCH] Update to upstream policycoreutils-2.1.6 * sepolgen-ifgen: new attr-helper does something * audit2allow: use alternate policy file * audit2allow: sepolgen-ifgen use the attr helper * setfiles: switch from stat to stat64 * setfiles: Fix potential crash using dereferenced ftsent * setfiles: do not wrap * output at 80 characters * sandbox: add -Wall and -Werror to makefile * sandbox: add sandbox cgroup support * sandbox: rewrite /tmp handling * sandbox: do not bind mount so much * sandbox: add level based kill option * sandbox: cntrl-c should kill entire process control group * Create a new preserve_tunables flag in sepol_handle_t. * semanage: show running and disk setting for booleans * semanage: Dont print heading if no items selected * sepolgen: audit2allow is mistakakenly not allowing valid module names * semanage: Catch RuntimeErrors, that can be generated when SELinux is disabled * More files to ignore * tree: default make target to all not install * sandbox: do not load unused generic init functions sepolgen-1.1.2 * src: sepolgen: add attribute storing infrastructure * Change perm-map and add open to try to get better results on * look for booleans that might solve problems * sepolgen: audit2allow is mistakakenly not allowing valid module names * tree: default make target to all not install --- .gitignore | 4 + policycoreutils-rhat.patch | 1985 +------------------------------- policycoreutils-sepolgen.patch | 329 ------ policycoreutils.spec | 42 +- sources | 4 +- 5 files changed, 105 insertions(+), 2259 deletions(-) diff --git a/.gitignore b/.gitignore index fd5b9e3..31fcea1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ +*.rpm .svn +*.tgz policycoreutils-1.17.5.tgz policycoreutils-1.17.6.tgz policycoreutils-1.17.7.tgz @@ -227,3 +229,5 @@ policycoreutils-2.0.83.tgz /policycoreutils-2.1.4.tgz /policycoreutils-2.1.5.tgz /sepolgen-1.1.1.tgz +/sepolgen-1.1.2.tgz +/policycoreutils-2.1.6.tgz diff --git a/policycoreutils-rhat.patch b/policycoreutils-rhat.patch index f74aff5..9990662 100644 --- a/policycoreutils-rhat.patch +++ b/policycoreutils-rhat.patch @@ -1,67 +1,20 @@ -diff --git a/policycoreutils/.gitignore b/policycoreutils/.gitignore -index 6f41f6a..50f8b82 100644 ---- a/policycoreutils/.gitignore -+++ b/policycoreutils/.gitignore -@@ -9,6 +9,7 @@ semodule_deps/semodule_deps - semodule_expand/semodule_expand - semodule_link/semodule_link - semodule_package/semodule_package -+semodule_package/semodule_unpackage - sestatus/sestatus - setfiles/restorecon - setfiles/setfiles diff --git a/policycoreutils/Makefile b/policycoreutils/Makefile -index 86ed03f..3e95698 100644 +index 7244a36..3e95698 100644 --- a/policycoreutils/Makefile +++ b/policycoreutils/Makefile @@ -1,4 +1,4 @@ --SUBDIRS = setfiles semanage load_policy newrole run_init sandbox secon audit2allow audit2why scripts sestatus semodule_package semodule semodule_link semodule_expand semodule_deps setsebool po +-SUBDIRS = setfiles semanage load_policy newrole run_init sandbox secon audit2allow audit2why scripts sestatus semodule_package semodule semodule_link semodule_expand semodule_deps sepolgen-ifgen setsebool po +SUBDIRS = setfiles semanage semanage/default_encoding load_policy newrole run_init sandbox secon audit2allow audit2why scripts sestatus semodule_package semodule semodule_link semodule_expand semodule_deps sepolgen-ifgen setsebool po INOTIFYH = $(shell ls /usr/include/sys/inotify.h 2>/dev/null) diff --git a/policycoreutils/audit2allow/audit2allow b/policycoreutils/audit2allow/audit2allow -index 5435e9d..e9d5882 100644 +index e9c80f0..e9d5882 100644 --- a/policycoreutils/audit2allow/audit2allow +++ b/policycoreutils/audit2allow/audit2allow -@@ -1,4 +1,4 @@ --#! /usr/bin/python -E -+#! /usr/bin/python -Es - # Authors: Karl MacMillan - # - # Copyright (C) 2006-2007 Red Hat -@@ -28,6 +28,7 @@ import sepolgen.objectmodel as objectmodel - import sepolgen.defaults as defaults - import sepolgen.module as module - from sepolgen.sepolgeni18n import _ -+import selinux.audit2why as audit2why - - class AuditToPolicy: - VERSION = "%prog .1" -@@ -46,6 +47,7 @@ class AuditToPolicy: - help="audit messages since last boot conflicts with -i") - parser.add_option("-a", "--all", action="store_true", dest="audit", default=False, - help="read input from audit log - conflicts with -i") -+ parser.add_option("-p", "--policy", dest="policy", default=None, help="Policy file to use for analysis") - parser.add_option("-d", "--dmesg", action="store_true", dest="dmesg", default=False, - help="read input from dmesg - conflicts with --all and --input") - parser.add_option("-i", "--input", dest="input", -@@ -102,7 +104,7 @@ class AuditToPolicy: - if name: - options.requires = True - if not module.is_valid_name(name): -- sys.stderr.write("only letters and numbers allowed in module names\n") -+ sys.stderr.write('error: module names must begin with a letter, optionally followed by letters, numbers, "-", "_", "."\n') - sys.exit(2) - - # Make -M and -o conflict -@@ -231,29 +233,12 @@ class AuditToPolicy: - - def __output_audit2why(self): +@@ -235,25 +235,10 @@ class AuditToPolicy: import selinux -- import selinux.audit2why as audit2why import seobject -- audit2why.init() for i in self.__parser.avc_msgs: - rc, bools = audit2why.analyze(i.scontext.to_string(), i.tcontext.to_string(), i.tclass, i.accesses) + rc = i.type @@ -87,146 +40,6 @@ index 5435e9d..e9d5882 100644 if rc == audit2why.ALLOW: print "\t\tUnknown - would be allowed by active policy\n", print "\t\tPossible mismatch between this policy and the one under which the audit message was generated.\n" -@@ -350,11 +335,19 @@ class AuditToPolicy: - def main(self): - try: - self.__parse_options() -+ if self.__options.policy: -+ audit2why.init(self.__options.policy) -+ else: -+ audit2why.init() -+ - self.__read_input() - self.__process_input() - self.__output() - except KeyboardInterrupt: - sys.exit(0) -+ except ValueError, e: -+ print e -+ sys.exit(1) - - if __name__ == "__main__": - app = AuditToPolicy() -diff --git a/policycoreutils/audit2allow/audit2allow.1 b/policycoreutils/audit2allow/audit2allow.1 -index fd9eb88..a854a45 100644 ---- a/policycoreutils/audit2allow/audit2allow.1 -+++ b/policycoreutils/audit2allow/audit2allow.1 -@@ -67,6 +67,9 @@ Generate module/require output - .B "\-M " - Generate loadable module package, conflicts with -o - .TP -+.B "\-p " | "\-\-policy " -+Policy file to use for analysis -+.TP - .B "\-o " | "\-\-output " - append output to - .I -diff --git a/policycoreutils/audit2allow/sepolgen-ifgen b/policycoreutils/audit2allow/sepolgen-ifgen -index 0acbf7e..ef4bec3 100644 ---- a/policycoreutils/audit2allow/sepolgen-ifgen -+++ b/policycoreutils/audit2allow/sepolgen-ifgen -@@ -28,6 +28,10 @@ - - import sys - import os -+import tempfile -+import subprocess -+ -+import selinux - - import sepolgen.refparser as refparser - import sepolgen.defaults as defaults -@@ -35,6 +39,7 @@ import sepolgen.interfaces as interfaces - - - VERSION = "%prog .1" -+ATTR_HELPER = "/usr/bin/sepolgen-ifgen-attr-helper" - - def parse_options(): - from optparse import OptionParser -@@ -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, - help="extra debugging output") -+ parser.add_option("--no_attrs", action="store_true", default=False, -+ help="do not retrieve attribute access from kernel policy") - options, args = parser.parse_args() - - return options - -+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: -+ 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") -+ return None -+ except OSError: -+ # SELinux Disabled Machine -+ return None -+ -+ fd = open("/dev/null","w") -+ ret = subprocess.Popen([ATTR_HELPER, policy_path, outfile.name], stdout=fd).wait() -+ fd.close() -+ if ret != 0: -+ sys.stderr.write("could not run attribute helper") -+ return None -+ -+ attrs = interfaces.AttributeSet() -+ try: -+ attrs.from_file(outfile) -+ except: -+ print "error parsing attribute info" -+ return None -+ -+ return attrs - - def main(): - options = parse_options() -@@ -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(options.policy_path) -+ if attrs is None: -+ return 1 -+ -+ # Parse the headers - try: - headers = refparser.parse_headers(options.headers, output=log, debug=options.debug) - except ValueError, e: -@@ -76,7 +133,7 @@ def main(): - return 1 - - if_set = interfaces.InterfaceSet(output=log) -- if_set.add_headers(headers) -+ if_set.add_headers(headers, attributes=attrs) - if_set.to_file(f) - f.close() - diff --git a/policycoreutils/newrole/newrole.c b/policycoreutils/newrole/newrole.c index 99d0ed7..3f08d37 100644 --- a/policycoreutils/newrole/newrole.c @@ -1507,20 +1320,9 @@ index 9db766c..068e24c 100644 } /* main() */ diff --git a/policycoreutils/sandbox/Makefile b/policycoreutils/sandbox/Makefile -index 21df0c4..924999d 100644 +index 4764987..924999d 100644 --- a/policycoreutils/sandbox/Makefile +++ b/policycoreutils/sandbox/Makefile -@@ -7,8 +7,8 @@ SBINDIR ?= $(PREFIX)/sbin - MANDIR ?= $(PREFIX)/share/man - LOCALEDIR ?= /usr/share/locale - SHAREDIR ?= $(PREFIX)/share/sandbox --override CFLAGS += $(LDFLAGS) -I$(PREFIX)/include -DPACKAGE="\"policycoreutils\"" --LDLIBS += -lselinux -lcap-ng -+override CFLAGS += $(LDFLAGS) -I$(PREFIX)/include -DPACKAGE="\"policycoreutils\"" -Wall -Werror -Wextra -+LDLIBS += -lcgroup -lselinux -lcap-ng - - all: sandbox seunshare sandboxX.sh start - @@ -22,7 +22,7 @@ install: all install -m 644 sandbox.8 $(MANDIR)/man8/ install -m 644 seunshare.8 $(MANDIR)/man8/ @@ -1530,205 +1332,11 @@ index 21df0c4..924999d 100644 -mkdir -p $(SBINDIR) install -m 4755 seunshare $(SBINDIR)/ -mkdir -p $(SHAREDIR) -diff --git a/policycoreutils/sandbox/sandbox b/policycoreutils/sandbox/sandbox -index edae667..486cd4e 100644 ---- a/policycoreutils/sandbox/sandbox -+++ b/policycoreutils/sandbox/sandbox -@@ -29,7 +29,6 @@ import commands - import setools - - PROGNAME = "policycoreutils" --HOMEDIR=pwd.getpwuid(os.getuid()).pw_dir - SEUNSHARE = "/usr/sbin/seunshare" - SANDBOXSH = "/usr/share/sandbox/sandboxX.sh" - import gettext -@@ -258,9 +257,9 @@ Policy defines the following types for use with the -t: - 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 - -@@ -309,6 +308,10 @@ sandbox [-h] [-l level ] [-[X|M] [-H homedir] [-T tempdir]] [-I includefile ] [- - 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", "--capabilities", - action="store_true", dest="usecaps", default=False, - help="Allow apps requiring capabilities to run within the sandbox.") -@@ -370,30 +373,29 @@ sandbox [-h] [-l level ] [-[X|M] [-H homedir] [-T tempdir]] [-I includefile ] [- - def __setup_dir(self): - if self.__options.level or self.__options.session: - return -- 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.__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) -- self.__tmpdir = mkdtemp(dir="/tmp", prefix=".sandbox") -+ self.__tmpdir = mkdtemp(dir="/tmp", prefix=".sandbox_tmp_") - selinux.setfscreatecon(None) - self.__copyfiles() - - def __execute(self): - try: - cmds = [ SEUNSHARE, "-Z", self.__execcon ] -- if self.__options.usecaps == 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 ] -diff --git a/policycoreutils/sandbox/sandbox.8 b/policycoreutils/sandbox/sandbox.8 -index e3b7ea7..2b37e63 100644 ---- a/policycoreutils/sandbox/sandbox.8 -+++ b/policycoreutils/sandbox/sandbox.8 -@@ -3,11 +3,11 @@ - sandbox \- Run cmd under an SELinux sandbox - .SH SYNOPSIS - .B sandbox --[-C] [-l level ] [[-M | -X] -H homedir -T tempdir ] [-I includefile ] [ -W windowmanager ] [ -w windowsize ] [[-i file ]...] [ -t type ] cmd -+[-C] [-c] [-l level ] [[-M | -X] -H homedir -T tempdir ] [-I includefile ] [ -W windowmanager ] [ -w windowsize ] [[-i file ]...] [ -t type ] cmd - - .br - .B sandbox --[-C] [-l level ] [[-M | -X] -H homedir -T tempdir ] [-I includefile ] [ -W windowmanager ] [ -w windowsize ] [[-i file ]...] [ -t type ] -S -+[-C] [-c] [-l level ] [[-M | -X] -H homedir -T tempdir ] [-I includefile ] [ -W windowmanager ] [ -w windowsize ] [[-i file ]...] [ -t type ] -S - .br - .SH DESCRIPTION - .PP -@@ -60,10 +60,19 @@ Default to /usr/bin/matchbox-window-manager. - 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 -+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 --runcon(1) -+runcon(1), seunshare(8), selinux(8) - .PP -+ -+.SH AUTHOR -+This manual page was written by -+.I Dan Walsh -+and -+.I Thomas Liu -diff --git a/policycoreutils/sandbox/sandbox.init b/policycoreutils/sandbox/sandbox.init -index ff8b3ef..d1ccdc2 100644 ---- a/policycoreutils/sandbox/sandbox.init -+++ b/policycoreutils/sandbox/sandbox.init -@@ -10,25 +10,15 @@ - # - # chkconfig: 345 1 99 - # --# Description: sandbox and other apps that want to use pam_namespace --# on /var/tmp, /tmp and home directories, requires this script --# to be run at boot time. --# This script sets up the / mount point and all of its --# subdirectories as shared. The script sets up --# /tmp, /var/tmp, /home and any homedirs listed in --# /etc/sysconfig/sandbox and all of their subdirectories --# as unshared. --# All processes that use pam_namespace will see --# modifications to the global mountspace, except for the --# unshared directories. -+# description: sandbox, xguest and other apps that want to use pam_namespace \ -+# require this script be run at boot. This service script does \ -+# not actually run any service but sets up: \ -+# / to be shared by any app that starts a separate namespace -+# If you do not use sandbox, xguest or pam_namespace you can turn \ -+# this service off.\ - # - - # Source function library. --. /etc/init.d/functions -- --HOMEDIRS="/home" -- --. /etc/sysconfig/sandbox - - LOCKFILE=/var/lock/subsys/sandbox - -@@ -41,15 +31,6 @@ start() { - - touch $LOCKFILE - mount --make-rshared / || return $? -- mount --rbind /tmp /tmp || return $? -- mount --rbind /var/tmp /var/tmp || return $? -- mount --make-private /tmp || return $? -- mount --make-private /var/tmp || return $? -- for h in $HOMEDIRS; do -- mount --rbind $h $h || return $? -- mount --make-private $h || return $? -- done -- - return 0 - } - -diff --git a/policycoreutils/sandbox/seunshare.8 b/policycoreutils/sandbox/seunshare.8 -index a9b846b..06610c0 100644 ---- a/policycoreutils/sandbox/seunshare.8 -+++ b/policycoreutils/sandbox/seunshare.8 -@@ -3,7 +3,7 @@ - seunshare \- Run cmd with alternate homedir, tmpdir and/or SELinux context - .SH SYNOPSIS - .B seunshare --[ -v ] [ -c ] [ -C ] [ -t tmpdir ] [ -h homedir ] [ -Z context ] -- executable [args] -+[ -v ] [ -c ] [ -C ] [ -k ] [ -t tmpdir ] [ -h homedir ] [ -Z context ] -- executable [args] - .br - .SH DESCRIPTION - .PP -@@ -16,7 +16,7 @@ within the specified context, using the alternate home directory and /tmp direct - Alternate homedir to be used by the application. Homedir must be owned by the user. - .TP - \fB\-t\ tmpdir --Use alternate temporary directory to mount on /tmp. tmpdir must be owned by the user. -+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. -@@ -24,6 +24,9 @@ Use cgroups to control this copy of seunshare. Specify parameters in /etc/sysco - \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 diff --git a/policycoreutils/sandbox/seunshare.c b/policycoreutils/sandbox/seunshare.c -index f9bf12c..594aff4 100644 +index a52b6f1..c493e98 100644 --- a/policycoreutils/sandbox/seunshare.c +++ b/policycoreutils/sandbox/seunshare.c -@@ -1,27 +1,35 @@ +@@ -1,3 +1,8 @@ +/* + * Authors: Dan Walsh + * Authors: Thomas Liu @@ -1736,39 +1344,8 @@ index f9bf12c..594aff4 100644 + #define _GNU_SOURCE #include - #include -+#include - #include - #include - #include -+#include - #include - #include -+#include - #include - #include -+#include - #include -+#include - #include - #include - #include /* for getopt_long() form of getopt() */ - #include - #include - #include -+#include - - #include - #include /* for context-mangling functions */ -- --#include --#include --#include -+#include - - #ifdef USE_NLS - #include /* for setlocale() */ -@@ -39,10 +47,16 @@ + #include +@@ -42,6 +47,10 @@ #define MS_PRIVATE 1<<18 #endif @@ -1776,700 +1353,10 @@ index f9bf12c..594aff4 100644 +#define PACKAGE "policycoreutils" /* the name of this package lang translation */ +#endif + -+#define BUF_SIZE 1024 + #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; - -@@ -74,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) -@@ -88,12 +109,17 @@ static int set_signal_handles(void) - - (void)sigprocmask(SIG_SETMASK, &empty, NULL); - -- /* Terminate on SIGHUP. */ -+ /* Terminate on SIGHUP */ - 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; - } - -@@ -139,26 +165,6 @@ static int spawn_command(const char *cmd, uid_t uid){ - } - - /** -- * 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. -- */ --static int verify_mount(const char *mntdir, struct passwd *pwd) { -- struct stat sb; -- if (stat(mntdir, &sb) == -1) { -- fprintf(stderr, _("Invalid mount point %s: %s\n"), mntdir, 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")); -- return -1; -- } -- return 0; --} -- --/** - * Check file/directory ownership, struct stat * must be passed to the - * functions. - */ -@@ -236,7 +242,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; - } - } -@@ -244,43 +250,600 @@ static int verify_shell(const char *shell_name) - return rc; - } - --static int seunshare_mount(const char *src, const char *dst, struct passwd *pwd) { -+/** -+ * Mount directory and check that we mounted the right directory. -+ */ -+static int seunshare_mount(const char *src, const char *dst, struct stat *src_st) -+{ -+ int flags = MS_REC; -+ int is_tmp = 0; -+ - 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)); - return -1; - } - -- if (verify_mount(dst, pwd) < 0) -+ /* 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; -+ -+} -+ -+/** -+ * Error logging used by cgroups code. -+ */ -+static int sandbox_error(const char *string) -+{ -+ fprintf(stderr, string); -+ syslog(LOG_AUTHPRIV | LOG_ALERT, string); -+ exit(-1); -+} -+ -+/** -+ * 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) { -+ return 0; -+ } -+ status = regexec(&re, string, (size_t)0, NULL, 0); -+ regfree(&re); -+ if (status != 0) { -+ return 0; -+ } -+ return 1; -+} -+ -+/** -+ * 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 */ -+ int64_t memusage = 0; /* amount of memory to use max (percent) */ -+ int cpupercentage = 0; /* what percentage of cpu to allow usage */ -+ FILE* fp; -+ char buf[BUF_SIZE]; -+ char *tok = NULL; -+ int rc = -1; -+ char *str = NULL; -+ const char* fname = "/etc/sysconfig/sandbox"; -+ -+ if ((fp = fopen(fname, "rt")) == NULL) { -+ fprintf(stderr, "Error opening sandbox config file."); -+ return rc; -+ } -+ while(fgets(buf, BUF_SIZE, fp) != NULL) { -+ /* Skip comments */ -+ if (buf[0] == '#') continue; -+ -+ /* Copy the string, ignoring whitespace */ -+ int len = strlen(buf); -+ 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]; -+ if (cur != ' ' && cur != '\t') { -+ str[ind] = cur; -+ ind++; -+ } -+ } -+ str[ind] = '\0'; -+ -+ tok = strtok(str, "=\n"); -+ if (tok != NULL) { -+ if (!strcmp(tok, "CPUAFFINITY")) { -+ tok = strtok(NULL, "=\n"); -+ cpus = strdup(tok); -+ if (!strcmp(cpus, "ALL")) { -+ free(cpus); -+ cpus = NULL; -+ } -+ } else if (!strcmp(tok, "MEMUSAGE")) { -+ tok = strtok(NULL, "=\n"); -+ if (match(tok, "^[0-9]+[kKmMgG%]")) { -+ char *ind = strchr(tok, '%'); -+ if (ind != NULL) { -+ *ind = '\0';; -+ memusage = atoi(tok); -+ } else { -+ mem = strdup(tok); -+ } -+ } else { -+ fprintf(stderr, "Error parsing config file."); -+ goto err; -+ } -+ -+ } else if (!strcmp(tok, "CPUUSAGE")) { -+ tok = strtok(NULL, "=\n"); -+ if (match(tok, "^[0-9]+\%")) { -+ char* ind = strchr(tok, '%'); -+ *ind = '\0'; -+ cpupercentage = atoi(tok); -+ } else { -+ fprintf(stderr, "Error parsing config file."); -+ goto err; -+ } -+ } else if (!strcmp(tok, "NAME")) { -+ tok = strtok(NULL, "=\n"); -+ cgroupname = strdup(tok); -+ } else { -+ 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; -+ int64_t current_period = 0 ; -+ int64_t current_mem = 0; -+ char *curr_cpu_path = NULL; -+ char *curr_mem_path = NULL; -+ int ret = cgroup_get_current_controller_path(getpid(), "cpu", &curr_cpu_path); -+ if (ret) { -+ sandbox_error("Error while trying to get current controller path.\n"); -+ } else { -+ struct cgroup *curr = cgroup_new_cgroup(curr_cpu_path); -+ 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"); -+ } else { -+ 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 (memusage > current_mem) { -+ sandbox_error("Attempting to use more memory than allowed!"); -+ goto err; -+ } -+ } -+ -+ long nprocs = sysconf(_SC_NPROCESSORS_ONLN); -+ -+ 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); -+ } -+ if (cpupercentage > 0) { -+ cgroup_set_value_uint64(cgroup_get_controller(sandbox_group, "cpu"), "cpu.rt_runtime_us", -+ (float) cpupercentage / 100.0 * 60000); -+ cgroup_set_value_uint64(cgroup_get_controller(sandbox_group, "cpu"), "cpu.rt_period_us",60000 * nprocs); -+ } -+ 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"); -+ goto err; -+ } -+ -+ cgroup_attach_task(sandbox_group); -+ -+ 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) { -+ 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; -+} -+ -+/** -+ * 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; -+} -+ -+#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 rc; - int status = -1; -+ security_context_t execcon = NULL; - -- security_context_t scontext = NULL; -- -- 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[] */ -+ 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[] */ -+ 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'}, -+ {"kill", 1, 0, 'k'}, - {"verbose", 1, 0, 'v'}, -+ {"cgroups", 1, 0, 'c'}, - {"context", 1, 0, 'Z'}, - {"capabilities", 1, 0, 'C'}, - {NULL, 0, 0, 0} -@@ -294,6 +857,12 @@ int main(int argc, char **argv) { + #define USAGE_STRING _("USAGE: seunshare [ -v ] [ -C ] [ -c ] [ -k ] [ -t tmpdir ] [ -h homedir ] [ -Z CONTEXT ] -- executable [args] ") +@@ -848,6 +857,12 @@ int main(int argc, char **argv) { } */ @@ -2482,180 +1369,18 @@ index f9bf12c..594aff4 100644 struct passwd *pwd=getpwuid(uid); if (!pwd) { perror(_("getpwduid failed")); -@@ -301,7 +870,7 @@ int main(int argc, char **argv) { - } +@@ -944,6 +959,7 @@ 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; - } - -@@ -312,28 +881,25 @@ int main(int argc, char **argv) { - - switch (clflag) { - 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; -+ tmpdir_s = optarg; -+ break; -+ case 'k': -+ kill_all = 1; - break; - case 'h': -- if (!(homedir_s = realpath(optarg, NULL))) { -- fprintf(stderr, _("Invalid mount point %s: %s\n"), optarg, strerror(errno)); -- return -1; -- } -- if (verify_mount(homedir_s, pwd) < 0) return -1; -- if (verify_mount(pwd->pw_dir, pwd) < 0) return -1; -+ homedir_s = optarg; - break; - case 'v': -- verbose = 1; -+ verbose++; -+ break; -+ case 'c': -+ usecgroups = 1; - break; - case 'C': - cap_set = CAPNG_SELECT_CAPS; - break; - case 'Z': -- scontext = strdup(optarg); -+ execcon = optarg; - break; - default: - fprintf(stderr, "%s\n", USAGE_STRING); -@@ -342,97 +908,144 @@ int main(int argc, char **argv) { - } - - if (! homedir_s && ! tmpdir_s) { -- fprintf(stderr, _("Error: tmpdir and/or homedir required \n"), -- "%s\n", USAGE_STRING); -+ fprintf(stderr, _("Error: tmpdir and/or homedir required\n %s\n"), USAGE_STRING); - return -1; - } - - 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; - } - -- if (set_signal_handles()) -+ if (execcon && is_selinux_enabled() != 1) { -+ fprintf(stderr, _("Error: execution context specified, but SELinux is not enabled\n")); - return -1; -+ } - -- if (unshare(CLONE_NEWNS) < 0) { -- perror(_("Failed to unshare")); -+ if (set_signal_handles()) - return -1; -- } - -- if (homedir_s && tmpdir_s && (strncmp(pwd->pw_dir, tmpdir_s, strlen(pwd->pw_dir)) == 0)) { -- if (seunshare_mount(tmpdir_s, "/tmp", pwd) < 0) -- return -1; -- if (seunshare_mount(homedir_s, pwd->pw_dir, pwd) < 0) -- return -1; -- } else { -- if (homedir_s && seunshare_mount(homedir_s, pwd->pw_dir, pwd) < 0) -- return -1; -- -- if (tmpdir_s && seunshare_mount(tmpdir_s, "/tmp", pwd) < 0) -- return -1; -- } -+ 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); - -- if (drop_privs(uid)) -+ /* 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; -+ } - -- int child = fork(); -+ /* spawn child process */ -+ child = fork(); - if (child == -1) { - perror(_("Unable to fork")); -- 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; + if (child == 0) { + char *display = NULL; + char *LANG = NULL; -+ int rc = -1; + int rc = -1; -- if ((rc = clearenv())) { -- perror(_("Unable to clear environment")); -- free(display); -- exit(-1); -+ if (unshare(CLONE_NEWNS) < 0) { -+ perror(_("Failed to unshare")); -+ goto childerr; - } - -- if (scontext) { -- if (setexeccon(scontext)) { -- fprintf(stderr, _("Could not set exec context to %s.\n"), -- scontext); -- 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 (unshare(CLONE_NEWNS) < 0) { +@@ -969,12 +985,23 @@ int main(int argc, char **argv) { + goto childerr; } } -- -- if (display) + + /* construct a new environment */ + if ((LANG = getenv("LANG")) != NULL) { @@ -2665,69 +1390,25 @@ index f9bf12c..594aff4 100644 + } + } + -+ if ((rc = clearenv()) != 0) { -+ perror(_("Failed to clear environment")); -+ goto childerr; -+ } -+ if (display) + if ((rc = clearenv()) != 0) { + perror(_("Failed to clear environment")); + goto childerr; + } + 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); - 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: +@@ -1000,6 +1027,7 @@ int main(int argc, char **argv) { + fprintf(stderr, _("Failed to execute command %s: %s\n"), argv[optind], strerror(errno)); + childerr: free(display); -- perror("execv"); + free(LANG); exit(-1); -- } else { -- waitpid(child, &status, 0); } -- free(tmpdir_s); -- free(homedir_s); -- free(scontext); -+ drop_caps(); -+ -+ /* parent waits for child exit to do the cleanup */ -+ 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; - } diff --git a/policycoreutils/scripts/fixfiles b/policycoreutils/scripts/fixfiles index e4e5f0d..27dcccf 100755 --- a/policycoreutils/scripts/fixfiles @@ -2888,7 +1569,7 @@ index 0000000..e2befdb + packages=["policycoreutils"], +) diff --git a/policycoreutils/semanage/semanage b/policycoreutils/semanage/semanage -index 0140cd2..2c0cfdd 100644 +index ee4d077..2c0cfdd 100644 --- a/policycoreutils/semanage/semanage +++ b/policycoreutils/semanage/semanage @@ -20,6 +20,7 @@ @@ -3017,23 +1698,10 @@ index 0140cd2..2c0cfdd 100644 except ValueError, error: errorExit(error.args[0]) except KeyError, error: -@@ -564,3 +575,5 @@ Object-specific Options (see above): - errorExit(error.args[1]) - except OSError, error: - errorExit(error.args[1]) -+ except RuntimeError, error: -+ errorExit(error.args[0]) diff --git a/policycoreutils/semanage/seobject.py b/policycoreutils/semanage/seobject.py -index 6842b07..e4b6c0d 100644 +index 1c83682..e4b6c0d 100644 --- a/policycoreutils/semanage/seobject.py +++ b/policycoreutils/semanage/seobject.py -@@ -1,5 +1,5 @@ - #! /usr/bin/python -E --# Copyright (C) 2005, 2006, 2007, 2008, 2009 Red Hat -+# Copyright (C) 2005-2011 Red Hat - # see file 'COPYING' for use and warranty information - # - # semanage is a tool for managing SELinux configuration files @@ -30,11 +30,10 @@ from IPy import IP import gettext gettext.bindtextdomain(PROGNAME, "/usr/share/locale") @@ -3073,22 +1741,7 @@ index 6842b07..e4b6c0d 100644 if not semanage_is_managed(handle): semanage_handle_destroy(handle) -@@ -253,9 +254,13 @@ class moduleRecords(semanageRecords): - return l - - def list(self, heading = 1, locallist = 0): -+ all = self.get_all() -+ if len(all) == 0: -+ return -+ - if heading: - print "\n%-25s%-10s\n" % (_("Modules Name"), _("Version")) -- for t in self.get_all(): -+ for t in all: - if t[2] == 0: - disabled = _("Disabled") - else: -@@ -328,11 +333,14 @@ class permissiveRecords(semanageRecords): +@@ -332,6 +333,7 @@ class permissiveRecords(semanageRecords): name = semanage_module_get_name(mod) if name and name.startswith("permissive_"): l.append(name.split("permissive_")[1]) @@ -3096,25 +1749,7 @@ index 6842b07..e4b6c0d 100644 return l def list(self, heading = 1, locallist = 0): - import setools - all = map(lambda y: y["name"], filter(lambda x: x["permissive"], setools.seinfo(setools.TYPE))) -+ if len(all) == 0: -+ return - - if heading: - print "\n%-25s\n" % (_("Builtin Permissive Types")) -@@ -340,6 +348,10 @@ class permissiveRecords(semanageRecords): - for t in all: - if t not in customized: - print t -+ -+ if len(customized) == 0: -+ return -+ - if heading: - print "\n%-25s\n" % (_("Customized Permissive Types")) - for t in customized: -@@ -420,7 +432,9 @@ class loginRecords(semanageRecords): +@@ -430,7 +432,9 @@ class loginRecords(semanageRecords): if rc < 0: raise ValueError(_("Could not check if login mapping for %s is defined") % name) if exists: @@ -3125,18 +1760,7 @@ index 6842b07..e4b6c0d 100644 if name[0] == '%': try: grp.getgrnam(name[1:]) -@@ -588,7 +602,10 @@ class loginRecords(semanageRecords): - def list(self,heading = 1, locallist = 0): - ddict = self.get_all(locallist) - keys = ddict.keys() -+ if len(keys) == 0: -+ return - keys.sort() -+ - if is_mls_enabled == 1: - if heading: - print "\n%-25s %-25s %-25s\n" % (_("Login Name"), _("SELinux User"), _("MLS/MCS Range")) -@@ -627,7 +644,8 @@ class seluserRecords(semanageRecords): +@@ -640,7 +644,8 @@ class seluserRecords(semanageRecords): if rc < 0: raise ValueError(_("Could not check if SELinux user %s is defined") % name) if exists: @@ -3146,18 +1770,7 @@ index 6842b07..e4b6c0d 100644 (rc, u) = semanage_user_create(self.sh) if rc < 0: -@@ -820,7 +838,10 @@ class seluserRecords(semanageRecords): - def list(self, heading = 1, locallist = 0): - ddict = self.get_all(locallist) - keys = ddict.keys() -+ if len(keys) == 0: -+ return - keys.sort() -+ - if is_mls_enabled == 1: - if heading: - print "\n%-15s %-10s %-10s %-30s" % ("", _("Labeling"), _("MLS/"), _("MLS/")) -@@ -864,6 +885,7 @@ class portRecords(semanageRecords): +@@ -880,6 +885,7 @@ class portRecords(semanageRecords): return ( k, proto_d, low, high ) def __add(self, port, proto, serange, type): @@ -3165,7 +1778,7 @@ index 6842b07..e4b6c0d 100644 if is_mls_enabled == 1: if serange == "": serange = "s0" -@@ -926,6 +948,7 @@ class portRecords(semanageRecords): +@@ -942,6 +948,7 @@ class portRecords(semanageRecords): self.commit() def __modify(self, port, proto, serange, setype): @@ -3173,24 +1786,7 @@ index 6842b07..e4b6c0d 100644 if serange == "" and setype == "": if is_mls_enabled == 1: raise ValueError(_("Requires setype or serange")) -@@ -1073,11 +1096,14 @@ class portRecords(semanageRecords): - return l - - def list(self, heading = 1, locallist = 0): -- if heading: -- print "%-30s %-8s %s\n" % (_("SELinux Port Type"), _("Proto"), _("Port Number")) - ddict = self.get_all_by_type(locallist) - keys = ddict.keys() -+ if len(keys) == 0: -+ return - keys.sort() -+ -+ if heading: -+ print "%-30s %-8s %s\n" % (_("SELinux Port Type"), _("Proto"), _("Port Number")) - for i in keys: - rec = "%-30s %-8s " % i - rec += "%s" % ddict[i][0] -@@ -1136,7 +1162,8 @@ class nodeRecords(semanageRecords): +@@ -1155,7 +1162,8 @@ class nodeRecords(semanageRecords): (rc, exists) = semanage_node_exists(self.sh, k) if exists: @@ -3200,7 +1796,7 @@ index 6842b07..e4b6c0d 100644 (rc, node) = semanage_node_create(self.sh) if rc < 0: -@@ -1152,7 +1179,6 @@ class nodeRecords(semanageRecords): +@@ -1171,7 +1179,6 @@ class nodeRecords(semanageRecords): if rc < 0: raise ValueError(_("Could not set mask for %s") % addr) @@ -3208,7 +1804,7 @@ index 6842b07..e4b6c0d 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) -@@ -1204,12 +1230,11 @@ class nodeRecords(semanageRecords): +@@ -1223,12 +1230,11 @@ class nodeRecords(semanageRecords): if not exists: raise ValueError(_("Addr %s is not defined") % addr) @@ -3222,24 +1818,7 @@ index 6842b07..e4b6c0d 100644 if serange != "": semanage_context_set_mls(self.sh, con, untranslate(serange)) if setype != "": -@@ -1296,11 +1321,14 @@ class nodeRecords(semanageRecords): - return l - - def list(self, heading = 1, locallist = 0): -- if heading: -- print "%-18s %-18s %-5s %-5s\n" % ("IP Address", "Netmask", "Protocol", "Context") - ddict = self.get_all(locallist) - keys = ddict.keys() -+ if len(keys) == 0: -+ return - keys.sort() -+ -+ if heading: -+ print "%-18s %-18s %-5s %-5s\n" % ("IP Address", "Netmask", "Protocol", "Context") - if is_mls_enabled: - for k in keys: - val = '' -@@ -1334,7 +1362,8 @@ class interfaceRecords(semanageRecords): +@@ -1356,7 +1362,8 @@ class interfaceRecords(semanageRecords): if rc < 0: raise ValueError(_("Could not check if interface %s is defined") % interface) if exists: @@ -3249,24 +1828,7 @@ index 6842b07..e4b6c0d 100644 (rc, iface) = semanage_iface_create(self.sh) if rc < 0: -@@ -1483,11 +1512,14 @@ class interfaceRecords(semanageRecords): - return l - - def list(self, heading = 1, locallist = 0): -- if heading: -- print "%-30s %s\n" % (_("SELinux Interface"), _("Context")) - ddict = self.get_all(locallist) - keys = ddict.keys() -+ if len(keys) == 0: -+ return - keys.sort() -+ -+ if heading: -+ print "%-30s %s\n" % (_("SELinux Interface"), _("Context")) - if is_mls_enabled: - for k in keys: - print "%-30s %s:%s:%s:%s " % (k,ddict[k][0], ddict[k][1],ddict[k][2], translate(ddict[k][3], False)) -@@ -1592,7 +1624,8 @@ class fcontextRecords(semanageRecords): +@@ -1617,7 +1624,8 @@ class fcontextRecords(semanageRecords): raise ValueError(_("Could not check if file context for %s is defined") % target) if exists: @@ -3276,24 +1838,7 @@ index 6842b07..e4b6c0d 100644 (rc, fcontext) = semanage_fcontext_create(self.sh) if rc < 0: -@@ -1783,11 +1816,14 @@ class fcontextRecords(semanageRecords): - return l - - def list(self, heading = 1, locallist = 0 ): -- if heading: -- print "%-50s %-18s %s\n" % (_("SELinux fcontext"), _("type"), _("Context")) - fcon_dict = self.get_all(locallist) - keys = fcon_dict.keys() -+ if len(keys) == 0: -+ return - keys.sort() -+ -+ if heading: -+ print "%-50s %-18s %s\n" % (_("SELinux fcontext"), _("type"), _("Context")) - for k in keys: - if fcon_dict[k]: - if is_mls_enabled: -@@ -1814,6 +1850,18 @@ class booleanRecords(semanageRecords): +@@ -1842,6 +1850,18 @@ class booleanRecords(semanageRecords): self.dict["1"] = 1 self.dict["0"] = 0 @@ -3312,7 +1857,7 @@ index 6842b07..e4b6c0d 100644 def __mod(self, name, value): (rc, k) = semanage_bool_key_create(self.sh, name) if rc < 0: -@@ -1833,9 +1881,10 @@ class booleanRecords(semanageRecords): +@@ -1861,9 +1881,10 @@ class booleanRecords(semanageRecords): else: raise ValueError(_("You must specify one of the following values: %s") % ", ".join(self.dict.keys()) ) @@ -3326,7 +1871,7 @@ index 6842b07..e4b6c0d 100644 rc = semanage_bool_modify_local(self.sh, k, b) if rc < 0: raise ValueError(_("Could not modify boolean %s") % name) -@@ -1918,8 +1967,12 @@ class booleanRecords(semanageRecords): +@@ -1946,8 +1967,12 @@ class booleanRecords(semanageRecords): value = [] name = semanage_bool_get_name(boolean) value.append(semanage_bool_get_value(boolean)) @@ -3341,358 +1886,21 @@ index 6842b07..e4b6c0d 100644 ddict[name] = value return ddict -@@ -1952,11 +2005,13 @@ class booleanRecords(semanageRecords): - if ddict[k]: - print "%s=%s" % (k, ddict[k][2]) - return -- if heading: -- print "%-40s %s\n" % (_("SELinux boolean"), _("Description")) - ddict = self.get_all(locallist) - keys = ddict.keys() -+ if len(keys) == 0: -+ return -+ -+ if heading: -+ print "%-30s %s %s %s\n" % (_("SELinux boolean"),_("State"), _("Default"), _("Description")) - for k in keys: - if ddict[k]: -- print "%-30s -> %-5s %s" % (k, on_off[ddict[k][2]], self.get_desc(k)) -- -+ print "%-30s (%-5s,%5s) %s" % (k, on_off[selinux.security_get_boolean_active(k)], on_off[ddict[k][2]], self.get_desc(k)) -diff --git a/policycoreutils/semodule/semodule.c b/policycoreutils/semodule/semodule.c -index 81d6a3c..5d662e7 100644 ---- a/policycoreutils/semodule/semodule.c -+++ b/policycoreutils/semodule/semodule.c -@@ -45,6 +45,7 @@ static int no_reload; - static int create_store; - static int build; - static int disable_dontaudit; -+static int preserve_tunables; +diff --git a/policycoreutils/semodule_package/Makefile b/policycoreutils/semodule_package/Makefile +index f84cd7e..3565f5e 100644 +--- a/policycoreutils/semodule_package/Makefile ++++ b/policycoreutils/semodule_package/Makefile +@@ -24,7 +24,7 @@ install: all + relabel: - static semanage_handle_t *sh = NULL; - static char *store; -@@ -117,6 +118,7 @@ static void usage(char *progname) - printf(" -h,--help print this message and quit\n"); - printf(" -v,--verbose be verbose\n"); - printf(" -D,--disable_dontaudit Remove dontaudits from policy\n"); -+ printf(" -P,--preserve_tunables Preserve tunables in policy\n"); - } + clean: +- -rm -f semodule_package *.o ++ -rm -f semodule_package semodule_unpackage *.o - /* Sets the global mode variable to new_mode, but only if no other -@@ -162,6 +164,7 @@ static void parse_command_line(int argc, char **argv) - {"noreload", 0, NULL, 'n'}, - {"build", 0, NULL, 'B'}, - {"disable_dontaudit", 0, NULL, 'D'}, -+ {"preserve_tunables", 0, NULL, 'P'}, - {"path", required_argument, NULL, 'p'}, - {NULL, 0, NULL, 0} - }; -@@ -171,7 +174,7 @@ static void parse_command_line(int argc, char **argv) - no_reload = 0; - create_store = 0; - while ((i = -- getopt_long(argc, argv, "p:s:b:hi:lvqe:d:r:u:RnBD", opts, -+ getopt_long(argc, argv, "p:s:b:hi:lvqe:d:r:u:RnBDP", opts, - NULL)) != -1) { - switch (i) { - case 'b': -@@ -220,6 +223,9 @@ static void parse_command_line(int argc, char **argv) - case 'D': - disable_dontaudit = 1; - break; -+ case 'P': -+ preserve_tunables = 1; -+ break; - case '?': - default:{ - usage(argv[0]); -@@ -466,6 +472,8 @@ int main(int argc, char *argv[]) - semanage_set_disable_dontaudit(sh, 1); - else if (build) - semanage_set_disable_dontaudit(sh, 0); -+ if (preserve_tunables) -+ semanage_set_preserve_tunables(sh, 1); - - result = semanage_commit(sh); - } -diff --git a/policycoreutils/sepolgen-ifgen/.gitignore b/policycoreutils/sepolgen-ifgen/.gitignore -new file mode 100644 -index 0000000..3816d2e ---- /dev/null -+++ b/policycoreutils/sepolgen-ifgen/.gitignore -@@ -0,0 +1 @@ -+sepolgen-ifgen-attr-helper -diff --git a/policycoreutils/sepolgen-ifgen/Makefile b/policycoreutils/sepolgen-ifgen/Makefile -new file mode 100644 -index 0000000..99f8fd0 ---- /dev/null -+++ b/policycoreutils/sepolgen-ifgen/Makefile -@@ -0,0 +1,25 @@ -+# Installation directories. -+PREFIX ?= ${DESTDIR}/usr -+BINDIR ?= $(PREFIX)/bin -+LIBDIR ?= ${PREFIX}/lib -+INCLUDEDIR ?= $(PREFIX)/include -+ -+CFLAGS ?= -Werror -Wall -W -+override CFLAGS += -I$(INCLUDEDIR) -+LDLIBS = $(LIBDIR)/libsepol.a -+ -+all: sepolgen-ifgen-attr-helper -+ -+sepolgen-ifgen-attr-helper: sepolgen-ifgen-attr-helper.o -+ -+install: all -+ -mkdir -p $(BINDIR) -+ install -m 755 sepolgen-ifgen-attr-helper $(BINDIR) -+ -+clean: -+ rm -f *~ *.o sepolgen-ifgen-attr-helper -+ -+indent: -+ ../../scripts/Lindent $(wildcard *.[ch]) -+ -+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..1ce37b0 ---- /dev/null -+++ b/policycoreutils/sepolgen-ifgen/sepolgen-ifgen-attr-helper.c -@@ -0,0 +1,232 @@ -+/* Authors: Frank Mayer -+ * and Karl MacMillan -+ * -+ * Copyright (C) 2003,2010 Tresys Technology, LLC -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation, version 2. -+ * -+ * Adapted from dispol.c. -+ * -+ * This program is used by sepolgen-ifgen to get the access for all of -+ * the attributes in the policy so that it can resolve the -+ * typeattribute statements in the interfaces. -+ * -+ * It outputs the attribute access in a similar format to what sepolgen -+ * uses to store interface vectors: -+ * [Attribute sandbox_x_domain] -+ * sandbox_x_domain,samba_var_t,file,ioctl,read,getattr,lock,open -+ * sandbox_x_domain,samba_var_t,dir,getattr,search,open -+ * sandbox_x_domain,initrc_var_run_t,file,ioctl,read,getattr,lock,open -+ * -+ */ -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+struct val_to_name { -+ unsigned int val; -+ char *name; -+}; -+ -+static int perm_name(hashtab_key_t key, hashtab_datum_t datum, void *data) -+{ -+ struct val_to_name *v = data; -+ perm_datum_t *perdatum; -+ -+ perdatum = (perm_datum_t *) datum; -+ -+ if (v->val == perdatum->s.value) { -+ v->name = key; -+ return 1; -+ } -+ -+ return 0; -+} -+ -+int render_access_mask(uint32_t av, avtab_key_t *key, policydb_t *policydbp, -+ FILE *fp) -+{ -+ struct val_to_name v; -+ class_datum_t *cladatum; -+ char *perm = NULL; -+ unsigned int i; -+ int rc; -+ uint32_t tclass = key->target_class; -+ -+ cladatum = policydbp->class_val_to_struct[tclass - 1]; -+ for (i = 0; i < cladatum->permissions.nprim; i++) { -+ if (av & (1 << i)) { -+ v.val = i + 1; -+ rc = hashtab_map(cladatum->permissions.table, -+ perm_name, &v); -+ if (!rc && cladatum->comdatum) { -+ rc = hashtab_map(cladatum->comdatum-> -+ permissions.table, perm_name, -+ &v); -+ } -+ if (rc) -+ perm = v.name; -+ if (perm) { -+ fprintf(fp, ",%s", perm); -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static int render_key(avtab_key_t *key, policydb_t *p, FILE *fp) -+{ -+ char *stype, *ttype, *tclass; -+ stype = p->p_type_val_to_name[key->source_type - 1]; -+ ttype = p->p_type_val_to_name[key->target_type - 1]; -+ tclass = p->p_class_val_to_name[key->target_class - 1]; -+ if (stype && ttype) { -+ fprintf(fp, "%s,%s,%s", stype, ttype, tclass); -+ } else { -+ fprintf(stderr, "error rendering key\n"); -+ exit(1); -+ } -+ -+ return 0; -+} -+ -+struct callback_data -+{ -+ uint32_t attr; -+ policydb_t *policy; -+ FILE *fp; -+}; -+ -+int output_avrule(avtab_key_t *key, avtab_datum_t *datum, void *args) -+{ -+ struct callback_data *cb_data = (struct callback_data *)args; -+ -+ if (key->source_type != cb_data->attr) -+ return 0; -+ -+ if (!(key->specified & AVTAB_AV && key->specified & AVTAB_ALLOWED)) -+ return 0; -+ -+ render_key(key, cb_data->policy, cb_data->fp); -+ render_access_mask(datum->data, key, cb_data->policy, cb_data->fp); -+ fprintf(cb_data->fp, "\n"); -+ -+ return 0; -+} -+ -+static int attribute_callback(hashtab_key_t key, hashtab_datum_t datum, void *datap) -+{ -+ struct callback_data *cb_data = (struct callback_data *)datap; -+ type_datum_t *t = (type_datum_t *)datum; -+ -+ if (t->flavor == TYPE_ATTRIB) { -+ fprintf(cb_data->fp, "[Attribute %s]\n", key); -+ cb_data->attr = t->s.value; -+ if (avtab_map(&cb_data->policy->te_avtab, output_avrule, cb_data) < 0) -+ return -1; -+ if (avtab_map(&cb_data->policy->te_cond_avtab, output_avrule, cb_data) < 0) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static policydb_t *load_policy(const char *filename) -+{ -+ policydb_t *policydb; -+ struct policy_file pf; -+ FILE *fp; -+ int ret; -+ -+ fp = fopen(filename, "r"); -+ if (fp == NULL) { -+ fprintf(stderr, "Can't open '%s': %s\n", -+ filename, strerror(errno)); -+ return NULL; -+ } -+ -+ policy_file_init(&pf); -+ pf.type = PF_USE_STDIO; -+ pf.fp = fp; -+ -+ policydb = malloc(sizeof(policydb_t)); -+ if (policydb == NULL) { -+ fprintf(stderr, "Out of memory!\n"); -+ return NULL; -+ } -+ -+ if (policydb_init(policydb)) { -+ fprintf(stderr, "Out of memory!\n"); -+ free(policydb); -+ return NULL; -+ } -+ -+ ret = policydb_read(policydb, &pf, 1); -+ if (ret) { -+ fprintf(stderr, -+ "error(s) encountered while parsing configuration\n"); -+ free(policydb); -+ return NULL; -+ } -+ -+ fclose(fp); -+ -+ return policydb; -+ -+} -+ -+void usage(char *progname) -+{ -+ printf("usage: %s policy_file out_file\n", progname); -+} -+ -+int main(int argc, char **argv) -+{ -+ policydb_t *p; -+ struct callback_data cb_data; -+ FILE *fp; -+ -+ if (argc != 3) { -+ usage(argv[0]); -+ return -1; -+ } -+ -+ /* Open the policy. */ -+ p = load_policy(argv[1]); -+ if (p == NULL) -+ return -1; -+ -+ /* Open the output policy. */ -+ fp = fopen(argv[2], "w"); -+ if (fp == NULL) { -+ fprintf(stderr, "error opening output file\n"); -+ policydb_destroy(p); -+ free(p); -+ return -1; -+ } -+ -+ /* Find all of the attributes and output their access. */ -+ cb_data.policy = p; -+ cb_data.fp = fp; -+ -+ if (hashtab_map(p->p_types.table, attribute_callback, &cb_data)) { -+ printf("error finding attributes\n"); -+ } -+ -+ policydb_destroy(p); -+ free(p); -+ fclose(fp); -+ -+ return 0; -+} + indent: + ../../scripts/Lindent $(wildcard *.[ch]) diff --git a/policycoreutils/setfiles/restore.c b/policycoreutils/setfiles/restore.c -index 48ffcad..8066162 100644 +index ce44c04..8066162 100644 --- a/policycoreutils/setfiles/restore.c +++ b/policycoreutils/setfiles/restore.c @@ -1,5 +1,6 @@ @@ -3733,18 +1941,7 @@ index 48ffcad..8066162 100644 if (match(my_file, ftsent->fts_statp, &newcon) < 0) /* Check for no matching specification. */ -@@ -113,10 +113,6 @@ static int restore(FTSENT *ftsent) - - if (r_opts->progress) { - r_opts->count++; -- if (r_opts->count % (80 * STAR_COUNT) == 0) { -- fprintf(stdout, "\n"); -- fflush(stdout); -- } - if (r_opts->count % STAR_COUNT == 0) { - fprintf(stdout, "*"); - fflush(stdout); -@@ -143,74 +139,105 @@ static int restore(FTSENT *ftsent) +@@ -139,74 +139,105 @@ static int restore(FTSENT *ftsent) printf("%s: %s matched by %s\n", r_opts->progname, my_file, newcon); } @@ -3838,22 +2035,22 @@ index 48ffcad..8066162 100644 + freecon(newcon); + newcon = strdup(context_str(conb)); + } - } ++ } + context_free(cona); + context_free(conb); + + if (!types_differ || err) { + goto out; -+ } -+ } -+ -+ if (r_opts->verbose) { -+ printf("%s reset %s context %s->%s\n", -+ r_opts->progname, my_file, curcon ?: "", newcon); + } } - if (r_opts->logging && !user_only_changed) { - if (context) ++ if (r_opts->verbose) { ++ printf("%s reset %s context %s->%s\n", ++ r_opts->progname, my_file, curcon ?: "", newcon); ++ } ++ + if (r_opts->logging) { + if (curcon) syslog(LOG_INFO, "relabeling %s from %s to %s\n", @@ -3879,45 +2076,7 @@ index 48ffcad..8066162 100644 goto out; /* -@@ -318,11 +345,16 @@ static int process_one(char *name, int recurse_this_path) - - - ftsent = fts_read(fts_handle); -- if (ftsent != NULL) { -- /* Keep the inode of the first one. */ -- dev_num = ftsent->fts_statp->st_dev; -+ if (ftsent == NULL) { -+ fprintf(stderr, -+ "%s: error while labeling %s: %s\n", -+ r_opts->progname, namelist[0], strerror(errno)); -+ goto err; - } - -+ /* Keep the inode of the first one. */ -+ dev_num = ftsent->fts_statp->st_dev; -+ - do { - rc = 0; - /* Skip the post order nodes. */ -@@ -390,7 +422,7 @@ int process_one_realpath(char *name, int recurse) - { - int rc = 0; - char *p; -- struct stat sb; -+ struct stat64 sb; - - if (r_opts == NULL){ - fprintf(stderr, -@@ -401,7 +433,7 @@ int process_one_realpath(char *name, int recurse) - if (!r_opts->expand_realpath) { - return process_one(name, recurse); - } else { -- rc = lstat(name, &sb); -+ rc = lstat64(name, &sb); - if (rc < 0) { - if (r_opts->ignore_enoent && errno == ENOENT) - return 0; -@@ -486,22 +518,6 @@ int add_exclude(const char *directory) +@@ -487,22 +518,6 @@ int add_exclude(const char *directory) return 0; } @@ -3940,24 +2099,6 @@ index 48ffcad..8066162 100644 /* * Evaluate the association hash table distribution. */ -@@ -568,7 +584,7 @@ static int filespec_add(ino_t ino, const security_context_t con, const char *fil - { - file_spec_t *prevfl, *fl; - int h, ret; -- struct stat sb; -+ struct stat64 sb; - - if (!fl_head) { - fl_head = malloc(sizeof(file_spec_t) * HASH_BUCKETS); -@@ -581,7 +597,7 @@ static int filespec_add(ino_t ino, const security_context_t con, const char *fil - for (prevfl = &fl_head[h], fl = fl_head[h].next; fl; - prevfl = fl, fl = fl->next) { - if (ino == fl->ino) { -- ret = lstat(fl->file, &sb); -+ ret = lstat64(fl->file, &sb); - if (ret < 0 || sb.st_ino != ino) { - freecon(fl->con); - free(fl->file); diff --git a/policycoreutils/setfiles/restore.h b/policycoreutils/setfiles/restore.h index ac27222..3909d15 100644 --- a/policycoreutils/setfiles/restore.h diff --git a/policycoreutils-sepolgen.patch b/policycoreutils-sepolgen.patch index 3ca80c7..03f07da 100644 --- a/policycoreutils-sepolgen.patch +++ b/policycoreutils-sepolgen.patch @@ -1,51 +1,3 @@ -diff --git a/sepolgen/src/sepolgen/access.py b/sepolgen/src/sepolgen/access.py -index 3eda2fd..649735f 100644 ---- a/sepolgen/src/sepolgen/access.py -+++ b/sepolgen/src/sepolgen/access.py -@@ -32,6 +32,7 @@ in a variety of ways, but they are the fundamental representation of access. - """ - - import refpolicy -+from selinux import audit2why - - def is_idparam(id): - """Determine if an id is a paramater in the form $N, where N is -@@ -85,6 +86,8 @@ class AccessVector: - self.obj_class = None - self.perms = refpolicy.IdSet() - self.audit_msgs = [] -+ self.type = audit2why.TERULE -+ self.bools = [] - - # The direction of the information flow represented by this - # access vector - used for matching -@@ -253,20 +256,22 @@ class AccessVectorSet: - for av in l: - self.add_av(AccessVector(av)) - -- def add(self, src_type, tgt_type, obj_class, perms, audit_msg=None): -+ def add(self, src_type, tgt_type, obj_class, perms, audit_msg=None, avc_type=audit2why.TERULE, bools=[]): - """Add an access vector to the set. - """ - tgt = self.src.setdefault(src_type, { }) - cls = tgt.setdefault(tgt_type, { }) - -- if cls.has_key(obj_class): -- access = cls[obj_class] -+ if cls.has_key((obj_class, avc_type)): -+ access = cls[obj_class, avc_type] - else: - access = AccessVector() - access.src_type = src_type - access.tgt_type = tgt_type - access.obj_class = obj_class -- cls[obj_class] = access -+ access.bools = bools -+ access.type = avc_type -+ cls[obj_class, avc_type] = access - - access.perms.update(perms) - if audit_msg: diff --git a/sepolgen/src/sepolgen/audit.py b/sepolgen/src/sepolgen/audit.py index 24e308e..e23725f 100644 --- a/sepolgen/src/sepolgen/audit.py @@ -133,139 +85,6 @@ index 24e308e..e23725f 100644 return av_set class AVCTypeFilter: -diff --git a/sepolgen/src/sepolgen/defaults.py b/sepolgen/src/sepolgen/defaults.py -index 45ce61a..6d511c3 100644 ---- a/sepolgen/src/sepolgen/defaults.py -+++ b/sepolgen/src/sepolgen/defaults.py -@@ -30,6 +30,9 @@ def perm_map(): - def interface_info(): - return data_dir() + "/interface_info" - -+def attribute_info(): -+ return data_dir() + "/attribute_info" -+ - def refpolicy_devel(): - return "/usr/share/selinux/devel" - -diff --git a/sepolgen/src/sepolgen/interfaces.py b/sepolgen/src/sepolgen/interfaces.py -index d8b3e34..ae1c9c5 100644 ---- a/sepolgen/src/sepolgen/interfaces.py -+++ b/sepolgen/src/sepolgen/interfaces.py -@@ -29,6 +29,8 @@ import matching - - from sepolgeni18n import _ - -+import copy -+ - class Param: - """ - Object representing a paramater for an interface. -@@ -197,10 +199,48 @@ def ifcall_extract_params(ifcall, params): - ret = 1 - - return ret -- -+ -+class AttributeVector: -+ def __init__(self): -+ self.name = "" -+ self.access = access.AccessVectorSet() -+ -+ def add_av(self, av): -+ self.access.add_av(av) -+ -+class AttributeSet: -+ def __init__(self): -+ self.attributes = { } -+ -+ def add_attr(self, attr): -+ self.attributes[attr.name] = attr -+ -+ def from_file(self, fd): -+ def parse_attr(line): -+ fields = line[1:-1].split() -+ if len(fields) != 2 or fields[0] != "Attribute": -+ raise SyntaxError("Syntax error Attribute statement %s" % line) -+ a = AttributeVector() -+ a.name = fields[1] -+ -+ return a -+ -+ a = None -+ for line in fd: -+ line = line[:-1] -+ if line[0] == "[": -+ if a: -+ self.add_attr(a) -+ a = parse_attr(line) -+ elif a: -+ l = line.split(",") -+ av = access.AccessVector(l) -+ a.add_av(av) -+ if a: -+ self.add_attr(a) - - class InterfaceVector: -- def __init__(self, interface=None): -+ def __init__(self, interface=None, attributes={}): - # Enabled is a loose concept currently - we are essentially - # not enabling interfaces that we can't handle currently. - # See InterfaceVector.add_ifv for more information. -@@ -214,10 +254,10 @@ class InterfaceVector: - # value: Param object). - self.params = { } - if interface: -- self.from_interface(interface) -+ self.from_interface(interface, attributes) - self.expanded = False - -- def from_interface(self, interface): -+ def from_interface(self, interface, attributes={}): - self.name = interface.name - - # Add allow rules -@@ -232,6 +272,23 @@ class InterfaceVector: - for av in avs: - self.add_av(av) - -+ # Add typeattribute access -+ if attributes != None: -+ for typeattribute in interface.typeattributes(): -+ for attr in typeattribute.attributes: -+ if not attributes.attributes.has_key(attr): -+ # print "missing attribute " + attr -+ continue -+ attr_vec = attributes.attributes[attr] -+ for a in attr_vec.access: -+ av = copy.copy(a) -+ if av.src_type == attr_vec.name: -+ av.src_type = typeattribute.type -+ if av.tgt_type == attr_vec.name: -+ av.tgt_type = typeattribute.type -+ self.add_av(av) -+ -+ - # Extract paramaters from roles - for role in interface.roles(): - if role_extract_params(role, self.params): -@@ -346,13 +403,13 @@ class InterfaceSet: - l = self.tgt_type_map.setdefault(type, []) - l.append(ifv) - -- def add(self, interface): -- ifv = InterfaceVector(interface) -+ def add(self, interface, attributes={}): -+ ifv = InterfaceVector(interface, attributes) - self.add_ifv(ifv) - -- def add_headers(self, headers, output=None): -+ def add_headers(self, headers, output=None, attributes={}): - for i in itertools.chain(headers.interfaces(), headers.templates()): -- self.add(i) -+ self.add(i, attributes) - - self.expand_ifcalls(headers) - self.index() diff --git a/sepolgen/src/sepolgen/matching.py b/sepolgen/src/sepolgen/matching.py index 1a9a3e5..d56dd92 100644 --- a/sepolgen/src/sepolgen/matching.py @@ -298,21 +117,6 @@ index 1a9a3e5..d56dd92 100644 def __iter__(self): return iter(self.children) -diff --git a/sepolgen/src/sepolgen/module.py b/sepolgen/src/sepolgen/module.py -index edd24c6..5818cec 100644 ---- a/sepolgen/src/sepolgen/module.py -+++ b/sepolgen/src/sepolgen/module.py -@@ -37,8 +37,8 @@ import shutil - def is_valid_name(modname): - """Check that a module name is valid. - """ -- m = re.findall("[^a-zA-Z0-9]", modname) -- if len(m) == 0: -+ m = re.findall("[^a-zA-Z0-9_\-\.]", modname) -+ if len(m) == 0 and modname[0].isalpha(): - return True - else: - return False diff --git a/sepolgen/src/sepolgen/policygen.py b/sepolgen/src/sepolgen/policygen.py index 0e6b502..6ce892c 100644 --- a/sepolgen/src/sepolgen/policygen.py @@ -377,136 +181,3 @@ index 0e6b502..6ce892c 100644 self.module.children.append(rule) -diff --git a/sepolgen/src/share/perm_map b/sepolgen/src/share/perm_map -index eb2e23b..ca4fa4d 100644 ---- a/sepolgen/src/share/perm_map -+++ b/sepolgen/src/share/perm_map -@@ -124,7 +124,7 @@ class filesystem 10 - quotamod w 1 - quotaget r 1 - --class file 20 -+class file 21 - execute_no_trans r 1 - entrypoint r 1 - execmod n 1 -@@ -141,48 +141,50 @@ class file 20 - unlink w 1 - link w 1 - rename w 5 -- execute r 100 -+ execute r 10 - swapon b 1 - quotaon b 1 - mounton b 1 -+ open r 1 - --class dir 22 -- add_name w 5 -+class dir 23 -+ add_name w 1 - remove_name w 1 - reparent w 1 - search r 1 - rmdir b 1 - ioctl n 1 -- read r 10 -- write w 10 -+ read r 1 -+ write w 1 - create w 1 -- getattr r 7 -- setattr w 7 -+ getattr r 1 -+ setattr w 1 - lock n 1 -- relabelfrom r 10 -- relabelto w 10 -+ relabelfrom r 1 -+ relabelto w 1 - append w 1 - unlink w 1 - link w 1 -- rename w 5 -+ rename w 1 - execute r 1 - swapon b 1 - quotaon b 1 - mounton b 1 -+ open r 1 - - class fd 1 - use b 1 - --class lnk_file 17 -+class lnk_file 18 - ioctl n 1 -- read r 10 -- write w 10 -+ read r 1 -+ write w 1 - create w 1 -- getattr r 7 -- setattr w 7 -+ getattr r 1 -+ setattr w 1 - lock n 1 -- relabelfrom r 10 -- relabelto w 10 -+ relabelfrom r 1 -+ relabelto w 1 - append w 1 - unlink w 1 - link w 1 -@@ -191,8 +193,9 @@ class lnk_file 17 - swapon b 1 - quotaon b 1 - mounton b 1 -+ open r 1 - --class chr_file 20 -+class chr_file 21 - execute_no_trans r 1 - entrypoint r 1 - execmod n 1 -@@ -213,8 +216,9 @@ class chr_file 20 - swapon b 1 - quotaon b 1 - mounton b 1 -+ open r 1 - --class blk_file 17 -+class blk_file 18 - ioctl n 1 - read r 10 - write w 10 -@@ -232,8 +236,9 @@ class blk_file 17 - swapon b 1 - quotaon b 1 - mounton b 1 -+ open r 1 - --class sock_file 17 -+class sock_file 18 - ioctl n 1 - read r 10 - write w 10 -@@ -251,8 +256,9 @@ class sock_file 17 - swapon b 1 - quotaon b 1 - mounton b 1 -+ open r 1 - --class fifo_file 17 -+class fifo_file 18 - ioctl n 1 - read r 10 - write w 10 -@@ -270,6 +276,7 @@ class fifo_file 17 - swapon b 1 - quotaon b 1 - mounton b 1 -+ open r 1 - - class socket 22 - ioctl n 1 diff --git a/policycoreutils.spec b/policycoreutils.spec index d95751f..8df8ef6 100644 --- a/policycoreutils.spec +++ b/policycoreutils.spec @@ -1,13 +1,13 @@ %define libauditver 1.4.2-1 -%define libsepolver 2.1.2-1 -%define libsemanagever 2.1.2-1 -%define libselinuxver 2.1.5-2 -%define sepolgenver 1.1.1 +%define libsepolver 2.1.2-3 +%define libsemanagever 2.1.4-1 +%define libselinuxver 2.1.5-5 +%define sepolgenver 1.1.2 Summary: SELinux policy core utilities Name: policycoreutils -Version: 2.1.5 -Release: 6%{?dist} +Version: 2.1.6 +Release: 1%{?dist} License: GPLv2 Group: System Environment/Base # Based on git repository with tag 20101221 @@ -352,6 +352,36 @@ fi /bin/systemctl try-restart restorecond.service >/dev/null 2>&1 || : %changelog +* Mon Sep 19 2011 Dan Walsh - 2.1.6-1 +-Update to upstream + policycoreutils-2.1.6 + * sepolgen-ifgen: new attr-helper does something + * audit2allow: use alternate policy file + * audit2allow: sepolgen-ifgen use the attr helper + * setfiles: switch from stat to stat64 + * setfiles: Fix potential crash using dereferenced ftsent + * setfiles: do not wrap * output at 80 characters + * sandbox: add -Wall and -Werror to makefile + * sandbox: add sandbox cgroup support + * sandbox: rewrite /tmp handling + * sandbox: do not bind mount so much + * sandbox: add level based kill option + * sandbox: cntrl-c should kill entire process control group + * Create a new preserve_tunables flag in sepol_handle_t. + * semanage: show running and disk setting for booleans + * semanage: Dont print heading if no items selected + * sepolgen: audit2allow is mistakakenly not allowing valid module names + * semanage: Catch RuntimeErrors, that can be generated when SELinux is disabled + * More files to ignore + * tree: default make target to all not install + * sandbox: do not load unused generic init functions + sepolgen-1.1.2 + * src: sepolgen: add attribute storing infrastructure + * Change perm-map and add open to try to get better results on + * look for booleans that might solve problems + * sepolgen: audit2allow is mistakakenly not allowing valid module names + * tree: default make target to all not install + * Wed Sep 14 2011 Dan Walsh - 2.1.5-6 - Change separator on -L from ; to : diff --git a/sources b/sources index 69b7e4a..0fc6095 100644 --- a/sources +++ b/sources @@ -1,3 +1,3 @@ 59d33101d57378ce69889cc078addf90 policycoreutils_man_ru2.tar.bz2 -fcff0d994c5106e04190432304b1e8c6 sepolgen-1.1.1.tgz -a84ec479bf09e8d2a912fd32532853e9 policycoreutils-2.1.5.tgz +c372e90a754ee87e1cc40b09134b8f31 sepolgen-1.1.2.tgz +e62d247400005126df7d36d2ce24b48b policycoreutils-2.1.6.tgz