* Add modules support to semanage @ 2009-09-30 18:33 Daniel J Walsh 2009-11-11 18:52 ` Chad Sellers 0 siblings, 1 reply; 9+ messages in thread From: Daniel J Walsh @ 2009-09-30 18:33 UTC (permalink / raw) To: SE Linux [-- Attachment #1: Type: text/plain, Size: 30 bytes --] Includes enable and disable. [-- Attachment #2: modules.patch --] [-- Type: text/plain, Size: 7081 bytes --] diff --git a/policycoreutils/semanage/semanage b/policycoreutils/semanage/semanage index 437eca3..128ab47 100644 --- a/policycoreutils/semanage/semanage +++ b/policycoreutils/semanage/semanage @@ -44,11 +44,12 @@ if __name__ == '__main__': text = _(""" semanage [ -S store ] -i [ input_file | - ] -semanage {boolean|login|user|port|interface|node|fcontext} -{l|D} [-n] +semanage {boolean|login|user|port|interface|module|node|fcontext} -{l|D} [-n] semanage login -{a|d|m} [-sr] login_name | %groupname semanage user -{a|d|m} [-LrRP] selinux_name semanage port -{a|d|m} [-tr] [ -p proto ] port | port_range semanage interface -{a|d|m} [-tr] interface_spec +semanage module -{a|d|m} [--enable|--disable] module semanage node -{a|d|m} [-tr] [ -p protocol ] [-M netmask] addr semanage fcontext -{a|d|m} [-frst] file_spec semanage boolean -{d|m} [--on|--off|-1|-0] -F boolean | boolean_file @@ -90,6 +91,8 @@ Object-specific Options (see above): -s, --seuser SELinux User Name -t, --type SELinux Type for the object -r, --range MLS/MCS Security Range (MLS/MCS Systems only) + --enable Enable a module + --disable Disable a module """) raise ValueError("%s\n%s" % (text, message)) @@ -110,6 +113,8 @@ Object-specific Options (see above): valid_option["port"] += valid_everyone + [ '-t', '--type', '-r', '--range', '-p', '--proto' ] valid_option["interface"] = [] valid_option["interface"] += valid_everyone + [ '-t', '--type', '-r', '--range'] + valid_option["module"] = [] + valid_option["module"] += valid_everyone + [ '--enable', '--disable'] valid_option["node"] = [] valid_option["node"] += valid_everyone + [ '-M', '--mask', '-t', '--type', '-r', '--range', '-p', '--protocol'] valid_option["fcontext"] = [] @@ -188,6 +193,8 @@ Object-specific Options (see above): locallist = False use_file = False store = "" + enable = False + disable = False object = argv[0] option_dict=get_options() @@ -240,6 +247,18 @@ Object-specific Options (see above): if modify: raise ValueError(_("%s bad option") % o) deleteall = True + + if o == "--enable": + if disable: + raise ValueError(_("You can't disable and enable at the same time")) + + enable = True + + if o == "--disable": + if enable: + raise ValueError(_("You can't disable and enable at the same time")) + disable = True + if o == "-f" or o == "--ftype": ftype=a @@ -307,6 +326,9 @@ Object-specific Options (see above): if object == "interface": OBJECT = seobject.interfaceRecords(store) + if object == "module": + OBJECT = seobject.moduleRecords(store) + if object == "node": OBJECT = seobject.nodeRecords(store) @@ -355,6 +377,9 @@ Object-specific Options (see above): if object == "interface": OBJECT.add(target, serange, setype) + if object == "module": + OBJECT.add(target) + if object == "node": OBJECT.add(target, mask, proto, serange, setype) @@ -382,6 +407,14 @@ Object-specific Options (see above): if object == "interface": OBJECT.modify(target, serange, setype) + if object == "module": + if enable: + OBJECT.enable(target) + elif disable: + OBJECT.disable(target) + else: + OBJECT.modify(target) + if object == "node": OBJECT.modify(target, mask, proto, serange, setype) diff --git a/policycoreutils/semanage/seobject.py b/policycoreutils/semanage/seobject.py index 7c94da0..4d36660 100644 --- a/policycoreutils/semanage/seobject.py +++ b/policycoreutils/semanage/seobject.py @@ -233,6 +233,77 @@ class semanageRecords: self.transaction = False self.commit() +class moduleRecords(semanageRecords): + def __init__(self, store): + semanageRecords.__init__(self, store) + + def get_all(self): + l = [] + (rc, mlist, number) = semanage_module_list(self.sh) + if rc < 0: + raise ValueError(_("Could not list SELinux modules")) + + for i in range(number): + mod = semanage_module_list_nth(mlist, i) + l.append((semanage_module_get_name(mod), semanage_module_get_version(mod), semanage_module_get_enabled(mod))) + return l + + def list(self, heading = 1, locallist = 0): + if heading: + print "\n%-25s%-10s\n" % (_("Modules Name"), _("Version")) + for t in self.get_all(): + if t[2] == 0: + disabled = _("Disabled") + else: + disabled = "" + print "%-25s%-10s%s" % (t[0], t[1], disabled) + + def add(self, file): + rc = semanage_module_install_file(self.sh, file); + if rc >= 0: + self.commit() + + def disable(self, module): + need_commit = False + for m in module.split(): + rc = semanage_module_disable(self.sh, m) + if rc < 0 and rc != -3: + raise ValueError(_("Could not disable module %s (remove failed)") % m) + if rc != -3: + need_commit = True + if need_commit: + self.commit() + + def enable(self, module): + need_commit = False + for m in module.split(): + rc = semanage_module_enable(self.sh, m) + if rc < 0 and rc != -3: + raise ValueError(_("Could not enable module %s (remove failed)") % m) + if rc != -3: + need_commit = True + if need_commit: + self.commit() + + def modify(self, file): + rc = semanage_module_update_file(self.sh, file); + if rc >= 0: + self.commit() + + def delete(self, module): + for m in module.split(): + rc = semanage_module_remove(self.sh, m) + if rc < 0 and rc != -2: + raise ValueError(_("Could not remove module %s (remove failed)") % m) + + self.commit() + + def deleteall(self): + l = self.get_all() + if len(l) > 0: + all = " ".join(l[0]) + self.delete(all) + class dontauditClass(semanageRecords): def __init__(self, store): semanageRecords.__init__(self, store) ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: Add modules support to semanage 2009-09-30 18:33 Add modules support to semanage Daniel J Walsh @ 2009-11-11 18:52 ` Chad Sellers 2009-11-12 16:23 ` Daniel J Walsh ` (2 more replies) 0 siblings, 3 replies; 9+ messages in thread From: Chad Sellers @ 2009-11-11 18:52 UTC (permalink / raw) To: Daniel J Walsh, SE Linux On 9/30/09 2:33 PM, "Daniel J Walsh" <dwalsh@redhat.com> wrote: > Includes enable and disable. > I presume I should hold off on this patch until you have a chance to resubmit the libsemanage support that it relies on. Let me know if that's not the case. Thanks, Chad -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Add modules support to semanage 2009-11-11 18:52 ` Chad Sellers @ 2009-11-12 16:23 ` Daniel J Walsh 2009-11-18 20:24 ` Chad Sellers 2009-11-12 16:45 ` Daniel J Walsh 2009-11-12 16:46 ` Daniel J Walsh 2 siblings, 1 reply; 9+ messages in thread From: Daniel J Walsh @ 2009-11-12 16:23 UTC (permalink / raw) To: Chad Sellers; +Cc: SE Linux [-- Attachment #1: Type: text/plain, Size: 414 bytes --] On 11/11/2009 01:52 PM, Chad Sellers wrote: > On 9/30/09 2:33 PM, "Daniel J Walsh" <dwalsh@redhat.com> wrote: > >> Includes enable and disable. >> > I presume I should hold off on this patch until you have a chance to > resubmit the libsemanage support that it relies on. Let me know if that's > not the case. > > Thanks, > Chad > Lets do this patch. Moves load_policy from /usr/sbin to /sbin Removed cruft. [-- Attachment #2: selinux_load_policy.patch --] [-- Type: text/plain, Size: 1403 bytes --] diff --git a/libsemanage/src/conf-parse.y b/libsemanage/src/conf-parse.y index 23661bf..931448f 100644 --- a/libsemanage/src/conf-parse.y +++ b/libsemanage/src/conf-parse.y @@ -263,7 +263,13 @@ static int semanage_conf_init(semanage_conf_t * conf) calloc(1, sizeof(*(current_conf->load_policy)))) == NULL) { return -1; } - if ((conf->load_policy->path = strdup("/usr/sbin/load_policy")) == NULL) { + + if (access("/sbin/load_policy", X_OK) == 0) { + conf->load_policy->path = strdup("/sbin/load_policy"); + } else { + conf->load_policy->path = strdup("/usr/sbin/load_policy"); + } + if (conf->load_policy->path == NULL) return -1; } conf->load_policy->args = NULL; diff --git a/policycoreutils/load_policy/Makefile b/policycoreutils/load_policy/Makefile index 2dd2943..91dc6c8 100644 --- a/policycoreutils/load_policy/Makefile +++ b/policycoreutils/load_policy/Makefile @@ -1,6 +1,7 @@ # Installation directories. PREFIX ?= ${DESTDIR}/usr -SBINDIR ?= $(PREFIX)/sbin +SBINDIR ?= $(DESTDIR)/sbin +USRSBINDIR ?= $(PREFIX)/sbin MANDIR ?= $(PREFIX)/share/man LOCALEDIR ?= /usr/share/locale @@ -17,6 +18,8 @@ install: all install -m 755 $(TARGETS) $(SBINDIR) test -d $(MANDIR)/man8 || install -m 755 -d $(MANDIR)/man8 install -m 644 load_policy.8 $(MANDIR)/man8/ + -mkdir -p $(USRSBINDIR) + ln -s /sbin/load_policy $(USRSBINDIR)/load_policy clean: -rm -f $(TARGETS) *.o ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: Add modules support to semanage 2009-11-12 16:23 ` Daniel J Walsh @ 2009-11-18 20:24 ` Chad Sellers 2009-11-18 20:28 ` Daniel J Walsh 0 siblings, 1 reply; 9+ messages in thread From: Chad Sellers @ 2009-11-18 20:24 UTC (permalink / raw) To: Daniel J Walsh; +Cc: SE Linux On 11/12/09 11:23 AM, "Daniel J Walsh" <dwalsh@redhat.com> wrote: > On 11/11/2009 01:52 PM, Chad Sellers wrote: >> On 9/30/09 2:33 PM, "Daniel J Walsh" <dwalsh@redhat.com> wrote: >> >>> Includes enable and disable. >>> >> I presume I should hold off on this patch until you have a chance to >> resubmit the libsemanage support that it relies on. Let me know if that's >> not the case. >> >> Thanks, >> Chad >> > Lets do this patch. > > > Moves load_policy from /usr/sbin to /sbin > > Removed cruft. > > diff --git a/libsemanage/src/conf-parse.y b/libsemanage/src/conf-parse.y > index 23661bf..931448f 100644 > --- a/libsemanage/src/conf-parse.y > +++ b/libsemanage/src/conf-parse.y > @@ -263,7 +263,13 @@ static int semanage_conf_init(semanage_conf_t * conf) > calloc(1, sizeof(*(current_conf->load_policy)))) == NULL) { > return -1; > } > - if ((conf->load_policy->path = strdup("/usr/sbin/load_policy")) == NULL) > { > + > + if (access("/sbin/load_policy", X_OK) == 0) { > + conf->load_policy->path = strdup("/sbin/load_policy"); > + } else { > + conf->load_policy->path = strdup("/usr/sbin/load_policy"); > + } > + if (conf->load_policy->path == NULL) Still missing a curly brace. > return -1; > } > conf->load_policy->args = NULL; > diff --git a/policycoreutils/load_policy/Makefile > b/policycoreutils/load_policy/Makefile > index 2dd2943..91dc6c8 100644 > --- a/policycoreutils/load_policy/Makefile > +++ b/policycoreutils/load_policy/Makefile > @@ -1,6 +1,7 @@ > # Installation directories. > PREFIX ?= ${DESTDIR}/usr > -SBINDIR ?= $(PREFIX)/sbin > +SBINDIR ?= $(DESTDIR)/sbin > +USRSBINDIR ?= $(PREFIX)/sbin > MANDIR ?= $(PREFIX)/share/man > LOCALEDIR ?= /usr/share/locale > > @@ -17,6 +18,8 @@ install: all > install -m 755 $(TARGETS) $(SBINDIR) > test -d $(MANDIR)/man8 || install -m 755 -d $(MANDIR)/man8 > install -m 644 load_policy.8 $(MANDIR)/man8/ > + -mkdir -p $(USRSBINDIR) > + ln -s /sbin/load_policy $(USRSBINDIR)/load_policy > Still using -s instead of -sf. You never responded to my previous email ( http://marc.info/?l=selinux&m=125788814205762&w=2 ). Are you ok with these 2 fixes? If so, I can make the changes and merge this. Thanks, Chad > clean: > -rm -f $(TARGETS) *.o -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Add modules support to semanage 2009-11-18 20:24 ` Chad Sellers @ 2009-11-18 20:28 ` Daniel J Walsh 2009-11-18 21:53 ` Chad Sellers 0 siblings, 1 reply; 9+ messages in thread From: Daniel J Walsh @ 2009-11-18 20:28 UTC (permalink / raw) To: Chad Sellers; +Cc: SE Linux On 11/18/2009 03:24 PM, Chad Sellers wrote: > On 11/12/09 11:23 AM, "Daniel J Walsh" <dwalsh@redhat.com> wrote: > >> On 11/11/2009 01:52 PM, Chad Sellers wrote: >>> On 9/30/09 2:33 PM, "Daniel J Walsh" <dwalsh@redhat.com> wrote: >>> >>>> Includes enable and disable. >>>> >>> I presume I should hold off on this patch until you have a chance to >>> resubmit the libsemanage support that it relies on. Let me know if that's >>> not the case. >>> >>> Thanks, >>> Chad >>> >> Lets do this patch. >> >> >> Moves load_policy from /usr/sbin to /sbin >> >> Removed cruft. >> >> diff --git a/libsemanage/src/conf-parse.y b/libsemanage/src/conf-parse.y >> index 23661bf..931448f 100644 >> --- a/libsemanage/src/conf-parse.y >> +++ b/libsemanage/src/conf-parse.y >> @@ -263,7 +263,13 @@ static int semanage_conf_init(semanage_conf_t * conf) >> calloc(1, sizeof(*(current_conf->load_policy)))) == NULL) { >> return -1; >> } >> - if ((conf->load_policy->path = strdup("/usr/sbin/load_policy")) == NULL) >> { >> + >> + if (access("/sbin/load_policy", X_OK) == 0) { >> + conf->load_policy->path = strdup("/sbin/load_policy"); >> + } else { >> + conf->load_policy->path = strdup("/usr/sbin/load_policy"); >> + } >> + if (conf->load_policy->path == NULL) > > Still missing a curly brace. > >> return -1; >> } >> conf->load_policy->args = NULL; >> diff --git a/policycoreutils/load_policy/Makefile >> b/policycoreutils/load_policy/Makefile >> index 2dd2943..91dc6c8 100644 >> --- a/policycoreutils/load_policy/Makefile >> +++ b/policycoreutils/load_policy/Makefile >> @@ -1,6 +1,7 @@ >> # Installation directories. >> PREFIX ?= ${DESTDIR}/usr >> -SBINDIR ?= $(PREFIX)/sbin >> +SBINDIR ?= $(DESTDIR)/sbin >> +USRSBINDIR ?= $(PREFIX)/sbin >> MANDIR ?= $(PREFIX)/share/man >> LOCALEDIR ?= /usr/share/locale >> >> @@ -17,6 +18,8 @@ install: all >> install -m 755 $(TARGETS) $(SBINDIR) >> test -d $(MANDIR)/man8 || install -m 755 -d $(MANDIR)/man8 >> install -m 644 load_policy.8 $(MANDIR)/man8/ >> + -mkdir -p $(USRSBINDIR) >> + ln -s /sbin/load_policy $(USRSBINDIR)/load_policy >> > Still using -s instead of -sf. You never responded to my previous email ( > http://marc.info/?l=selinux&m=125788814205762&w=2 ). Are you ok with these 2 > fixes? If so, I can make the changes and merge this. > > Thanks, > Chad > >> clean: >> -rm -f $(TARGETS) *.o > Yes go ahead. -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Add modules support to semanage 2009-11-18 20:28 ` Daniel J Walsh @ 2009-11-18 21:53 ` Chad Sellers 0 siblings, 0 replies; 9+ messages in thread From: Chad Sellers @ 2009-11-18 21:53 UTC (permalink / raw) To: Daniel J Walsh; +Cc: SE Linux On 11/18/09 3:28 PM, "Daniel J Walsh" <dwalsh@redhat.com> wrote: > On 11/18/2009 03:24 PM, Chad Sellers wrote: >> On 11/12/09 11:23 AM, "Daniel J Walsh" <dwalsh@redhat.com> wrote: >> >>> On 11/11/2009 01:52 PM, Chad Sellers wrote: >>>> On 9/30/09 2:33 PM, "Daniel J Walsh" <dwalsh@redhat.com> wrote: >>>> >>>>> Includes enable and disable. >>>>> >>>> I presume I should hold off on this patch until you have a chance to >>>> resubmit the libsemanage support that it relies on. Let me know if that's >>>> not the case. >>>> >>>> Thanks, >>>> Chad >>>> >>> Lets do this patch. >>> >>> >>> Moves load_policy from /usr/sbin to /sbin >>> >>> Removed cruft. >>> >>> diff --git a/libsemanage/src/conf-parse.y b/libsemanage/src/conf-parse.y >>> index 23661bf..931448f 100644 >>> --- a/libsemanage/src/conf-parse.y >>> +++ b/libsemanage/src/conf-parse.y >>> @@ -263,7 +263,13 @@ static int semanage_conf_init(semanage_conf_t * conf) >>> calloc(1, sizeof(*(current_conf->load_policy)))) == NULL) { >>> return -1; >>> } >>> - if ((conf->load_policy->path = strdup("/usr/sbin/load_policy")) == >>> NULL) >>> { >>> + >>> + if (access("/sbin/load_policy", X_OK) == 0) { >>> + conf->load_policy->path = strdup("/sbin/load_policy"); >>> + } else { >>> + conf->load_policy->path = strdup("/usr/sbin/load_policy"); >>> + } >>> + if (conf->load_policy->path == NULL) >> >> Still missing a curly brace. >> >>> return -1; >>> } >>> conf->load_policy->args = NULL; >>> diff --git a/policycoreutils/load_policy/Makefile >>> b/policycoreutils/load_policy/Makefile >>> index 2dd2943..91dc6c8 100644 >>> --- a/policycoreutils/load_policy/Makefile >>> +++ b/policycoreutils/load_policy/Makefile >>> @@ -1,6 +1,7 @@ >>> # Installation directories. >>> PREFIX ?= ${DESTDIR}/usr >>> -SBINDIR ?= $(PREFIX)/sbin >>> +SBINDIR ?= $(DESTDIR)/sbin >>> +USRSBINDIR ?= $(PREFIX)/sbin >>> MANDIR ?= $(PREFIX)/share/man >>> LOCALEDIR ?= /usr/share/locale >>> >>> @@ -17,6 +18,8 @@ install: all >>> install -m 755 $(TARGETS) $(SBINDIR) >>> test -d $(MANDIR)/man8 || install -m 755 -d $(MANDIR)/man8 >>> install -m 644 load_policy.8 $(MANDIR)/man8/ >>> + -mkdir -p $(USRSBINDIR) >>> + ln -s /sbin/load_policy $(USRSBINDIR)/load_policy >>> >> Still using -s instead of -sf. You never responded to my previous email ( >> http://marc.info/?l=selinux&m=125788814205762&w=2 ). Are you ok with these 2 >> fixes? If so, I can make the changes and merge this. >> >> Thanks, >> Chad >> >>> clean: >>> -rm -f $(TARGETS) *.o >> > Yes go ahead. OK, merged as of policycoreutils 2.0.76 and libsemanage 2.0.42. Thanks, Chad -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Add modules support to semanage 2009-11-11 18:52 ` Chad Sellers 2009-11-12 16:23 ` Daniel J Walsh @ 2009-11-12 16:45 ` Daniel J Walsh 2009-12-30 19:48 ` Chad Sellers 2009-11-12 16:46 ` Daniel J Walsh 2 siblings, 1 reply; 9+ messages in thread From: Daniel J Walsh @ 2009-11-12 16:45 UTC (permalink / raw) To: Chad Sellers; +Cc: SE Linux [-- Attachment #1: Type: text/plain, Size: 471 bytes --] On 11/11/2009 01:52 PM, Chad Sellers wrote: > On 9/30/09 2:33 PM, "Daniel J Walsh" <dwalsh@redhat.com> wrote: > >> Includes enable and disable. >> > I presume I should hold off on this patch until you have a chance to > resubmit the libsemanage support that it relies on. Let me know if that's > not the case. > > Thanks, > Chad > This patch is provided the old fashioned way since I am fighting with guilt right now. Just the enable/disable changes to libsemanage. [-- Attachment #2: libsemanage-disable.patch --] [-- Type: text/plain, Size: 15325 bytes --] diff --exclude-from=exclude -N -u -r nsalibsemanage/include/semanage/modules.h libsemanage-2.0.41/include/semanage/modules.h --- nsalibsemanage/include/semanage/modules.h 2009-01-13 08:45:35.000000000 -0500 +++ libsemanage-2.0.41/include/semanage/modules.h 2009-11-12 11:01:10.000000000 -0500 @@ -40,10 +40,12 @@ char *module_data, size_t data_len); int semanage_module_install_base_file(semanage_handle_t *, const char *module_name); +int semanage_module_enable(semanage_handle_t *, char *module_name); +int semanage_module_disable(semanage_handle_t *, char *module_name); int semanage_module_remove(semanage_handle_t *, char *module_name); /* semanage_module_info is for getting information on installed - modules, only name and version at this time */ + modules, only name and version, and enabled/disabled flag at this time */ typedef struct semanage_module_info semanage_module_info_t; int semanage_module_list(semanage_handle_t *, @@ -53,5 +55,6 @@ int n); const char *semanage_module_get_name(semanage_module_info_t *); const char *semanage_module_get_version(semanage_module_info_t *); +int semanage_module_get_enabled(semanage_module_info_t *); #endif diff --exclude-from=exclude -N -u -r nsalibsemanage/src/direct_api.c libsemanage-2.0.41/src/direct_api.c --- nsalibsemanage/src/direct_api.c 2009-09-17 08:59:43.000000000 -0400 +++ libsemanage-2.0.41/src/direct_api.c 2009-11-12 11:01:10.000000000 -0500 @@ -66,6 +66,8 @@ static int semanage_direct_install_base(semanage_handle_t * sh, char *base_data, size_t data_len); static int semanage_direct_install_base_file(semanage_handle_t * sh, const char *module_name); +static int semanage_direct_enable(semanage_handle_t * sh, char *module_name); +static int semanage_direct_disable(semanage_handle_t * sh, char *module_name); static int semanage_direct_remove(semanage_handle_t * sh, char *module_name); static int semanage_direct_list(semanage_handle_t * sh, semanage_module_info_t ** modinfo, @@ -83,6 +85,8 @@ .upgrade_file = semanage_direct_upgrade_file, .install_base = semanage_direct_install_base, .install_base_file = semanage_direct_install_base_file, + .enable = semanage_direct_enable, + .disable = semanage_direct_disable, .remove = semanage_direct_remove, .list = semanage_direct_list }; @@ -348,10 +352,17 @@ semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES)) == NULL) { return -1; } - if (asprintf(filename, "%s/%s.pp", module_path, *module_name) == -1) { + if (asprintf(filename, "%s/%s.pp%s", module_path, *module_name, DISABLESTR) == -1) { ERR(sh, "Out of memory!"); return -1; } + + if (access(*filename, F_OK) == -1) { + char *ptr = *filename; + int len = strlen(ptr) - strlen(DISABLESTR); + if (len > 0) ptr[len]='\0'; + } + return 0; } @@ -1273,6 +1284,107 @@ return retval; } +/* Enables a module from the sandbox. Returns 0 on success, -1 if out + * of memory, -2 if module not found or could not be enabled. */ +static int semanage_direct_enable(semanage_handle_t * sh, char *module_name) +{ + int i, retval = -1; + char **module_filenames = NULL; + int num_mod_files; + size_t name_len = strlen(module_name); + if (semanage_get_modules_names(sh, &module_filenames, &num_mod_files) == + -1) { + return -1; + } + for (i = 0; i < num_mod_files; i++) { + char *base = strrchr(module_filenames[i], '/'); + if (base == NULL) { + ERR(sh, "Could not read module names."); + retval = -2; + goto cleanup; + } + base++; + if (memcmp(module_name, base, name_len) == 0 && + strcmp(base + name_len + 3, DISABLESTR) == 0) { + int len = strlen(module_filenames[i]) - strlen(DISABLESTR); + char *enabled_name = calloc(1, len+1); + if (!enabled_name) { + ERR(sh, "Could not allocate memory"); + retval = -1; + goto cleanup; + } + + strncpy(enabled_name, module_filenames[i],len); + + if (rename(module_filenames[i], enabled_name) == -1) { + ERR(sh, "Could not enable module file %s.", + enabled_name); + retval = -2; + } + retval = 0; + free(enabled_name); + goto cleanup; + } + } + ERR(sh, "Module %s was not found.", module_name); + retval = -2; /* module not found */ + cleanup: + for (i = 0; module_filenames != NULL && i < num_mod_files; i++) { + free(module_filenames[i]); + } + free(module_filenames); + return retval; +} + +/* Enables a module from the sandbox. Returns 0 on success, -1 if out + * of memory, -2 if module not found or could not be enabled. */ +static int semanage_direct_disable(semanage_handle_t * sh, char *module_name) +{ + int i, retval = -1; + char **module_filenames = NULL; + int num_mod_files; + size_t name_len = strlen(module_name); + if (semanage_get_modules_names(sh, &module_filenames, &num_mod_files) == + -1) { + return -1; + } + for (i = 0; i < num_mod_files; i++) { + char *base = strrchr(module_filenames[i], '/'); + if (base == NULL) { + ERR(sh, "Could not read module names."); + retval = -2; + goto cleanup; + } + base++; + if (memcmp(module_name, base, name_len) == 0 && + strcmp(base + name_len, ".pp") == 0) { + char disabled_name[PATH_MAX]; + if (snprintf(disabled_name, PATH_MAX, "%s%s", + module_filenames[i], DISABLESTR) == PATH_MAX) { + ERR(sh, "Could not disable module file %s.", + module_filenames[i]); + retval = -2; + goto cleanup; + } + if (rename(module_filenames[i], disabled_name) == -1) { + ERR(sh, "Could not disable module file %s.", + module_filenames[i]); + retval = -2; + } + retval = 0; + goto cleanup; + } + } + ERR(sh, "Module %s was not found.", module_name); + retval = -2; /* module not found */ + cleanup: + for (i = 0; module_filenames != NULL && i < num_mod_files; i++) { + free(module_filenames[i]); + } + free(module_filenames); + return retval; +} + /* Removes a module from the sandbox. Returns 0 on success, -1 if out * of memory, -2 if module not found or could not be removed. */ static int semanage_direct_remove(semanage_handle_t * sh, char *module_name) @@ -1293,8 +1405,7 @@ goto cleanup; } base++; - if (memcmp(module_name, base, name_len) == 0 && - strcmp(base + name_len, ".pp") == 0) { + if (memcmp(module_name, base, name_len) == 0) { if (unlink(module_filenames[i]) == -1) { ERR(sh, "Could not remove module file %s.", module_filenames[i]); @@ -1369,6 +1480,7 @@ } ssize_t size; char *data = NULL; + int enabled = semanage_module_enabled(module_filenames[i]); if ((size = bunzip(sh, fp, &data)) > 0) { fclose(fp); @@ -1393,6 +1505,7 @@ if (type == SEPOL_POLICY_MOD) { (*modinfo)[*num_modules].name = name; (*modinfo)[*num_modules].version = version; + (*modinfo)[*num_modules].enabled = enabled; (*num_modules)++; } else { /* file was not a module, so don't report it */ diff --exclude-from=exclude -N -u -r nsalibsemanage/src/libsemanage.map libsemanage-2.0.41/src/libsemanage.map --- nsalibsemanage/src/libsemanage.map 2009-10-29 15:21:39.000000000 -0400 +++ libsemanage-2.0.41/src/libsemanage.map 2009-11-12 11:01:10.000000000 -0500 @@ -6,10 +6,13 @@ semanage_module_install; semanage_module_install_file; semanage_module_upgrade; semanage_module_upgrade_file; semanage_module_install_base; semanage_module_install_base_file; + semanage_module_enable; + semanage_module_disable; semanage_module_remove; semanage_module_list; semanage_module_info_datum_destroy; semanage_module_list_nth; semanage_module_get_name; semanage_module_get_version; semanage_select_store; + semanage_module_get_enabled; semanage_reload_policy; semanage_set_reload; semanage_set_rebuild; semanage_user_*; semanage_bool_*; semanage_seuser_*; semanage_iface_*; semanage_port_*; semanage_context_*; diff --exclude-from=exclude -N -u -r nsalibsemanage/src/module_internal.h libsemanage-2.0.41/src/module_internal.h --- nsalibsemanage/src/module_internal.h 2008-08-28 09:34:24.000000000 -0400 +++ libsemanage-2.0.41/src/module_internal.h 2009-11-12 11:01:10.000000000 -0500 @@ -6,6 +6,7 @@ hidden_proto(semanage_module_get_name) hidden_proto(semanage_module_get_version) + hidden_proto(semanage_module_get_enabled) hidden_proto(semanage_module_info_datum_destroy) hidden_proto(semanage_module_list_nth) #endif diff --exclude-from=exclude -N -u -r nsalibsemanage/src/modules.c libsemanage-2.0.41/src/modules.c --- nsalibsemanage/src/modules.c 2009-09-17 08:59:43.000000000 -0400 +++ libsemanage-2.0.41/src/modules.c 2009-11-12 11:01:10.000000000 -0500 @@ -154,6 +154,40 @@ return sh->funcs->install_base_file(sh, module_name); } +int semanage_module_enable(semanage_handle_t * sh, char *module_name) +{ + if (sh->funcs->enable == NULL) { + ERR(sh, "No enable function defined for this connection type."); + return -1; + } else if (!sh->is_connected) { + ERR(sh, "Not connected."); + return -1; + } else if (!sh->is_in_transaction) { + if (semanage_begin_transaction(sh) < 0) { + return -1; + } + } + sh->modules_modified = 1; + return sh->funcs->enable(sh, module_name); +} + +int semanage_module_disable(semanage_handle_t * sh, char *module_name) +{ + if (sh->funcs->disable == NULL) { + ERR(sh, "No disable function defined for this connection type."); + return -1; + } else if (!sh->is_connected) { + ERR(sh, "Not connected."); + return -1; + } else if (!sh->is_in_transaction) { + if (semanage_begin_transaction(sh) < 0) { + return -1; + } + } + sh->modules_modified = 1; + return sh->funcs->disable(sh, module_name); +} + int semanage_module_remove(semanage_handle_t * sh, char *module_name) { if (sh->funcs->remove == NULL) { @@ -209,6 +243,13 @@ hidden_def(semanage_module_get_name) +int semanage_module_get_enabled(semanage_module_info_t * modinfo) +{ + return modinfo->enabled; +} + +hidden_def(semanage_module_get_enabled) + const char *semanage_module_get_version(semanage_module_info_t * modinfo) { return modinfo->version; diff --exclude-from=exclude -N -u -r nsalibsemanage/src/modules.h libsemanage-2.0.41/src/modules.h --- nsalibsemanage/src/modules.h 2008-08-28 09:34:24.000000000 -0400 +++ libsemanage-2.0.41/src/modules.h 2009-11-12 11:01:10.000000000 -0500 @@ -26,6 +26,7 @@ struct semanage_module_info { char *name; /* Key */ char *version; + int enabled; }; #endif diff --exclude-from=exclude -N -u -r nsalibsemanage/src/policy.h libsemanage-2.0.41/src/policy.h --- nsalibsemanage/src/policy.h 2009-01-13 08:45:35.000000000 -0500 +++ libsemanage-2.0.41/src/policy.h 2009-11-12 11:01:10.000000000 -0500 @@ -58,6 +58,12 @@ /* Upgrade a policy module */ int (*upgrade_file) (struct semanage_handle *, const char *); + /* Enable a policy module */ + int (*enable) (struct semanage_handle *, char *); + + /* Disable a policy module */ + int (*disable) (struct semanage_handle *, char *); + /* Remove a policy module */ int (*remove) (struct semanage_handle *, char *); diff --exclude-from=exclude -N -u -r nsalibsemanage/src/semanage_store.c libsemanage-2.0.41/src/semanage_store.c --- nsalibsemanage/src/semanage_store.c 2009-10-29 15:21:39.000000000 -0400 +++ libsemanage-2.0.41/src/semanage_store.c 2009-11-12 11:01:10.000000000 -0500 @@ -57,6 +57,8 @@ #include "debug.h" +const char *DISABLESTR=".disabled"; + #define SEMANAGE_CONF_FILE "semanage.conf" /* relative path names to enum semanage_paths to special files and * directories for the module store */ @@ -433,6 +435,21 @@ return 1; } +int semanage_module_enabled(const char *file) { + int len = strlen(file) - strlen(DISABLESTR); + return (len < 0 || strcmp(&file[len], DISABLESTR) != 0); +} + +static int semanage_modulename_select(const struct dirent *d) +{ + if (d->d_name[0] == '.' + && (d->d_name[1] == '\0' + || (d->d_name[1] == '.' && d->d_name[2] == '\0'))) + return 0; + + return semanage_module_enabled(d->d_name); +} + /* Copies a file from src to dst. If dst already exists then * overwrite it. Returns 0 on success, -1 on error. */ static int semanage_copy_file(const char *src, const char *dst, mode_t mode) @@ -599,15 +616,8 @@ return -1; } -/* Scans the modules directory for the current semanage handler. This - * might be the active directory or sandbox, depending upon if the - * handler has a transaction lock. Allocates and fills in *filenames - * with an array of module filenames; length of array is stored in - * *len. The caller is responsible for free()ing *filenames and its - * individual elements. Upon success returns 0, -1 on error. - */ -int semanage_get_modules_names(semanage_handle_t * sh, char ***filenames, - int *len) +static int semanage_get_modules_names_filter(semanage_handle_t * sh, char ***filenames, + int *len, int (*filter)(const struct dirent *)) { const char *modules_path; struct dirent **namelist = NULL; @@ -622,7 +632,7 @@ *filenames = NULL; *len = 0; if ((num_files = scandir(modules_path, &namelist, - semanage_filename_select, alphasort)) == -1) { + filter, alphasort)) == -1) { ERR(sh, "Error while scanning directory %s.", modules_path); goto cleanup; } @@ -663,6 +673,34 @@ return retval; } +/* Scans the modules directory for the current semanage handler. This + * might be the active directory or sandbox, depending upon if the + * handler has a transaction lock. Allocates and fills in *filenames + * with an array of module filenames; length of array is stored in + * *len. The caller is responsible for free()ing *filenames and its + * individual elements. Upon success returns 0, -1 on error. + */ +int semanage_get_modules_names(semanage_handle_t * sh, char ***filenames, + int *len) +{ + return semanage_get_modules_names_filter(sh, filenames, + len, semanage_filename_select); +} + +/* Scans the modules directory for the current semanage handler. This + * might be the active directory or sandbox, depending upon if the + * handler has a transaction lock. Allocates and fills in *filenames + * with an array of module filenames; length of array is stored in + * *len. The caller is responsible for free()ing *filenames and its + * individual elements. Upon success returns 0, -1 on error. + */ +int semanage_get_active_modules_names(semanage_handle_t * sh, char ***filenames, + int *len) +{ + return semanage_get_modules_names_filter(sh, filenames, + len, semanage_modulename_select); +} + /******************* routines that run external programs *******************/ /* Appends a single character to a string. Returns a pointer to the @@ -1589,7 +1627,7 @@ } /* get list of modules and load them */ - if (semanage_get_modules_names(sh, &module_filenames, &num_modules) == + if (semanage_get_active_modules_names(sh, &module_filenames, &num_modules) == -1 || semanage_load_module(sh, base_filename, base) == -1) { goto cleanup; } diff --exclude-from=exclude -N -u -r nsalibsemanage/src/semanage_store.h libsemanage-2.0.41/src/semanage_store.h --- nsalibsemanage/src/semanage_store.h 2009-07-07 15:32:32.000000000 -0400 +++ libsemanage-2.0.41/src/semanage_store.h 2009-11-12 11:01:10.000000000 -0500 @@ -128,4 +128,6 @@ size_t buf_len, char **sorted_buf, size_t * sorted_buf_len); +extern const char *DISABLESTR; + #endif ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Add modules support to semanage 2009-11-12 16:45 ` Daniel J Walsh @ 2009-12-30 19:48 ` Chad Sellers 0 siblings, 0 replies; 9+ messages in thread From: Chad Sellers @ 2009-12-30 19:48 UTC (permalink / raw) To: Daniel J Walsh; +Cc: SE Linux On 11/12/09 11:45 AM, "Daniel J Walsh" <dwalsh@redhat.com> wrote: > On 11/11/2009 01:52 PM, Chad Sellers wrote: >> On 9/30/09 2:33 PM, "Daniel J Walsh" <dwalsh@redhat.com> wrote: >> >>> Includes enable and disable. >>> >> I presume I should hold off on this patch until you have a chance to >> resubmit the libsemanage support that it relies on. Let me know if that's >> not the case. >> >> Thanks, >> Chad >> > > This patch is provided the old fashioned way since I am fighting with guilt > right now. > > Just the enable/disable changes to libsemanage. > > diff --git a/policycoreutils/Makefile b/policycoreutils/Makefile > index 538302b..394069a 100644 > --- a/policycoreutils/Makefile > +++ b/policycoreutils/Makefile > @@ -1,4 +1,4 @@ > -SUBDIRS = setfiles semanage load_policy newrole run_init secon audit2allow > audit2why scripts sestatus semodule_package semodule semodule_link > semodule_expand semodule_deps setsebool po > +SUBDIRS = sandbox setfiles semanage load_policy newrole run_init secon > audit2allow audit2why scripts sestatus semodule_package semodule semodule_link > semodule_expand semodule_deps setsebool po > > INOTIFYH = $(shell ls /usr/include/sys/inotify.h 2>/dev/null) > > diff --git a/policycoreutils/sandbox/Makefile > b/policycoreutils/sandbox/Makefile > new file mode 100644 > index 0000000..299276a > --- /dev/null > +++ b/policycoreutils/sandbox/Makefile > @@ -0,0 +1,31 @@ > +# Installation directories. > +PREFIX ?= ${DESTDIR}/usr > +BINDIR ?= $(PREFIX)/bin > +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 > + > +all: sandbox seunshare sandboxX.sh > + > +seunshare: seunshare.o $(EXTRA_OBJS) EXTRA_OBJS? I don't see that anywhere else. > + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) > + > +install: all > + -mkdir -p $(BINDIR) > + install -m 755 sandbox $(BINDIR) > + -mkdir -p $(MANDIR)/man8 > + install -m 644 sandbox.8 $(MANDIR)/man8/ > + install -m 4755 seunshare $(SBINDIR)/ > + -mkdir -p $(SHAREDIR) > + install -m 755 sandboxX.sh $(SHAREDIR) > + > +clean: > + -rm -f seunshare *.o *~ > + > +indent: > + ../../scripts/Lindent $(wildcard *.[ch]) > + > +relabel: > diff --git a/policycoreutils/sandbox/sandbox b/policycoreutils/sandbox/sandbox > new file mode 100644 > index 0000000..bc257bf > --- /dev/null > +++ b/policycoreutils/sandbox/sandbox > @@ -0,0 +1,242 @@ > +#!/usr/bin/python -E > +import os, sys, getopt, socket, random, fcntl, shutil > +import selinux > +import signal > + > +PROGNAME = "policycoreutils" > + > +import gettext > +gettext.bindtextdomain(PROGNAME, "/usr/share/locale") > +gettext.textdomain(PROGNAME) > + > +try: > + gettext.install(PROGNAME, > + localedir = "/usr/share/locale", > + unicode=False, > + codeset = 'utf-8') > +except IOError: > + import __builtin__ > + __builtin__.__dict__['_'] = unicode > + > + > +DEFAULT_TYPE = "sandbox_t" > +DEFAULT_X_TYPE = "sandbox_x_t" > +X_FILES = {} > + > +random.seed(None) > + > +def sighandler(signum, frame): > + signal.signal(signum, signal.SIG_IGN) > + os.kill(0, signum) > + raise KeyboardInterrupt > + > +def setup_sighandlers(): > + signal.signal(signal.SIGHUP, sighandler) > + signal.signal(signal.SIGQUIT, sighandler) > + signal.signal(signal.SIGTERM, sighandler) > + > +def error_exit(msg): > + sys.stderr.write("%s: " % sys.argv[0]) > + sys.stderr.write("%s\n" % msg) > + sys.stderr.flush() > + sys.exit(1) > + > +def reserve(mcs): > + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) > + sock.bind("\0%s" % mcs) > + fcntl.fcntl(sock.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC) > + > +def gen_context(setype): > + while True: > + i1 = random.randrange(0, 1024) > + i2 = random.randrange(0, 1024) > + if i1 == i2: > + continue > + if i1 > i2: > + tmp = i1 > + i1 = i2 > + i2 = tmp > + mcs = "s0:c%d,c%d" % (i1, i2) > + reserve(mcs) > + try: > + reserve(mcs) > + except: > + continue > + break I'm guessing this is supposed to ensure that 2 sandboxes have different category sets. It looks like it's supposed to bind to an abstract socket to prevent other processes from doing the same. I don't understand why reserve() is called twice (once outside the try block, then once inside). Regardless, in my testing it doesn't seem to work (I switched i1 and i2 to hardcoded values and can run multiple sandboxes with the same category sets simultaneously). So perhaps I'm misunderstanding the intent here. Also, assuming I'm guessing what this is supposed to do correctly, this logic will hang when the system runs out of categories. Admittedly that's a million sandboxes, but an error message would be much better than an infinite loop. > + con = selinux.getcon()[1].split(":") > + > + execcon = "%s:%s:%s:%s" % (con[0], con[1], setype, mcs) > + > + filecon = "%s:%s:%s:%s" % (con[0], > + "object_r", > + "%s_file_t" % setype[:-2], > + mcs) > + return execcon, filecon > + > +def copyfile(file, dir, dest): > + import re > + if file.startswith(dir): > + dname = os.path.dirname(file) > + bname = os.path.basename(file) > + if dname == dir: > + dest = dest + "/" + bname > + else: > + newdir = re.sub(dir, dest, dname) > + os.makedirs(newdir) > + dest = newdir + "/" + bname > + > + if os.path.isdir(file): > + shutil.copytree(file, dest) > + else: > + shutil.copy2(file, dest) > + X_FILES[file] = (dest, os.path.getmtime(dest)) > + > +def copyfiles(newhomedir, newtmpdir, files): > + import pwd > + homedir=pwd.getpwuid(os.getuid()).pw_dir > + for f in files: > + copyfile(f,homedir, newhomedir) > + copyfile(f,"/tmp", newtmpdir) > + > +def savefile(new, orig): > + import gtk Hmmm, this adds a gtk requirement to policycoreutils which we've never had before. Could we wrap this in a try block and use the console if gtk is not available? That way we could still support graphical messages if it was available, but work anyway if not. > + dlg = gtk.MessageDialog(None, 0, gtk.MESSAGE_INFO, > + gtk.BUTTONS_YES_NO, > + _("Do you want to save changes to '%s' (Y/N): > ") % orig) > + dlg.set_title(_("Sandbox Message")) > + dlg.set_position(gtk.WIN_POS_MOUSE) > + dlg.show_all() > + rc = dlg.run() > + dlg.destroy() > + if rc == gtk.RESPONSE_YES: > + shutil.copy2(new,orig) > + copyfile() above allows for copying individual files or full directory trees into the sandbox, but savefile() here seems to only allow copying individual files out of it. I'm guessing this will blow up if someone clicks Yes on a changed directory. > +if __name__ == '__main__': > + setup_sighandlers() > + if selinux.is_selinux_enabled() != 1: > + error_exit("Requires an SELinux enabled system") > + > + init_files = [] > + > + def usage(message = ""): > + text = _(""" > +sandbox [-h] [-I includefile ] [[-i file ] ...] [ -t type ] command > +""") > + error_exit("%s\n%s" % (message, text)) > + > + setype = DEFAULT_TYPE > + X_ind = False > + try: > + gopts, cmds = getopt.getopt(sys.argv[1:], "i:ht:XI:", > + ["help", > + "include=", > + "includefile=", > + "type=" > + ]) This does not agree with the usage message above or the man page (and they don't agree with each other either). The usage leaves out -X. The man page leaves out -h and -I. > + for o, a in gopts: > + if o == "-t" or o == "--type": > + setype = a > + > + if o == "-i" or o == "--include": > + rp = os.path.realpath(a) > + if rp not in init_files: > + init_files.append(rp) > + > + if o == "-I" or o == "--includefile": > + fd = open(a, "r") > + for i in fd.read().split("\n"): > + if os.path.exists(i): > + rp = os.path.realpath(i) > + if rp not in init_files: > + init_files.append(rp) > + > + fd.close > + > + if o == "-X": > + if DEFAULT_TYPE == setype: > + setype = DEFAULT_X_TYPE > + X_ind = True > + > + if o == "-h" or o == "--help": > + usage(_("Usage")); > + > + if len(cmds) == 0: > + usage(_("Command required")) > + > + execcon, filecon = gen_context(setype) > + rc = -1 > + > + if cmds[0][0] != "/" and cmds[0][:2] != "./" and cmds[0][:3] != > "../": > + for i in os.environ["PATH"].split(':'): > + f = "%s/%s" % (i, cmds[0]) > + if os.access(f, os.X_OK): > + cmds[0] = f > + break > + > + try: > + newhomedir = None > + newtmpdir = None > + if X_ind: > + if not os.path.exists("/usr/sbin/seunshare"): > + raise ValueError("""/usr/sbin/seunshare > required for sandbox -X, to install you need to execute > +#yum install /usr/sbin/seunshare""") > + import warnings > + warnings.simplefilter("ignore") > + newhomedir = os.tempnam(".", ".sandbox%s") > + os.mkdir(newhomedir) > + selinux.setfilecon(newhomedir, filecon) > + newtmpdir = os.tempnam("/tmp", ".sandbox") > + os.mkdir(newtmpdir) > + selinux.setfilecon(newtmpdir, filecon) > + warnings.resetwarnings() > + paths = [] > + for i in cmds: > + f = os.path.realpath(i) > + if os.path.exists(f): > + paths.append(f) > + else: > + paths.append(i) > + > + copyfiles(newhomedir, newtmpdir, init_files + paths) > + execfile = newhomedir + "/.sandboxrc" > + fd = open(execfile, "w+") > + fd.write("""#! /bin/sh > +%s > +""" % " ".join(paths)) > + fd.close() > + os.chmod(execfile, 0700) > + > + cmds = ("/usr/sbin/seunshare -t %s -h %s -- %s > /usr/share/sandbox/sandboxX.sh" % (newtmpdir, newhomedir, execcon)).split() > + rc = os.spawnvp(os.P_WAIT, cmds[0], cmds) > + for i in paths: > + if i not in X_FILES: > + continue > + (dest, mtime) = X_FILES[i] > + if os.path.getmtime(dest) > mtime: > + savefile(dest, i) > + else: > + selinux.setexeccon(execcon) > + rc = os.spawnvp(os.P_WAIT, cmds[0], cmds) > + selinux.setexeccon(None) > + finally: > + if X_ind: > + if newhomedir: > + shutil.rmtree(newhomedir) > + if newtmpdir: > + shutil.rmtree(newtmpdir) > + > + except getopt.GetoptError, error: > + usage(_("Options Error %s ") % error.msg) > + except OSError, error: > + error_exit(error.args[1]) > + except ValueError, error: > + error_exit(error.args[0]) > + except KeyError, error: > + error_exit(_("Invalid value %s") % error.args[0]) > + except IOError, error: > + error_exit(error.args[1]) > + except KeyboardInterrupt: > + rc = 0 > + > + sys.exit(rc) > + The other potential problem I see with this utility is that it makes some assumptions about the configuration (and mostly policy) of the system. These include: 1) The system is using an mcs policy 2) The sandbox file type is foo_file_t if the sandbox type is foo_t 3) There are 1024 categories 4) seunshare is found in /usr/sbin I think #1 and #2 are necessary assumptions, and hard to avoid. #3 could be solved with an optional command line arg. #4 probably isn't a big deal, but I'd move it to a variable at the top so other distros can easily change it if necessary. > diff --git a/policycoreutils/sandbox/sandbox.8 > b/policycoreutils/sandbox/sandbox.8 > new file mode 100644 > index 0000000..c3f8a1f > --- /dev/null > +++ b/policycoreutils/sandbox/sandbox.8 > @@ -0,0 +1,26 @@ > +.TH SANDBOX "8" "May 2009" "chcat" "User Commands" > +.SH NAME > +sandbox \- Run cmd under an SELinux sandbox > +.SH SYNOPSIS > +.B sandbox > +[-X] [[-i file ]...] [ -t type ] cmd This should probably be: [-X [-i file ]...] [ -t type ] cmd or something similar to indicate that -i is only valid if you're using -X. Speaking of which, any reason you chose not to allow the unshared tmp/home for non-X apps? It seems like useful functionality for command-line programs as well. > +.br > +.SH DESCRIPTION > +.PP > +Run application within a tightly confined SELinux domain, The default > sandbox allows the application to only read and write stdin and stdout along > with files handled to it by the shell. > +Additionaly a -X qualifier allows you to run sandboxed X applications. These > apps will start up their own X Server and create a temporary homedir and /tmp. > The default policy does not allow any capabilities or network access. Also > prevents all access to the users other processes and files. Any file > specified on the command line will be copied into the sandbox. > +.PP > +.TP > +\fB\-t type\fR > +Use alternate sandbox type, defaults to sandbox_t or sandbox_x_t for -X. > +.TP > +\fB\-i file\fR > +Copy this file into the temporary sandbox homedir. Command can be repeated. > +.TP > +\fB\-X\fR > +Create an X based Sandbox for gui apps, temporary files for $HOME and /tmp, > seconday Xserver, defaults to sandbox_x_t > +.TP > +.SH "SEE ALSO" > +.TP > +runcon(1) > +.PP > diff --git a/policycoreutils/sandbox/sandboxX.sh > b/policycoreutils/sandbox/sandboxX.sh > new file mode 100644 > index 0000000..21e6b0d > --- /dev/null > +++ b/policycoreutils/sandbox/sandboxX.sh > @@ -0,0 +1,16 @@ > +#!/bin/bash > +export TITLE="Sandbox: `/usr/bin/tail -1 ~/.sandboxrc | /usr/bin/cut -b1-70`" > +export SCREEN=`/usr/bin/xdpyinfo -display $DISPLAY | /bin/awk '/dimensions/ { > print $2 }'` > + > +(/usr/bin/Xephyr -title "$TITLE" -terminate -screen 1000x700 -displayfd 5 > 5>&1 2>/dev/null) | while read D; do > + export DISPLAY=:$D > + /usr/bin/matchbox-window-manager -use_titlebar no & > + WM_PID=$! > + ~/.sandboxrc & > + CLIENT_PID=$! > + wait $CLIENT_PID > + export EXITCODE=$? > + kill -TERM $WM_PID > + kill -HUP 0 > + break > +done > diff --git a/policycoreutils/sandbox/seunshare.c > b/policycoreutils/sandbox/seunshare.c > new file mode 100644 > index 0000000..ddf6bf1 > --- /dev/null > +++ b/policycoreutils/sandbox/seunshare.c > @@ -0,0 +1,265 @@ > +#include <signal.h> > +#include <sys/types.h> > +#include <sys/wait.h> > +#include <syslog.h> > +#include <sys/mount.h> > +#include <pwd.h> > +#define _GNU_SOURCE > +#include <sched.h> > +#include <string.h> > +#include <stdio.h> > +#include <unistd.h> > +#include <stdlib.h> > +#include <cap-ng.h> > +#include <getopt.h> /* for getopt_long() form of getopt() */ > +#include <limits.h> > +#include <stdlib.h> > +#include <errno.h> > + > +#include <selinux/selinux.h> > +#include <selinux/context.h> /* for context-mangling functions */ > + > +#include <sys/types.h> > +#include <sys/stat.h> > +#include <unistd.h> > + > +/** > + * This function will drop all capabilities > + * Returns zero on success, non-zero otherwise > + */ > +static int drop_capabilities(uid_t uid) > +{ > + capng_clear(CAPNG_SELECT_BOTH); > + > + if (capng_lock() < 0) > + return -1; > + /* Change uid */ > + if (setresuid(uid, uid, uid)) { > + fprintf(stderr, "Error changing uid, aborting.\n"); > + return -1; > + } > + return capng_apply(CAPNG_SELECT_BOTH); > +} > + > +#define DEFAULT_PATH "/usr/bin:/bin" > +#define TRUE 1 > +#define FALSE 0 > + > +/** > + * Take care of any signal setup > + */ > +static int set_signal_handles(void) > +{ > + sigset_t empty; > + > + /* Empty the signal mask in case someone is blocking a signal */ > + if (sigemptyset(&empty)) { > + fprintf(stderr, "Unable to obtain empty signal set\n"); > + return -1; > + } > + > + (void)sigprocmask(SIG_SETMASK, &empty, NULL); > + > + /* Terminate on SIGHUP. */ > + if (signal(SIGHUP, SIG_DFL) == SIG_ERR) { > + perror("Unable to set SIGHUP handler"); > + return -1; > + } > + > + return 0; > +} > +#define USAGE_STRING "USAGE: seunshare [ -t tmpdir ] [ -h homedir ] -- > CONTEXT executable [args] " > + > + > + > +static int verify_mount(const char *mntdir, struct passwd *pwd) { > + struct stat sb; > + if (stat(mntdir, &sb) == -1) { > + perror("Invalid mount point"); > + 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; > +} > + > +/** > + * This function checks to see if the shell is known in /etc/shells. > + * If so, it returns 1. On error or illegal shell, it returns 0. > + */ > +static int verify_shell(const char *shell_name) > +{ > + int found = 0; > + const char *buf; > + > + if (!(shell_name && shell_name[0])) > + return found; > + > + while ((buf = getusershell()) != NULL) { > + /* ignore comments */ > + if (*buf == '#') > + continue; > + > + /* check the shell skipping newline char */ > + if (!strcmp(shell_name, buf)) { > + found = 1; > + break; > + } > + } > + endusershell(); > + return found; > +} > + > +int main(int argc, char **argv) { > + int rc; > + int status = -1; > + > + 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[] */ > + > + const struct option long_options[] = { > + {"homedir", 1, 0, 'h'}, > + {"tmpdir", 1, 0, 't'}, > + {NULL, 0, 0, 0} > + }; > + > + uid_t uid = getuid(); > + > + if (!uid) { > + fprintf(stderr, "Must not be root"); > + return -1; > + } > + Why? Root can't run graphical things in a sandbox? Seems like an unnecessary restriction. > + struct passwd *pwd=getpwuid(uid); > + if (!pwd) { > + perror("getpwduid failed"); > + return -1; > + } > + > + if (verify_shell(pwd->pw_shell) == 0) { > + fprintf(stderr, "Error! Shell is not valid.\n"); > + return -1; > + } > + > + while (1) { > + clflag = getopt_long(argc, argv, "h:t:", long_options, > + &flag_index); > + if (clflag == -1) > + break; > + > + switch (clflag) { > + case 't': > + tmpdir_s = optarg; > + if (verify_mount(tmpdir_s, pwd) < 0) return -1; > + break; > + case 'h': > + homedir_s = optarg; > + if (verify_mount(homedir_s, pwd) < 0) return -1; > + if (verify_mount(pwd->pw_dir, pwd) < 0) return -1; > + break; > + default: > + fprintf(stderr, "%s\n", USAGE_STRING); > + return -1; > + } > + } > + > + if (! homedir_s && ! tmpdir_s) { > + fprintf(stderr, "Error: tmpdir and/or homedir required \n" > + "%s\n", USAGE_STRING); > + return -1; > + } > + > + if (argc - optind < 2) { > + fprintf(stderr, "Error: executable required \n" > + "%s\n", USAGE_STRING); > + return -1; > + } > + > + scontext = argv[optind++]; > + > + if (set_signal_handles()) > + return -1; > + > + if (unshare(CLONE_NEWNS) < 0) { > + perror("Failed to unshare"); > + return -1; > + } > + > + if (homedir_s && mount(homedir_s, pwd->pw_dir, NULL, MS_BIND, NULL) < 0) > { > + perror("Failed to mount HOMEDIR"); > + return -1; > + } > + > + if (homedir_s && verify_mount(pwd->pw_dir, pwd) < 0) > + return -1; > + > + if (tmpdir_s && mount(tmpdir_s, "/tmp", NULL, MS_BIND, NULL) < 0) { > + perror("Failed to mount /tmp"); > + return -1; > + } > + > + if (tmpdir_s && verify_mount("/tmp", pwd) < 0) > + return -1; > + > + if (drop_capabilities(uid)) { > + perror("Failed to drop all capabilities"); > + return -1; > + } > + > + int child = fork(); > + 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 ((rc = clearenv())) { > + perror("Unable to clear environment"); > + free(display); > + exit(-1); > + } > + > + if (setexeccon(scontext)) { > + fprintf(stderr, "Could not set exec context to %s.\n", > + scontext); > + free(display); > + exit(-1); > + } > + > + if (display) > + rc |= setenv("DISPLAY", display, 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 (chdir(pwd->pw_dir)) { > + 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); > + } > + > + return status; > +} > > Thanks for submitting this. I'm think it will be great to get it upstream, as it's such a useful utility. I'd be happy to help out with any changes to it that are necessary once I understand a few of the things I asked about. Just let me know. Chad Sellers -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Add modules support to semanage 2009-11-11 18:52 ` Chad Sellers 2009-11-12 16:23 ` Daniel J Walsh 2009-11-12 16:45 ` Daniel J Walsh @ 2009-11-12 16:46 ` Daniel J Walsh 2 siblings, 0 replies; 9+ messages in thread From: Daniel J Walsh @ 2009-11-12 16:46 UTC (permalink / raw) To: Chad Sellers; +Cc: SE Linux [-- Attachment #1: Type: text/plain, Size: 406 bytes --] On 11/11/2009 01:52 PM, Chad Sellers wrote: > On 9/30/09 2:33 PM, "Daniel J Walsh" <dwalsh@redhat.com> wrote: > >> Includes enable and disable. >> > I presume I should hold off on this patch until you have a chance to > resubmit the libsemanage support that it relies on. Let me know if that's > not the case. > > Thanks, > Chad > I have updated the sandbox patch to include a setsid call in seunshare. [-- Attachment #2: policycoretuils-sandbox.patch --] [-- Type: text/plain, Size: 18783 bytes --] diff --git a/policycoreutils/Makefile b/policycoreutils/Makefile index 538302b..394069a 100644 --- a/policycoreutils/Makefile +++ b/policycoreutils/Makefile @@ -1,4 +1,4 @@ -SUBDIRS = setfiles semanage load_policy newrole run_init secon audit2allow audit2why scripts sestatus semodule_package semodule semodule_link semodule_expand semodule_deps setsebool po +SUBDIRS = sandbox setfiles semanage load_policy newrole run_init secon audit2allow audit2why scripts sestatus semodule_package semodule semodule_link semodule_expand semodule_deps setsebool po INOTIFYH = $(shell ls /usr/include/sys/inotify.h 2>/dev/null) diff --git a/policycoreutils/sandbox/Makefile b/policycoreutils/sandbox/Makefile new file mode 100644 index 0000000..299276a --- /dev/null +++ b/policycoreutils/sandbox/Makefile @@ -0,0 +1,31 @@ +# Installation directories. +PREFIX ?= ${DESTDIR}/usr +BINDIR ?= $(PREFIX)/bin +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 + +all: sandbox seunshare sandboxX.sh + +seunshare: seunshare.o $(EXTRA_OBJS) + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +install: all + -mkdir -p $(BINDIR) + install -m 755 sandbox $(BINDIR) + -mkdir -p $(MANDIR)/man8 + install -m 644 sandbox.8 $(MANDIR)/man8/ + install -m 4755 seunshare $(SBINDIR)/ + -mkdir -p $(SHAREDIR) + install -m 755 sandboxX.sh $(SHAREDIR) + +clean: + -rm -f seunshare *.o *~ + +indent: + ../../scripts/Lindent $(wildcard *.[ch]) + +relabel: diff --git a/policycoreutils/sandbox/sandbox b/policycoreutils/sandbox/sandbox new file mode 100644 index 0000000..bc257bf --- /dev/null +++ b/policycoreutils/sandbox/sandbox @@ -0,0 +1,242 @@ +#!/usr/bin/python -E +import os, sys, getopt, socket, random, fcntl, shutil +import selinux +import signal + +PROGNAME = "policycoreutils" + +import gettext +gettext.bindtextdomain(PROGNAME, "/usr/share/locale") +gettext.textdomain(PROGNAME) + +try: + gettext.install(PROGNAME, + localedir = "/usr/share/locale", + unicode=False, + codeset = 'utf-8') +except IOError: + import __builtin__ + __builtin__.__dict__['_'] = unicode + + +DEFAULT_TYPE = "sandbox_t" +DEFAULT_X_TYPE = "sandbox_x_t" +X_FILES = {} + +random.seed(None) + +def sighandler(signum, frame): + signal.signal(signum, signal.SIG_IGN) + os.kill(0, signum) + raise KeyboardInterrupt + +def setup_sighandlers(): + signal.signal(signal.SIGHUP, sighandler) + signal.signal(signal.SIGQUIT, sighandler) + signal.signal(signal.SIGTERM, sighandler) + +def error_exit(msg): + sys.stderr.write("%s: " % sys.argv[0]) + sys.stderr.write("%s\n" % msg) + sys.stderr.flush() + sys.exit(1) + +def reserve(mcs): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.bind("\0%s" % mcs) + fcntl.fcntl(sock.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC) + +def gen_context(setype): + while True: + i1 = random.randrange(0, 1024) + i2 = random.randrange(0, 1024) + if i1 == i2: + continue + if i1 > i2: + tmp = i1 + i1 = i2 + i2 = tmp + mcs = "s0:c%d,c%d" % (i1, i2) + reserve(mcs) + try: + reserve(mcs) + except: + continue + break + con = selinux.getcon()[1].split(":") + + execcon = "%s:%s:%s:%s" % (con[0], con[1], setype, mcs) + + filecon = "%s:%s:%s:%s" % (con[0], + "object_r", + "%s_file_t" % setype[:-2], + mcs) + return execcon, filecon + +def copyfile(file, dir, dest): + import re + if file.startswith(dir): + dname = os.path.dirname(file) + bname = os.path.basename(file) + if dname == dir: + dest = dest + "/" + bname + else: + newdir = re.sub(dir, dest, dname) + os.makedirs(newdir) + dest = newdir + "/" + bname + + if os.path.isdir(file): + shutil.copytree(file, dest) + else: + shutil.copy2(file, dest) + X_FILES[file] = (dest, os.path.getmtime(dest)) + +def copyfiles(newhomedir, newtmpdir, files): + import pwd + homedir=pwd.getpwuid(os.getuid()).pw_dir + for f in files: + copyfile(f,homedir, newhomedir) + copyfile(f,"/tmp", newtmpdir) + +def savefile(new, orig): + import gtk + dlg = gtk.MessageDialog(None, 0, gtk.MESSAGE_INFO, + gtk.BUTTONS_YES_NO, + _("Do you want to save changes to '%s' (Y/N): ") % orig) + dlg.set_title(_("Sandbox Message")) + dlg.set_position(gtk.WIN_POS_MOUSE) + dlg.show_all() + rc = dlg.run() + dlg.destroy() + if rc == gtk.RESPONSE_YES: + shutil.copy2(new,orig) + +if __name__ == '__main__': + setup_sighandlers() + if selinux.is_selinux_enabled() != 1: + error_exit("Requires an SELinux enabled system") + + init_files = [] + + def usage(message = ""): + text = _(""" +sandbox [-h] [-I includefile ] [[-i file ] ...] [ -t type ] command +""") + error_exit("%s\n%s" % (message, text)) + + setype = DEFAULT_TYPE + X_ind = False + try: + gopts, cmds = getopt.getopt(sys.argv[1:], "i:ht:XI:", + ["help", + "include=", + "includefile=", + "type=" + ]) + for o, a in gopts: + if o == "-t" or o == "--type": + setype = a + + if o == "-i" or o == "--include": + rp = os.path.realpath(a) + if rp not in init_files: + init_files.append(rp) + + if o == "-I" or o == "--includefile": + fd = open(a, "r") + for i in fd.read().split("\n"): + if os.path.exists(i): + rp = os.path.realpath(i) + if rp not in init_files: + init_files.append(rp) + + fd.close + + if o == "-X": + if DEFAULT_TYPE == setype: + setype = DEFAULT_X_TYPE + X_ind = True + + if o == "-h" or o == "--help": + usage(_("Usage")); + + if len(cmds) == 0: + usage(_("Command required")) + + execcon, filecon = gen_context(setype) + rc = -1 + + if cmds[0][0] != "/" and cmds[0][:2] != "./" and cmds[0][:3] != "../": + for i in os.environ["PATH"].split(':'): + f = "%s/%s" % (i, cmds[0]) + if os.access(f, os.X_OK): + cmds[0] = f + break + + try: + newhomedir = None + newtmpdir = None + if X_ind: + if not os.path.exists("/usr/sbin/seunshare"): + raise ValueError("""/usr/sbin/seunshare required for sandbox -X, to install you need to execute +#yum install /usr/sbin/seunshare""") + import warnings + warnings.simplefilter("ignore") + newhomedir = os.tempnam(".", ".sandbox%s") + os.mkdir(newhomedir) + selinux.setfilecon(newhomedir, filecon) + newtmpdir = os.tempnam("/tmp", ".sandbox") + os.mkdir(newtmpdir) + selinux.setfilecon(newtmpdir, filecon) + warnings.resetwarnings() + paths = [] + for i in cmds: + f = os.path.realpath(i) + if os.path.exists(f): + paths.append(f) + else: + paths.append(i) + + copyfiles(newhomedir, newtmpdir, init_files + paths) + execfile = newhomedir + "/.sandboxrc" + fd = open(execfile, "w+") + fd.write("""#! /bin/sh +%s +""" % " ".join(paths)) + fd.close() + os.chmod(execfile, 0700) + + cmds = ("/usr/sbin/seunshare -t %s -h %s -- %s /usr/share/sandbox/sandboxX.sh" % (newtmpdir, newhomedir, execcon)).split() + rc = os.spawnvp(os.P_WAIT, cmds[0], cmds) + for i in paths: + if i not in X_FILES: + continue + (dest, mtime) = X_FILES[i] + if os.path.getmtime(dest) > mtime: + savefile(dest, i) + else: + selinux.setexeccon(execcon) + rc = os.spawnvp(os.P_WAIT, cmds[0], cmds) + selinux.setexeccon(None) + finally: + if X_ind: + if newhomedir: + shutil.rmtree(newhomedir) + if newtmpdir: + shutil.rmtree(newtmpdir) + + except getopt.GetoptError, error: + usage(_("Options Error %s ") % error.msg) + except OSError, error: + error_exit(error.args[1]) + except ValueError, error: + error_exit(error.args[0]) + except KeyError, error: + error_exit(_("Invalid value %s") % error.args[0]) + except IOError, error: + error_exit(error.args[1]) + except KeyboardInterrupt: + rc = 0 + + sys.exit(rc) + diff --git a/policycoreutils/sandbox/sandbox.8 b/policycoreutils/sandbox/sandbox.8 new file mode 100644 index 0000000..c3f8a1f --- /dev/null +++ b/policycoreutils/sandbox/sandbox.8 @@ -0,0 +1,26 @@ +.TH SANDBOX "8" "May 2009" "chcat" "User Commands" +.SH NAME +sandbox \- Run cmd under an SELinux sandbox +.SH SYNOPSIS +.B sandbox +[-X] [[-i file ]...] [ -t type ] cmd +.br +.SH DESCRIPTION +.PP +Run application within a tightly confined SELinux domain, The default sandbox allows the application to only read and write stdin and stdout along with files handled to it by the shell. +Additionaly a -X qualifier allows you to run sandboxed X applications. These apps will start up their own X Server and create a temporary homedir and /tmp. The default policy does not allow any capabilities or network access. Also prevents all access to the users other processes and files. Any file specified on the command line will be copied into the sandbox. +.PP +.TP +\fB\-t type\fR +Use alternate sandbox type, defaults to sandbox_t or sandbox_x_t for -X. +.TP +\fB\-i file\fR +Copy this file into the temporary sandbox homedir. Command can be repeated. +.TP +\fB\-X\fR +Create an X based Sandbox for gui apps, temporary files for $HOME and /tmp, seconday Xserver, defaults to sandbox_x_t +.TP +.SH "SEE ALSO" +.TP +runcon(1) +.PP diff --git a/policycoreutils/sandbox/sandboxX.sh b/policycoreutils/sandbox/sandboxX.sh new file mode 100644 index 0000000..21e6b0d --- /dev/null +++ b/policycoreutils/sandbox/sandboxX.sh @@ -0,0 +1,16 @@ +#!/bin/bash +export TITLE="Sandbox: `/usr/bin/tail -1 ~/.sandboxrc | /usr/bin/cut -b1-70`" +export SCREEN=`/usr/bin/xdpyinfo -display $DISPLAY | /bin/awk '/dimensions/ { print $2 }'` + +(/usr/bin/Xephyr -title "$TITLE" -terminate -screen 1000x700 -displayfd 5 5>&1 2>/dev/null) | while read D; do + export DISPLAY=:$D + /usr/bin/matchbox-window-manager -use_titlebar no & + WM_PID=$! + ~/.sandboxrc & + CLIENT_PID=$! + wait $CLIENT_PID + export EXITCODE=$? + kill -TERM $WM_PID + kill -HUP 0 + break +done diff --git a/policycoreutils/sandbox/seunshare.c b/policycoreutils/sandbox/seunshare.c new file mode 100644 index 0000000..ddf6bf1 --- /dev/null +++ b/policycoreutils/sandbox/seunshare.c @@ -0,0 +1,265 @@ +#include <signal.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <syslog.h> +#include <sys/mount.h> +#include <pwd.h> +#define _GNU_SOURCE +#include <sched.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <cap-ng.h> +#include <getopt.h> /* for getopt_long() form of getopt() */ +#include <limits.h> +#include <stdlib.h> +#include <errno.h> + +#include <selinux/selinux.h> +#include <selinux/context.h> /* for context-mangling functions */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +/** + * This function will drop all capabilities + * Returns zero on success, non-zero otherwise + */ +static int drop_capabilities(uid_t uid) +{ + capng_clear(CAPNG_SELECT_BOTH); + + if (capng_lock() < 0) + return -1; + /* Change uid */ + if (setresuid(uid, uid, uid)) { + fprintf(stderr, "Error changing uid, aborting.\n"); + return -1; + } + return capng_apply(CAPNG_SELECT_BOTH); +} + +#define DEFAULT_PATH "/usr/bin:/bin" +#define TRUE 1 +#define FALSE 0 + +/** + * Take care of any signal setup + */ +static int set_signal_handles(void) +{ + sigset_t empty; + + /* Empty the signal mask in case someone is blocking a signal */ + if (sigemptyset(&empty)) { + fprintf(stderr, "Unable to obtain empty signal set\n"); + return -1; + } + + (void)sigprocmask(SIG_SETMASK, &empty, NULL); + + /* Terminate on SIGHUP. */ + if (signal(SIGHUP, SIG_DFL) == SIG_ERR) { + perror("Unable to set SIGHUP handler"); + return -1; + } + + return 0; +} +#define USAGE_STRING "USAGE: seunshare [ -t tmpdir ] [ -h homedir ] -- CONTEXT executable [args] " + + + +static int verify_mount(const char *mntdir, struct passwd *pwd) { + struct stat sb; + if (stat(mntdir, &sb) == -1) { + perror("Invalid mount point"); + 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; +} + +/** + * This function checks to see if the shell is known in /etc/shells. + * If so, it returns 1. On error or illegal shell, it returns 0. + */ +static int verify_shell(const char *shell_name) +{ + int found = 0; + const char *buf; + + if (!(shell_name && shell_name[0])) + return found; + + while ((buf = getusershell()) != NULL) { + /* ignore comments */ + if (*buf == '#') + continue; + + /* check the shell skipping newline char */ + if (!strcmp(shell_name, buf)) { + found = 1; + break; + } + } + endusershell(); + return found; +} + +int main(int argc, char **argv) { + int rc; + int status = -1; + + 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[] */ + + const struct option long_options[] = { + {"homedir", 1, 0, 'h'}, + {"tmpdir", 1, 0, 't'}, + {NULL, 0, 0, 0} + }; + + uid_t uid = getuid(); + + if (!uid) { + fprintf(stderr, "Must not be root"); + return -1; + } + + struct passwd *pwd=getpwuid(uid); + if (!pwd) { + perror("getpwduid failed"); + return -1; + } + + if (verify_shell(pwd->pw_shell) == 0) { + fprintf(stderr, "Error! Shell is not valid.\n"); + return -1; + } + + while (1) { + clflag = getopt_long(argc, argv, "h:t:", long_options, + &flag_index); + if (clflag == -1) + break; + + switch (clflag) { + case 't': + tmpdir_s = optarg; + if (verify_mount(tmpdir_s, pwd) < 0) return -1; + break; + case 'h': + homedir_s = optarg; + if (verify_mount(homedir_s, pwd) < 0) return -1; + if (verify_mount(pwd->pw_dir, pwd) < 0) return -1; + break; + default: + fprintf(stderr, "%s\n", USAGE_STRING); + return -1; + } + } + + if (! homedir_s && ! tmpdir_s) { + fprintf(stderr, "Error: tmpdir and/or homedir required \n" + "%s\n", USAGE_STRING); + return -1; + } + + if (argc - optind < 2) { + fprintf(stderr, "Error: executable required \n" + "%s\n", USAGE_STRING); + return -1; + } + + scontext = argv[optind++]; + + if (set_signal_handles()) + return -1; + + if (unshare(CLONE_NEWNS) < 0) { + perror("Failed to unshare"); + return -1; + } + + if (homedir_s && mount(homedir_s, pwd->pw_dir, NULL, MS_BIND, NULL) < 0) { + perror("Failed to mount HOMEDIR"); + return -1; + } + + if (homedir_s && verify_mount(pwd->pw_dir, pwd) < 0) + return -1; + + if (tmpdir_s && mount(tmpdir_s, "/tmp", NULL, MS_BIND, NULL) < 0) { + perror("Failed to mount /tmp"); + return -1; + } + + if (tmpdir_s && verify_mount("/tmp", pwd) < 0) + return -1; + + if (drop_capabilities(uid)) { + perror("Failed to drop all capabilities"); + return -1; + } + + int child = fork(); + 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 ((rc = clearenv())) { + perror("Unable to clear environment"); + free(display); + exit(-1); + } + + if (setexeccon(scontext)) { + fprintf(stderr, "Could not set exec context to %s.\n", + scontext); + free(display); + exit(-1); + } + + if (display) + rc |= setenv("DISPLAY", display, 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 (chdir(pwd->pw_dir)) { + 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); + } + + return status; +} ^ permalink raw reply related [flat|nested] 9+ messages in thread
end of thread, other threads:[~2009-12-30 19:48 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-09-30 18:33 Add modules support to semanage Daniel J Walsh 2009-11-11 18:52 ` Chad Sellers 2009-11-12 16:23 ` Daniel J Walsh 2009-11-18 20:24 ` Chad Sellers 2009-11-18 20:28 ` Daniel J Walsh 2009-11-18 21:53 ` Chad Sellers 2009-11-12 16:45 ` Daniel J Walsh 2009-12-30 19:48 ` Chad Sellers 2009-11-12 16:46 ` Daniel J Walsh
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.