diff options
Diffstat (limited to 'plugins/sepolicy.c')
-rw-r--r-- | plugins/sepolicy.c | 655 |
1 files changed, 0 insertions, 655 deletions
diff --git a/plugins/sepolicy.c b/plugins/sepolicy.c deleted file mode 100644 index 86bf1981a..000000000 --- a/plugins/sepolicy.c +++ /dev/null @@ -1,655 +0,0 @@ -#include "plugin.h" - -#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 <rpm/rpmbase64.h> - -#include "lib/rpmte_internal.h" -#include "lib/rpmts_internal.h" /* rpmtsSELabelFoo() */ - -rpmPluginHook PLUGIN_HOOKS = \ - PLUGINHOOK_INIT | \ - PLUGINHOOK_CLEANUP | \ - PLUGINHOOK_OPENTE | \ - PLUGINHOOK_COLL_POST_ADD | \ - PLUGINHOOK_COLL_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 char * name; -static rpmts ts; - -static sepol * policiesHead; -static sepol * policiesTail; - - -static sepol *sepolNew(rpmte te); -static sepol *sepolFree(sepol * pol); -static int sepolHasType(const sepol * pol, const char *type); - -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 = rpmteHeader(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 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; - rpmRC rc = RPMRC_FAIL; - - if (rpmBase64Decode(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; - rpmRC rc = RPMRC_FAIL; - sepoltrans *pt = sepoltransNew(); - - if (pt == NULL) - goto exit; - - 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 exit; - } - - rc = sepoltransCommit(pt); - -exit: - 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); - } - free(pt); - - return NULL; -} - -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); - } - - free(pt->semodulepath); - memset(pt, 0, sizeof(*pt)); /* trash and burn */ - - 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; -} - -static rpmRC sepolGo(void) -{ - semanage_handle_t *sh; - int existingPolicy; - char *policytype = NULL; - rpmRC rc = RPMRC_FAIL; - - static int performed = 0; - if (performed) { - return RPMRC_OK; - } - performed = 1; - - if (rpmChrootIn()) { - goto exit; - } - - if (selinux_getpolicytype(&policytype) < 0) { - goto exit; - } - - sepolPreparePolicies(policiesHead, 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(policiesHead); - - /* 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, 0) == 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); - - return rc; -} - -static rpmRC sepolAddTE(rpmte te) -{ - sepol *pol; - sepol *polTail; - - if (!rpmteHasCollection(te, name)) { - return RPMRC_OK; - } - - pol = sepolNew(te); - if (!pol) { - /* something's wrong with the policy information, either missing or - * corrupt. abort */ - rpmlog(RPMLOG_ERR, _("Failed to extract policy from %s\n"), - rpmteNEVRA(te)); - return RPMRC_FAIL; - } - - /* find the tail of pol */ - polTail = pol; - while (polTail->next) { - polTail = polTail->next; - } - - /* add the new policy to the list */ - if (!policiesHead) { - policiesHead = pol; - policiesTail = polTail; - } else { - if (rpmteType(te) == TR_ADDED) { - /* add to the end of the list */ - policiesTail->next = pol; - policiesTail = polTail; - } else { - /* add to the beginning of the list */ - polTail->next = policiesHead; - policiesHead = pol; - } - } - - return RPMRC_OK; -} - - - -rpmRC PLUGINHOOK_INIT_FUNC(rpmts _ts, const char *_name, const char *_opts) -{ - ts = _ts; - name = strdup(_name); - policiesHead = policiesTail = NULL; - return RPMRC_OK; -} - -rpmRC PLUGINHOOK_CLEANUP_FUNC(void) -{ - _free(name); - ts = NULL; - policiesHead = policiesTail = sepolFree(policiesHead); - return RPMRC_OK; -} - -rpmRC PLUGINHOOK_OPENTE_FUNC(rpmte te) -{ - return sepolAddTE(te); -} - -rpmRC PLUGINHOOK_COLL_POST_ADD_FUNC(void) -{ - return sepolGo(); -} - -rpmRC PLUGINHOOK_COLL_PRE_REMOVE_FUNC(void) -{ - return sepolGo(); -} |