4 #include <selinux/selinux.h>
5 #include <semanage/semanage.h>
9 #include <rpm/rpmpol.h>
10 #include <rpm/rpmfileutil.h>
11 #include <rpm/rpmmacro.h>
12 #include <rpm/rpmbase64.h>
14 #include "lib/rpmte_internal.h"
15 #include "lib/rpmts_internal.h" /* rpmtsSELabelFoo() */
17 rpmPluginHook PLUGIN_HOOKS = \
19 PLUGINHOOK_CLEANUP | \
21 PLUGINHOOK_COLL_POST_ADD | \
22 PLUGINHOOK_COLL_PRE_REMOVE;
24 typedef enum sepolAction {
30 typedef struct sepol {
31 char *data; /*!< policy data */
32 char *name; /*!< policy names */
33 ARGV_t types; /*!< policy types */
34 uint32_t flags; /*!< policy flags */
35 sepolAction action; /*!< install/remove/ignore */
36 struct sepol *next; /*!< next in linked list */
39 typedef struct sepoltrans {
40 int execsemodule; /*!< 0 = use libsemanage to install policy; non-zero = use semodule */
41 semanage_handle_t *sh; /*!< handle to libsemanage, only used when execsemodule is zero */
42 char *semodulepath; /*!< path to semodule binary */
43 ARGV_t semodargs; /*!< argument list to pass to semodule, only used when execsemodule is non-zero */
44 ARGV_t filelist; /*!< list of temporary files that have been written to disk during the transaction */
45 int changes; /*!< number of changes made during the transaction */
52 static sepol * policiesHead;
53 static sepol * policiesTail;
56 static sepol *sepolNew(rpmte te);
57 static sepol *sepolFree(sepol * pol);
58 static int sepolHasType(const sepol * pol, const char *type);
60 static rpmRC sepolPreparePolicies(sepol * pols, const char *policytype);
61 static rpmRC sepolWritePolicy(const sepol * pol, char **path);
62 static rpmRC sepolLoadPolicies(const sepol * pols);
64 static sepoltrans *sepoltransNew(void);
65 static sepoltrans *sepoltransFree(sepoltrans * pt);
67 static rpmRC sepoltransInstall(sepoltrans * pt, const sepol * pol);
68 static rpmRC sepoltransRemove(sepoltrans * pt, const sepol * pol);
69 static rpmRC sepoltransCommit(sepoltrans * pt);
72 static sepol *sepolNew(rpmte te)
78 struct rpmtd_s policies, names, types, typesidx, flags;
82 rpmtdReset(&policies);
85 rpmtdReset(&typesidx);
93 if (!headerIsEntry(h, RPMTAG_POLICIES)) {
97 if (!headerGet(h, RPMTAG_POLICIES, &policies, HEADERGET_MINMEM)) {
101 count = rpmtdCount(&policies);
106 if (!headerGet(h, RPMTAG_POLICYNAMES, &names, HEADERGET_MINMEM)
107 || rpmtdCount(&names) != count) {
111 if (!headerGet(h, RPMTAG_POLICYFLAGS, &flags, HEADERGET_MINMEM)
112 || rpmtdCount(&flags) != count) {
116 if (!headerGet(h, RPMTAG_POLICYTYPES, &types, HEADERGET_MINMEM)) {
120 if (!headerGet(h, RPMTAG_POLICYTYPESINDEXES, &typesidx, HEADERGET_MINMEM)
121 || rpmtdCount(&types) != rpmtdCount(&typesidx)) {
125 action = (rpmteType(te) == TR_ADDED) ? SEPOL_ACTION_INSTALL : SEPOL_ACTION_REMOVE;
127 for (i = 0; i < count; i++) {
128 sepol *pol = xcalloc(1, sizeof(*pol));
132 pol->data = xstrdup(rpmtdNextString(&policies));
133 pol->name = xstrdup(rpmtdNextString(&names));
134 pol->flags = *rpmtdNextUint32(&flags);
135 pol->action = action;
137 for (j = 0; j < rpmtdCount(&types); j++) {
138 uint32_t index = ((uint32_t *) typesidx.data)[j];
139 if (index < 0 || index >= count) {
145 argvAdd(&pol->types, rpmtdNextString(&types));
147 argvSort(pol->types, NULL);
155 rpmtdFreeData(&policies);
156 rpmtdFreeData(&names);
157 rpmtdFreeData(&types);
158 rpmtdFreeData(&typesidx);
159 rpmtdFreeData(&flags);
168 static sepol *sepolFree(sepol * pol)
171 sepol *next = pol->next;
173 pol->data = _free(pol->data);
174 pol->name = _free(pol->name);
175 pol->types = argvFree(pol->types);
185 int sepolHasType(const sepol * pol, const char *type)
191 return (argvSearch(pol->types, type, NULL) != NULL) ||
192 (argvSearch(pol->types, RPMPOL_TYPE_DEFAULT, NULL) != NULL);
195 static rpmRC sepolPreparePolicies(sepol * pols, const char *policytype)
200 for (pol = pols; pol; pol = pol->next) {
201 if (!sepolHasType(pol, policytype)) {
202 pol->action = SEPOL_ACTION_IGNORE;
209 static rpmRC sepolWritePolicy(const sepol * pol, char **path)
211 char *tmppath = NULL;
215 rpmRC rc = RPMRC_FAIL;
217 if (rpmBase64Decode(pol->data, (void **) &policy, &policylen) != 0) {
218 rpmlog(RPMLOG_ERR, _("Failed to decode policy for %s\n"),
223 fd = rpmMkTempFile(NULL, &tmppath);
224 if (fd == NULL || Ferror(fd)) {
225 rpmlog(RPMLOG_ERR, _("Failed to create temporary file for %s: %s\n"),
226 pol->name, strerror(errno));
230 if (!Fwrite(policy, sizeof(*policy), policylen, fd)) {
231 rpmlog(RPMLOG_ERR, _("Failed to write %s policy to file %s\n"),
249 static rpmRC sepolLoadPolicies(const sepol * pols)
252 rpmRC rc = RPMRC_FAIL;
253 sepoltrans *pt = sepoltransNew();
258 for (pol = pols; pol; pol = pol->next) {
259 switch (pol->action) {
260 case SEPOL_ACTION_REMOVE:
261 rc = sepoltransRemove(pt, pol);
263 case SEPOL_ACTION_INSTALL:
264 rc = sepoltransInstall(pt, pol);
266 case SEPOL_ACTION_IGNORE:
276 rc = sepoltransCommit(pt);
284 static sepoltrans *sepoltransNew(void)
286 sepoltrans *pt = xcalloc(1, sizeof(*pt));
287 pt->semodulepath = rpmExpand("%{__semodule}", NULL);
288 pt->execsemodule = (!rpmChrootDone() && access(pt->semodulepath, X_OK) == 0);
291 if (pt->execsemodule) {
292 argvAdd(&pt->semodargs, "semodule");
294 pt->sh = semanage_handle_create();
296 rpmlog(RPMLOG_ERR, _("Failed to create semanage handle\n"));
299 semanage_set_create_store(pt->sh, 1);
300 semanage_set_check_contexts(pt->sh, 0);
301 if (semanage_connect(pt->sh) < 0) {
302 rpmlog(RPMLOG_ERR, _("Failed to connect to policy handler\n"));
305 if (semanage_begin_transaction(pt->sh) < 0) {
306 rpmlog(RPMLOG_ERR, _("Failed to begin policy transaction: %s\n"),
307 errno ? strerror(errno) : "");
310 semanage_set_reload(pt->sh, !rpmChrootDone());
317 if (semanage_is_connected(pt->sh)) {
318 semanage_disconnect(pt->sh);
320 semanage_handle_destroy(pt->sh);
327 static sepoltrans *sepoltransFree(sepoltrans * pt)
335 for (file = pt->filelist; file && *file; file++) {
336 if (unlink(*file) < 0) {
337 rpmlog(RPMLOG_WARNING, _("Failed to remove temporary policy file %s: %s\n"),
338 *file, strerror(errno));
341 argvFree(pt->filelist);
343 if (pt->execsemodule) {
344 argvFree(pt->semodargs);
346 semanage_disconnect(pt->sh);
347 semanage_handle_destroy(pt->sh);
350 free(pt->semodulepath);
351 memset(pt, 0, sizeof(*pt)); /* trash and burn */
357 static rpmRC sepoltransInstall(sepoltrans * pt, const sepol * pol)
362 rc = sepolWritePolicy(pol, &path);
363 if (rc != RPMRC_OK) {
366 argvAdd(&pt->filelist, path);
368 if (pt->execsemodule) {
369 const char *flag = (pol->flags & RPMPOL_FLAG_BASE) ? "-b" : "-i";
370 if (argvAdd(&pt->semodargs, flag) < 0 || argvAdd(&pt->semodargs, path) < 0) {
374 if (pol->flags & RPMPOL_FLAG_BASE) {
375 if (semanage_module_install_base_file(pt->sh, path) < 0) {
379 if (semanage_module_install_file(pt->sh, path) < 0) {
385 if (rc != RPMRC_OK) {
386 rpmlog(RPMLOG_ERR, _("Failed to install policy module: %s (%s)\n"),
397 static rpmRC sepoltransRemove(sepoltrans * pt, const sepol * pol)
401 if (pol->flags & RPMPOL_FLAG_BASE) {
405 if (pt->execsemodule) {
406 if (argvAdd(&pt->semodargs, "-r") < 0 || argvAdd(&pt->semodargs, pol->name) < 0) {
410 if (semanage_module_remove(pt->sh, (char *) pol->name) < 0) {
415 if (rc != RPMRC_OK) {
416 rpmlog(RPMLOG_ERR, _("Failed to remove policy module: %s\n"),
425 static rpmRC sepoltransCommit(sepoltrans * pt)
429 if (pt->changes == 0) {
433 if (pt->execsemodule) {
440 rpmlog(RPMLOG_ERR, _("Failed to fork process: %s\n"),
445 fd = open("/dev/null", O_RDWR);
446 dup2(fd, STDIN_FILENO);
447 dup2(fd, STDOUT_FILENO);
448 dup2(fd, STDERR_FILENO);
449 execv(pt->semodulepath, pt->semodargs);
450 rpmlog(RPMLOG_ERR, _("Failed to execute %s: %s\n"),
451 pt->semodulepath, strerror(errno));
454 waitpid(pid, &status, 0);
455 if (!WIFEXITED(status)) {
456 rpmlog(RPMLOG_ERR, _("%s terminated abnormally\n"),
459 } else if (WEXITSTATUS(status)) {
460 rpmlog(RPMLOG_ERR, _("%s failed with exit code %i\n"),
461 pt->semodulepath, WEXITSTATUS(status));
466 if (semanage_commit(pt->sh) < 0) {
467 rpmlog(RPMLOG_ERR, _("Failed to commit policy changes\n"));
475 static rpmRC sepolRelabelFiles(void)
481 char *restoreconPath = rpmExpand("%{__restorecon}", NULL);
483 if (!restoreconPath) {
484 rpmlog(RPMLOG_ERR, _("Failed to expand restorecon path"));
488 /* execute restorecon -R / */
492 rpmlog(RPMLOG_ERR, _("Failed to fork process: %s\n"),
497 fd = open("/dev/null", O_RDWR);
498 dup2(fd, STDIN_FILENO);
499 dup2(fd, STDOUT_FILENO);
500 dup2(fd, STDERR_FILENO);
501 execl(restoreconPath, "restorecon", "-R", "/", NULL);
502 rpmlog(RPMLOG_ERR, _("Failed to execute %s: %s\n"), restoreconPath,
506 waitpid(pid, &status, 0);
507 if (!WIFEXITED(status)) {
508 rpmlog(RPMLOG_ERR, _("%s terminated abnormally\n"),
511 } else if (WEXITSTATUS(status)) {
512 rpmlog(RPMLOG_ERR, _("%s failed with exit code %i\n"),
513 restoreconPath, WEXITSTATUS(status));
518 _free(restoreconPath);
523 static rpmRC sepolGo(void)
525 semanage_handle_t *sh;
527 char *policytype = NULL;
528 rpmRC rc = RPMRC_FAIL;
530 static int performed = 0;
540 if (selinux_getpolicytype(&policytype) < 0) {
544 sepolPreparePolicies(policiesHead, policytype);
546 /* determine if this is the first time installing policy */
547 sh = semanage_handle_create();
548 existingPolicy = (semanage_is_managed(sh) == 1);
549 semanage_handle_destroy(sh);
551 /* now load the policies */
552 rc = sepolLoadPolicies(policiesHead);
554 /* re-init selinux and re-read the files contexts, since things may have changed */
555 selinux_reset_config();
556 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS)) {
557 if (rpmtsSELabelInit(ts, 0) == RPMRC_OK) {
558 /* if this was the first time installing policy, every package before
559 * policy was installed will be mislabeled (e.g. semodule). So, relabel
560 * the entire filesystem if this is the case */
561 if (!existingPolicy) {
562 if (sepolRelabelFiles() != RPMRC_OK) {
563 rpmlog(RPMLOG_WARNING, _("Failed to relabel filesystem. Files may be mislabeled\n"));
567 rpmlog(RPMLOG_WARNING, _("Failed to reload file contexts. Files may be mislabeled\n"));
572 if (rpmChrootOut()) {
581 static rpmRC sepolAddTE(rpmte te)
586 if (!rpmteHasCollection(te, name)) {
592 /* something's wrong with the policy information, either missing or
594 rpmlog(RPMLOG_ERR, _("Failed to extract policy from %s\n"),
599 /* find the tail of pol */
601 while (polTail->next) {
602 polTail = polTail->next;
605 /* add the new policy to the list */
608 policiesTail = polTail;
610 if (rpmteType(te) == TR_ADDED) {
611 /* add to the end of the list */
612 policiesTail->next = pol;
613 policiesTail = polTail;
615 /* add to the beginning of the list */
616 polTail->next = policiesHead;
626 rpmRC PLUGINHOOK_INIT_FUNC(rpmts _ts, const char *_name, const char *_opts)
629 name = strdup(_name);
630 policiesHead = policiesTail = NULL;
634 rpmRC PLUGINHOOK_CLEANUP_FUNC(void)
638 policiesHead = policiesTail = sepolFree(policiesHead);
642 rpmRC PLUGINHOOK_OPENTE_FUNC(rpmte te)
644 return sepolAddTE(te);
647 rpmRC PLUGINHOOK_COLL_POST_ADD_FUNC(void)
652 rpmRC PLUGINHOOK_COLL_PRE_REMOVE_FUNC(void)