[Rpm-maint] [PATCH 5/6] Add SELinux policy plugin

Steve Lawrence slawrence at tresys.com
Wed Jul 14 20:40:47 UTC 2010


This adds a new plugin specifically for a collection to load SELinux
policy. This implements the post_add and pre_remove plugin hooks.  The
only time pre_remove does anything is if post_add was not called (i.e.
if the transaction only removes policies).

This plugin loops through all packages in the sepolicy collection and
extracts the included policies. It then determines which policies should
be installed/removed based on if the package is being installed/removed
and the type of the policy and the system policy. It then executes
semodule (or uses libsemanage if semodule cannot be executed or
installing in a chroot) to remove and install the necessary policies. It
then reloads the selinux state, reloads the file contexts, and if
necessary, relabels the file system.
---
 configure.ac        |   49 ++++-
 macros.in           |    3 +
 plugins/Makefile.am |    5 +-
 plugins/sepolicy.c  |  668 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 721 insertions(+), 4 deletions(-)
 create mode 100644 plugins/sepolicy.c

diff --git a/configure.ac b/configure.ac
index c593b6c..8700c67 100644
--- a/configure.ac
+++ b/configure.ac
@@ -109,6 +109,7 @@ AC_PATH_PROG(__MAKE, make, /usr/bin/make, $MYPATH)
 AC_PATH_PROG(__MKDIR, mkdir, /bin/mkdir, $MYPATH)
 AC_PATH_PROG(__MV, mv, /bin/mv, $MYPATH)
 AC_PATH_PROG(__PATCH, patch, /usr/bin/patch, $MYPATH)
+AC_PATH_PROG(__RESTORECON, restorecon, /sbin/restorecon, $MYPATH)
 AC_MSG_CHECKING(old version of patch)
     PATCHVERSION=`patch --version 2>&1`
 
@@ -126,6 +127,7 @@ AC_PATH_PROG(__PYTHON, python, /usr/bin/python, $MYPATH)
 AC_PATH_PROG(__RM, rm, /bin/rm, $MYPATH)
 AC_PATH_PROG(__RSH, rsh, /usr/bin/rsh, $MYPATH)
 AC_PATH_PROG(__SED, sed, /bin/sed, $MYPATH)
+AC_PATH_PROG(__SEMODULE, semodule, /usr/bin/semodule, $MYPATH)
 AC_PATH_PROG(__SSH, ssh, /usr/bin/ssh, $MYPATH)
 AC_PATH_PROG(__TAR, tar, /bin/tar, $MYPATH)
 
@@ -572,8 +574,14 @@ esac],
 
 AS_IF([test "$with_selinux" = yes],[
   AC_CHECK_HEADER([selinux/selinux.h],[
-    AC_CHECK_LIB(selinux,[is_selinux_enabled],[with_selinux=yes],[
-      AC_MSG_ERROR([--with-selinux given, but libselinux not found])])
+    save_LIBS="$LIBS"
+    AC_CHECK_LIB([selinux],[is_selinux_enabled],[],[
+      AC_MSG_ERROR([--with-selinux given, but is_selinux_enabled not found in libselinux])])
+    AC_CHECK_LIB([selinux],[selinux_getpolicytype],[],[
+      AC_MSG_ERROR([--with-selinux given, but selinux_getpolicytype not found in libselinux])])
+    AC_CHECK_LIB([selinux],[selinux_reset_config],[],[
+      AC_MSG_ERROR([--with-selinux given, but selinux_reset_config not found in libselinux])])
+    LIBS="$save_LIBS"
   ],[
     AC_MSG_ERROR([--with-selinux given, but selinux/selinux.h not found])
   ])
@@ -590,11 +598,46 @@ AS_IF([test "$with_selinux" = yes],[
   ],[
     AC_MSG_ERROR([--with-selinux given, but selinux/label.h not found])
   ])
+
+  AC_CHECK_HEADER([semanage/semanage.h],[
+    save_LIBS="$LIBS"
+    AC_CHECK_LIB([semanage],[semanage_begin_transaction],[],[
+      AC_MSG_ERROR([--with-selinux given, but semanage_begin_transaction missing in libsemanage])])
+    AC_CHECK_LIB([semanage],[semanage_commit],[],[
+      AC_MSG_ERROR([--with-selinux given, but semanage_commit missing in libsemanage])])
+    AC_CHECK_LIB([semanage],[semanage_connect],[],[
+      AC_MSG_ERROR([--with-selinux given, but semanage_connect missing in libsemanage])])
+    AC_CHECK_LIB([semanage],[semanage_disconnect],[],[
+      AC_MSG_ERROR([--with-selinux given, but semanage_disconnect missing in libsemanage])])
+    AC_CHECK_LIB([semanage],[semanage_handle_create],[],[
+      AC_MSG_ERROR([--with-selinux given, but semanage_handle_create missing in libsemanage])])
+    AC_CHECK_LIB([semanage],[semanage_handle_destroy],[],[
+      AC_MSG_ERROR([--with-selinux given, but semanage_handle_destroy missing in libsemanage])])
+    AC_CHECK_LIB([semanage],[semanage_is_connected],[],[
+      AC_MSG_ERROR([--with-selinux given, but semanage_is_connected missing in libsemanage])])
+    AC_CHECK_LIB([semanage],[semanage_module_install_base_file],[],[
+      AC_MSG_ERROR([--with-selinux given, but semanage_module_install_base_file missing in libsemanage])])
+    AC_CHECK_LIB([semanage],[semanage_module_install_file],[],[
+      AC_MSG_ERROR([--with-selinux given, but semanage_module_install_file missing in libsemanage])])
+    AC_CHECK_LIB([semanage],[semanage_module_remove],[],[
+      AC_MSG_ERROR([--with-selinux given, but semanage_module_remove missing in libsemanage])])
+    AC_CHECK_LIB([semanage],[semanage_select_store],[],[
+      AC_MSG_ERROR([--with-selinux given, but semanage_select_store missing in libsemanage])])
+    AC_CHECK_LIB([semanage],[semanage_set_check_contexts],[],[
+      AC_MSG_ERROR([--with-selinux given, but semanage_set_check_contexts missing in libsemanage])])
+    AC_CHECK_LIB([semanage],[semanage_set_create_store],[],[
+      AC_MSG_ERROR([--with-selinux given, but semanage_set_create_store missing in libsemanage])])
+    AC_CHECK_LIB([semanage],[semanage_set_reload],[],[
+      AC_MSG_ERROR([--with-selinux given, but semanage_set_reload missing in libsemanage])])
+    LIBS="$save_LIBS"
+  ],[
+    AC_MSG_ERROR([--with-selinux given, but semanage/semanage.h not found])
+  ])
 ])
 
 AS_IF([test "$with_selinux" = yes],[
   AC_DEFINE(WITH_SELINUX, 1, [Build with selinux support?])
-  WITH_SELINUX_LIB="-lselinux"
+  WITH_SELINUX_LIB="-lselinux -lsemanage"
 ])
 AC_SUBST(WITH_SELINUX_LIB)
 AM_CONDITIONAL(SELINUX,[test "$with_selinux" = yes])
diff --git a/macros.in b/macros.in
index bf49d04..ff44255 100644
--- a/macros.in
+++ b/macros.in
@@ -57,9 +57,11 @@
 %__patch		@__PATCH@
 %__perl			@__PERL@
 %__python		@__PYTHON@
+%__restorecon		@__RESTORECON@
 %__rm			@__RM@
 %__rsh			@__RSH@
 %__sed			@__SED@
+%__semodule		@__SEMODULE@
 %__ssh			@__SSH@
 %__tar			@__TAR@
 %__unzip		@__UNZIP@
@@ -1164,6 +1166,7 @@ done \
 %__plugindir		%{_rpmconfigdir}/plugins
 %__collection_font	%{__plugindir}/exec.so /usr/bin/fc-cache
 %__collection_java	%{__plugindir}/exec.so /usr/bin/rebuild-gcj-db
+%__collection_sepolicy		%{__plugindir}/sepolicy.so
 
 # \endverbatim
 #*/
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 41a9ca4..fe2c9e1 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -13,7 +13,10 @@ AM_LDFLAGS = -avoid-version -module -shared
 
 pluginsdir = $(rpmconfigdir)/plugins
 
-plugins_LTLIBRARIES = exec.la
+plugins_LTLIBRARIES = exec.la sepolicy.la
 
 exec_la_SOURCES = collection.h exec.c
 exec_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
+
+sepolicy_la_SOURCES = collection.h sepolicy.c
+sepolicy_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la @WITH_SELINUX_LIB@
diff --git a/plugins/sepolicy.c b/plugins/sepolicy.c
new file mode 100644
index 0000000..f50c21a
--- /dev/null
+++ b/plugins/sepolicy.c
@@ -0,0 +1,668 @@
+#include "collection.h"
+
+#if WITH_SELINUX
+
+#include <errno.h>
+#include <selinux/selinux.h>
+#include <semanage/semanage.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <rpm/rpmpol.h>
+#include <rpm/rpmfileutil.h>
+#include <rpm/rpmmacro.h>
+
+#include "rpmio/base64.h"
+#include "lib/rpmte_internal.h"
+
+rpmCollHook COLLECTION_HOOKS = COLLHOOK_POST_ADD | COLLHOOK_PRE_REMOVE;
+
+typedef enum sepolAction {
+    SEPOL_ACTION_IGNORE,
+    SEPOL_ACTION_INSTALL,
+    SEPOL_ACTION_REMOVE
+} sepolAction;
+
+typedef struct sepol {
+    char *data;			/*!< policy data */
+    char *name;			/*!< policy names */
+    ARGV_t types;		/*!< policy types */
+    uint32_t flags;		/*!< policy flags */
+    sepolAction action;		/*!< install/remove/ignore */
+    struct sepol *next;		/*!< next in linked list */
+} sepol;
+
+typedef struct sepoltrans {
+    int execsemodule;		/*!< 0 = use libsemanage to install policy; non-zero = use semodule */
+    semanage_handle_t *sh;	/*!< handle to libsemanage, only used when execsemodule is zero */
+    char *semodulepath;		/*!< path to semodule binary */
+    ARGV_t semodargs;		/*!< argument list to pass to semodule, only used when execsemodule is non-zero */
+    ARGV_t filelist;		/*!< list of temporary files that have been written to disk during the transaction */
+    int changes;		/*!< number of changes made during the transaction */
+} sepoltrans;
+
+
+static sepol *sepolNew(rpmte te);
+static sepol *sepolFree(sepol * pol);
+static int sepolHasType(const sepol * pol, const char *type);
+
+static sepol *sepolReadPolicies(rpmts ts, const char *collname);
+static rpmRC sepolPreparePolicies(sepol * pols, const char *policytype);
+static rpmRC sepolWritePolicy(const sepol * pol, char **path);
+static rpmRC sepolLoadPolicies(const sepol * pols);
+
+static sepoltrans *sepoltransNew(void);
+static sepoltrans *sepoltransFree(sepoltrans * pt);
+
+static rpmRC sepoltransInstall(sepoltrans * pt, const sepol * pol);
+static rpmRC sepoltransRemove(sepoltrans * pt, const sepol * pol);
+static rpmRC sepoltransCommit(sepoltrans * pt);
+
+
+static sepol *sepolNew(rpmte te)
+{
+    sepol *head = NULL;
+    sepol *ret = NULL;
+    sepolAction action;
+    Header h;
+    struct rpmtd_s policies, names, types, typesidx, flags;
+    int i, j;
+    int count;
+
+    rpmtdReset(&policies);
+    rpmtdReset(&names);
+    rpmtdReset(&types);
+    rpmtdReset(&typesidx);
+    rpmtdReset(&flags);
+
+    h = rpmteHeaderOpen(te);
+    if (!h) {
+	goto exit;
+    }
+
+    if (!headerIsEntry(h, RPMTAG_POLICIES)) {
+	goto exit;
+    }
+
+    if (!headerGet(h, RPMTAG_POLICIES, &policies, HEADERGET_MINMEM)) {
+	goto exit;
+    }
+
+    count = rpmtdCount(&policies);
+    if (count <= 0) {
+	goto exit;
+    }
+
+    if (!headerGet(h, RPMTAG_POLICYNAMES, &names, HEADERGET_MINMEM)
+	|| rpmtdCount(&names) != count) {
+	goto exit;
+    }
+
+    if (!headerGet(h, RPMTAG_POLICYFLAGS, &flags, HEADERGET_MINMEM)
+	|| rpmtdCount(&flags) != count) {
+	goto exit;
+    }
+
+    if (!headerGet(h, RPMTAG_POLICYTYPES, &types, HEADERGET_MINMEM)) {
+	goto exit;
+    }
+
+    if (!headerGet(h, RPMTAG_POLICYTYPESINDEXES, &typesidx, HEADERGET_MINMEM)
+	|| rpmtdCount(&types) != rpmtdCount(&typesidx)) {
+	goto exit;
+    }
+
+    action = (rpmteType(te) == TR_ADDED) ? SEPOL_ACTION_INSTALL : SEPOL_ACTION_REMOVE;
+
+    for (i = 0; i < count; i++) {
+	sepol *pol = xcalloc(1, sizeof(*pol));
+	pol->next = head;
+	head = pol;
+
+	pol->data = xstrdup(rpmtdNextString(&policies));
+	pol->name = xstrdup(rpmtdNextString(&names));
+	pol->flags = *rpmtdNextUint32(&flags);
+	pol->action = action;
+
+	for (j = 0; j < rpmtdCount(&types); j++) {
+	    uint32_t index = ((uint32_t *) typesidx.data)[j];
+	    if (index < 0 || index >= count) {
+		goto exit;
+	    }
+	    if (index != i) {
+		continue;
+	    }
+	    argvAdd(&pol->types, rpmtdNextString(&types));
+	}
+	argvSort(pol->types, NULL);
+    }
+
+    ret = head;
+
+  exit:
+    headerFree(h);
+
+    rpmtdFreeData(&policies);
+    rpmtdFreeData(&names);
+    rpmtdFreeData(&types);
+    rpmtdFreeData(&typesidx);
+    rpmtdFreeData(&flags);
+
+    if (!ret) {
+	sepolFree(head);
+    }
+
+    return ret;
+}
+
+static sepol *sepolFree(sepol * pol)
+{
+    while (pol) {
+	sepol *next = pol->next;
+
+	pol->data = _free(pol->data);
+	pol->name = _free(pol->name);
+	pol->types = argvFree(pol->types);
+	pol->next = NULL;
+	_free(pol);
+
+	pol = next;
+    }
+
+    return NULL;
+}
+
+int sepolHasType(const sepol * pol, const char *type)
+{
+    if (!pol || !type) {
+	return 0;
+    }
+
+    return (argvSearch(pol->types, type, NULL) != NULL) ||
+	   (argvSearch(pol->types, RPMPOL_TYPE_DEFAULT, NULL) != NULL);
+}
+
+static sepol *sepolReadPolicies(rpmts ts, const char *collname)
+{
+    rpmtsi pi;
+    rpmte p;
+    sepol *head = NULL;
+    sepol *tail = NULL;
+
+    /* read all the policy modules from the collection */
+    pi = rpmtsiInit(ts);
+    while ((p = rpmtsiNext(pi, 0)) != NULL) {
+	sepol *pols;
+	sepol *polsTail;
+
+	if (!rpmteHasCollection(p, collname)) {
+	    continue;
+	}
+
+	pols = sepolNew(p);
+	if (!pols) {
+	    /* something's wrong with the policy information, either missing or
+	     * corrupt. abort */
+	    rpmlog(RPMLOG_ERR, _("Failed to extract policy from %s\n"),
+		   rpmteNEVRA(p));
+	    head = sepolFree(head);
+	    goto err;
+	}
+
+	/* find the tail of pols */
+	polsTail = pols;
+	while (polsTail->next) {
+	    polsTail = polsTail->next;
+	}
+
+	/* add the new pols to the list */
+	if (!head) {
+	    head = pols;
+	    tail = polsTail;
+	} else {
+	    if (rpmteType(p) == TR_ADDED) {
+		/* add to the end of the list */
+		tail->next = pols;
+		tail = polsTail;
+	    } else {
+		/* add to the beginning of the list */
+		polsTail->next = head;
+		head = pols;
+	    }
+	}
+    }
+
+  err:
+    pi = rpmtsiFree(pi);
+
+    return head;
+}
+
+static rpmRC sepolPreparePolicies(sepol * pols, const char *policytype)
+{
+    sepol *pol;
+    rpmRC rc = RPMRC_OK;
+
+    for (pol = pols; pol; pol = pol->next) {
+	if (!sepolHasType(pol, policytype)) {
+	    pol->action = SEPOL_ACTION_IGNORE;
+	}
+    }
+
+    return rc;
+}
+
+static rpmRC sepolWritePolicy(const sepol * pol, char **path)
+{
+    char *tmppath = NULL;
+    FD_t fd = NULL;
+    char *policy = NULL;
+    size_t policylen;
+    int rc = RPMRC_FAIL;
+
+    if (b64decode(pol->data, (void **) &policy, &policylen) != 0) {
+	rpmlog(RPMLOG_ERR, _("Failed to decode policy for %s\n"),
+	       pol->name);
+	goto exit;
+    }
+
+    fd = rpmMkTempFile(NULL, &tmppath);
+    if (fd == NULL || Ferror(fd)) {
+	rpmlog(RPMLOG_ERR, _("Failed to create temporary file for %s: %s\n"),
+	       pol->name, strerror(errno));
+	goto exit;
+    }
+
+    if (!Fwrite(policy, sizeof(*policy), policylen, fd)) {
+	rpmlog(RPMLOG_ERR, _("Failed to write %s policy to file %s\n"),
+	       pol->name, tmppath);
+	goto exit;
+    }
+
+    *path = tmppath;
+    rc = RPMRC_OK;
+
+  exit:
+    if (fd)
+	Fclose(fd);
+    _free(policy);
+    if (rc != RPMRC_OK)
+	_free(tmppath);
+
+    return rc;
+}
+
+static rpmRC sepolLoadPolicies(const sepol * pols)
+{
+    const sepol *pol;
+    sepoltrans *pt;
+    rpmRC rc = RPMRC_FAIL;
+
+    pt = sepoltransNew();
+    if (!pt) {
+	rc = RPMRC_FAIL;
+	goto err;
+    }
+
+    for (pol = pols; pol; pol = pol->next) {
+	switch (pol->action) {
+	case SEPOL_ACTION_REMOVE:
+	    rc = sepoltransRemove(pt, pol);
+	    break;
+	case SEPOL_ACTION_INSTALL:
+	    rc = sepoltransInstall(pt, pol);
+	    break;
+	case SEPOL_ACTION_IGNORE:
+	default:
+	    rc = RPMRC_OK;
+	    break;
+	}
+
+	if (rc != RPMRC_OK) {
+	    goto err;
+	}
+    }
+
+    rc = sepoltransCommit(pt);
+    if (rc != RPMRC_OK) {
+	goto err;
+    }
+
+  err:
+    pt = sepoltransFree(pt);
+
+    return rc;
+}
+
+static sepoltrans *sepoltransNew(void)
+{
+    sepoltrans *pt = xcalloc(1, sizeof(*pt));
+    pt->semodulepath = rpmExpand("%{__semodule}", NULL);
+    pt->execsemodule = (!rpmChrootDone() && access(pt->semodulepath, X_OK) == 0);
+    pt->changes = 0;
+
+    if (pt->execsemodule) {
+	argvAdd(&pt->semodargs, "semodule");
+    } else {
+	pt->sh = semanage_handle_create();
+	if (!pt->sh) {
+	    rpmlog(RPMLOG_ERR, _("Failed to create semanage handle\n"));
+	    goto err;
+	}
+	semanage_set_create_store(pt->sh, 1);
+	semanage_set_check_contexts(pt->sh, 0);
+	if (semanage_connect(pt->sh) < 0) {
+	    rpmlog(RPMLOG_ERR, _("Failed to connect to policy handler\n"));
+	    goto err;
+	}
+	if (semanage_begin_transaction(pt->sh) < 0) {
+	    rpmlog(RPMLOG_ERR, _("Failed to begin policy transaction: %s\n"),
+		   errno ? strerror(errno) : "");
+	    goto err;
+	}
+	semanage_set_reload(pt->sh, !rpmChrootDone());
+    }
+
+    return pt;
+
+  err:
+    if (pt->sh) {
+	if (semanage_is_connected(pt->sh)) {
+	    semanage_disconnect(pt->sh);
+	}
+	semanage_handle_destroy(pt->sh);
+    }
+    pt = _free(pt);
+
+    return pt;
+}
+
+static sepoltrans *sepoltransFree(sepoltrans * pt)
+{
+    ARGV_t file;
+
+    if (!pt) {
+	return NULL;
+    }
+
+    for (file = pt->filelist; file && *file; file++) {
+	if (unlink(*file) < 0) {
+	    rpmlog(RPMLOG_WARNING, _("Failed to remove temporary policy file %s: %s\n"),
+		   *file, strerror(errno));
+	}
+    }
+    argvFree(pt->filelist);
+
+    if (pt->execsemodule) {
+	argvFree(pt->semodargs);
+    } else {
+	semanage_disconnect(pt->sh);
+	semanage_handle_destroy(pt->sh);
+    }
+
+    pt->semodulepath = _free(pt->semodulepath);
+
+    pt = _free(pt);
+    return NULL;
+}
+
+static rpmRC sepoltransInstall(sepoltrans * pt, const sepol * pol)
+{
+    rpmRC rc = RPMRC_OK;
+    char *path = NULL;
+
+    rc = sepolWritePolicy(pol, &path);
+    if (rc != RPMRC_OK) {
+	return rc;
+    }
+    argvAdd(&pt->filelist, path);
+
+    if (pt->execsemodule) {
+	const char *flag = (pol->flags & RPMPOL_FLAG_BASE) ? "-b" : "-i";
+	if (argvAdd(&pt->semodargs, flag) < 0 || argvAdd(&pt->semodargs, path) < 0) {
+	    rc = RPMRC_FAIL;
+	}
+    } else {
+	if (pol->flags & RPMPOL_FLAG_BASE) {
+	    if (semanage_module_install_base_file(pt->sh, path) < 0) {
+		rc = RPMRC_FAIL;
+	    }
+	} else {
+	    if (semanage_module_install_file(pt->sh, path) < 0) {
+		rc = RPMRC_FAIL;
+	    }
+	}
+    }
+
+    if (rc != RPMRC_OK) {
+	rpmlog(RPMLOG_ERR, _("Failed to install policy module: %s (%s)\n"),
+	       pol->name, path);
+    } else {
+	pt->changes++;
+    }
+
+    _free(path);
+
+    return rc;
+}
+
+static rpmRC sepoltransRemove(sepoltrans * pt, const sepol * pol)
+{
+    rpmRC rc = RPMRC_OK;
+
+    if (pol->flags & RPMPOL_FLAG_BASE) {
+	return RPMRC_FAIL;
+    }
+
+    if (pt->execsemodule) {
+	if (argvAdd(&pt->semodargs, "-r") < 0 || argvAdd(&pt->semodargs, pol->name) < 0) {
+	    rc = RPMRC_FAIL;
+	}
+    } else {
+	if (semanage_module_remove(pt->sh, (char *) pol->name) < 0) {
+	    rc = RPMRC_FAIL;
+	}
+    }
+
+    if (rc != RPMRC_OK) {
+	rpmlog(RPMLOG_ERR, _("Failed to remove policy module: %s\n"),
+	       pol->name);
+    } else {
+	pt->changes++;
+    }
+
+    return rc;
+}
+
+static rpmRC sepoltransCommit(sepoltrans * pt)
+{
+    rpmRC rc = RPMRC_OK;
+
+    if (pt->changes == 0) {
+	return rc;
+    }
+
+    if (pt->execsemodule) {
+	int status;
+	pid_t pid = fork();
+	int fd;
+
+	switch (pid) {
+	case -1:
+	    rpmlog(RPMLOG_ERR, _("Failed to fork process: %s\n"),
+		   strerror(errno));
+	    rc = RPMRC_FAIL;
+	    break;
+	case 0:
+	    fd = open("/dev/null", O_RDWR);
+	    dup2(fd, STDIN_FILENO);
+	    dup2(fd, STDOUT_FILENO);
+	    dup2(fd, STDERR_FILENO);
+	    execv(pt->semodulepath, pt->semodargs);
+	    rpmlog(RPMLOG_ERR, _("Failed to execute %s: %s\n"),
+		   pt->semodulepath, strerror(errno));
+	    exit(1);
+	default:
+	    waitpid(pid, &status, 0);
+	    if (!WIFEXITED(status)) {
+		rpmlog(RPMLOG_ERR, _("%s terminated abnormally\n"),
+		       pt->semodulepath);
+		rc = RPMRC_FAIL;
+	    } else if (WEXITSTATUS(status)) {
+		rpmlog(RPMLOG_ERR, _("%s failed with exit code %i\n"),
+		       pt->semodulepath, WEXITSTATUS(status));
+		rc = RPMRC_FAIL;
+	    }
+	}
+    } else {
+	if (semanage_commit(pt->sh) < 0) {
+	    rpmlog(RPMLOG_ERR, _("Failed to commit policy changes\n"));
+	    rc = RPMRC_FAIL;
+	}
+    }
+
+    return rc;
+}
+
+static rpmRC sepolRelabelFiles(void)
+{
+    rpmRC rc = RPMRC_OK;
+    pid_t pid;
+    int fd;
+    int status;
+    char *restoreconPath = rpmExpand("%{__restorecon}", NULL);
+
+    if (!restoreconPath) {
+	rpmlog(RPMLOG_ERR, _("Failed to expand restorecon path"));
+	return RPMRC_FAIL;
+    }
+
+    /* execute restorecon -R / */
+    pid = fork();
+    switch (pid) {
+    case -1:
+	rpmlog(RPMLOG_ERR, _("Failed to fork process: %s\n"),
+	       strerror(errno));
+	rc = RPMRC_FAIL;
+	break;
+    case 0:
+	fd = open("/dev/null", O_RDWR);
+	dup2(fd, STDIN_FILENO);
+	dup2(fd, STDOUT_FILENO);
+	dup2(fd, STDERR_FILENO);
+	execl(restoreconPath, "restorecon", "-R", "/", NULL);
+	rpmlog(RPMLOG_ERR, _("Failed to execute %s: %s\n"), restoreconPath,
+	       strerror(errno));
+	exit(1);
+    default:
+	waitpid(pid, &status, 0);
+	if (!WIFEXITED(status)) {
+	    rpmlog(RPMLOG_ERR, _("%s terminated abnormally\n"),
+		   restoreconPath);
+	    rc = RPMRC_FAIL;
+	} else if (WEXITSTATUS(status)) {
+	    rpmlog(RPMLOG_ERR, _("%s failed with exit code %i\n"),
+		   restoreconPath, WEXITSTATUS(status));
+	    rc = RPMRC_FAIL;
+	}
+    }
+
+    _free(restoreconPath);
+
+    return rc;
+}
+
+
+#endif				/* WITH_SELINUX */
+
+
+rpmRC COLLHOOK_POST_ADD_FUNC(rpmts ts, const char *collname,
+			     const char *options)
+{
+#if WITH_SELINUX
+    sepol *pols;
+    semanage_handle_t *sh;
+    int existingPolicy;
+    char *policytype = NULL;
+    int rc = RPMRC_FAIL;
+
+    pols = sepolReadPolicies(ts, collname);
+    if (!pols) {
+	goto exit;
+    }
+
+    if (rpmChrootIn()) {
+	goto exit;
+    }
+
+    if (selinux_getpolicytype(&policytype) < 0) {
+	goto exit;
+    }
+
+    sepolPreparePolicies(pols, policytype);
+
+    /* determine if this is the first time installing policy */
+    sh = semanage_handle_create();
+    existingPolicy = (semanage_is_managed(sh) == 1);
+    semanage_handle_destroy(sh);
+
+    /* now load the policies */
+    rc = sepolLoadPolicies(pols);
+
+    /* re-init selinux and re-read the files contexts, since things may have changed */
+    selinux_reset_config();
+    if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS)) {
+	if (rpmtsSELabelInit(ts, selinux_file_context_path()) == RPMRC_OK) {
+	    /* if this was the first time installing policy, every package before
+	     * policy was installed will be mislabeled (e.g. semodule). So, relabel
+	     * the entire filesystem if this is the case */
+	    if (!existingPolicy) {
+		if (sepolRelabelFiles() != RPMRC_OK) {
+		    rpmlog(RPMLOG_WARNING, _("Failed to relabel filesystem. Files may be mislabeled\n"));
+		}
+	    }
+	} else {
+	    rpmlog(RPMLOG_WARNING, _("Failed to reload file contexts. Files may be mislabeled\n"));
+	}
+    }
+
+  exit:
+    if (rpmChrootOut()) {
+	rc = RPMRC_FAIL;
+    }
+
+    _free(policytype);
+    sepolFree(pols);
+
+    return rc;
+#else
+    return RPMRC_OK;
+#endif
+}
+
+rpmRC COLLHOOK_PRE_REMOVE_FUNC(rpmts ts, const char *collname,
+			       const char *options)
+{
+#if WITH_SELINUX
+    rpmtsi pi;
+    rpmte p;
+    int found = 0;
+
+    /* figure out if post_add was already called. if it was, then nothing needs
+     * to be done here. if it wasn't (like in the case of policy package
+     * removals, but no installs) we need call post_add to perform those removals
+     */
+    pi = rpmtsiInit(ts);
+    while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
+	if (rpmteHasCollection(p, collname)) {
+	    found = 1;
+	    break;
+	}
+    }
+    pi = rpmtsiFree(pi);
+
+    return found ? RPMRC_OK : COLLHOOK_POST_ADD_FUNC(ts, collname, options);
+#else
+    return RPMRC_OK;
+#endif				/* WITH_SELINUX */
+}
-- 
1.6.2.5



More information about the Rpm-maint mailing list