[Rpm-maint] [PATCH 12/12] Relabel files using fixfiles
Steve Lawrence
slawrence at tresys.com
Thu Oct 22 18:25:49 UTC 2009
If policy installation is postponed due to missing dependencies, it is
possible that file contexts have changed after files have been put on
the system. In this case, relabel files using fixfiles.
Fixfiles is too complicated to re-implement in C/rpm, so we can't easily
create a fallback ala semodule/libsemanage in cases where it can't be
executed (e.g. cross install chroots). If fixfiles fails, we just let
the user know, and suggest they manually relabel the chroot.
Also use selinux_file_context_path to get the path to the file_contexts
file instead of the macro %_install_file_context_path. Macros are cached,
and it's possible the path will change during a transaction if policy
type changes, so we need to make sure we have the correct path.
Note: This patch requires libselinux >= 2.0.88
---
configure.ac | 5 ++
lib/rpmpol.c | 5 +-
lib/transaction.c | 184 +++++++++++++++++++++++++++++++++++++++++++++++++++-
macros.in | 1 +
4 files changed, 187 insertions(+), 8 deletions(-)
diff --git a/configure.ac b/configure.ac
index 6231c57..1f9e8dc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -136,6 +136,7 @@ AC_PATH_PROG(__CHOWN, chown, /bin/chown, $MYPATH)
AC_PATH_PROG(__CP, cp, /bin/cp, $MYPATH)
AC_PATH_PROG(__CPIO, cpio, /bin/cpio, $MYPATH)
AC_PATH_PROG(__CURL, curl, /usr/bin/curl, $MYPATH)
+AC_PATH_PROG(__FIXFILES, fixfiles, /sbin/fixfiles, $MYPATH)
AC_PATH_PROG(__FILE, file, /usr/bin/file, $MYPATH)
AC_PATH_PROG(__GPG, gpg, /usr/bin/gpg, $MYPATH)
AC_PATH_PROG(__GREP, grep, /bin/grep, $MYPATH)
@@ -731,8 +732,12 @@ AS_IF([test "$with_selinux" = yes],[
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_file_context_path],[],[
+ AC_MSG_ERROR([--with-selinux given, but selinux_file_context_path 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])
diff --git a/lib/rpmpol.c b/lib/rpmpol.c
index ef13b55..2edee0c 100644
--- a/lib/rpmpol.c
+++ b/lib/rpmpol.c
@@ -1151,7 +1151,6 @@ rpmRC rpmpolsInstall(rpmpols ps, const char * root, const char * cwd)
rpmpoltrans ptrans = NULL;
rpmRC rc = RPMRC_FAIL;
int chrootDone = 0;
- char * fcpath;
if (!ps || (root && !cwd)) {
return rc;
@@ -1191,11 +1190,9 @@ rpmRC rpmpolsInstall(rpmpols ps, const char * root, const char * cwd)
}
matchpathcon_fini();
- fcpath = rpmGetPath("%{?_install_file_context_path}", NULL);
- if (matchpathcon_init(fcpath) == -1) {
+ if (matchpathcon_init(selinux_file_context_path()) == -1) {
rpmlog(RPMLOG_WARNING, _("Failed to read new file contexts. New files may be mislabeled.\n"));
}
- _free(fcpath);
err:
ptrans = rpmpoltransFree(ptrans);
diff --git a/lib/transaction.c b/lib/transaction.c
index 74dbeea..648be77 100644
--- a/lib/transaction.c
+++ b/lib/transaction.c
@@ -928,6 +928,162 @@ static int runTransScripts(rpmts ts, rpmTag stag)
}
/*
+ * save the current file_contexts file to a temporary location.
+ * the caller must remove the file when done with it.
+ * @param ts rpm transaction set
+ * @param fc temporary location of saved file_contexts file. if file_contexts does not
+ * exist or could not be copied, fc is set to NULL. if fc is not NULL, the
+ * caller must unlink the file and free fc
+ */
+static void rpmtsSaveFileContexts(rpmts ts, char ** fc)
+{
+ const char * rootDir;
+ int dochroot;
+ const char * currFC;
+ char * tmpFC = NULL;
+ FD_t sfd = NULL;
+ FD_t tfd = NULL;
+
+ *fc = NULL;
+
+ if (!ts) {
+ return;
+ }
+
+ rootDir = rpmtsRootDir(ts);
+ dochroot = (rootDir != NULL && !rstreq(rootDir, "/") && *rootDir == '/');
+
+ /* enter chroot */
+ if (!rpmtsChrootDone(ts)) {
+ if (dochroot) {
+ if (chdir("/") == -1) {
+ rpmlog(RPMLOG_ERR, _("Failed to chdir: %s\n"), strerror(errno));
+ goto exit;
+ }
+
+ if (chroot(rootDir) == -1) {
+ rpmlog(RPMLOG_ERR, _("Failed to chroot: %s\n"), strerror(errno));
+ goto exit;
+ }
+
+ rpmtsSetChrootDone(ts, 1);
+ }
+ }
+
+ currFC = selinux_file_context_path();
+ if (access(currFC, R_OK) == -1) {
+ goto exit;
+ }
+
+ sfd = Fopen(currFC, "r.ufdio");
+ if (!sfd) {
+ goto exit;
+ }
+
+ tfd = rpmMkTempFile(NULL, &tmpFC);
+ if (!tfd) {
+ goto exit;
+ }
+
+ if (ufdCopy(sfd, tfd) < 0) {
+ goto exit;
+ }
+
+ *fc = xstrdup(tmpFC);
+
+exit:
+ /* exit chroot */
+ if (rpmtsChrootDone(ts)) {
+ const char * currDir = rpmtsCurrDir(ts);
+ chroot(".");
+ rpmtsSetChrootDone(ts, 0);
+ if (currDir != NULL) {
+ chdir(currDir);
+ }
+ }
+
+ if (tfd) Fclose(tfd);
+ if (sfd) Fclose(sfd);
+ _free(tmpFC);
+}
+
+/*
+ * Execute `fixfiles -C prevFC restore` to relabel only files that need to be relabeld
+ * @param ts rpm transaction set
+ * @param prevFC previous file context to diff new file context against
+ * @return RPMRC_OK if fixfiles run with no problems, RPMRC_FAIL otherwise
+ */
+static rpmRC rpmtsRelabelFiles(rpmts ts, const char * prevFC)
+{
+ pid_t pid;
+ int status;
+ rpmRC rc = RPMRC_FAIL;
+
+ if (!ts) {
+ return rc;
+ }
+
+ const char * rootDir = rpmtsRootDir(ts);
+ int dochroot = (rootDir != NULL && !rstreq(rootDir, "/") && *rootDir == '/');
+
+ /* enter chroot */
+ if (!rpmtsChrootDone(ts)) {
+ if (dochroot) {
+ if (chdir("/") == -1) {
+ rpmlog(RPMLOG_ERR, _("Failed to chdir: %s\n"), strerror(errno));
+ goto exit;
+ }
+
+ if (chroot(rootDir) == -1) {
+ rpmlog(RPMLOG_ERR, _("Failed to chroot: %s\n"), strerror(errno));
+ goto exit;
+ }
+
+ rpmtsSetChrootDone(ts, 1);
+ }
+ }
+
+ if (!prevFC) {
+ prevFC = "/dev/null";
+ }
+
+ /* execute fixfiles -C prevFC */
+ pid = fork();
+ switch (pid) {
+ case -1:
+ rpmlog(RPMLOG_ERR, "Failed to fork process: %s\n", strerror(errno));
+ goto exit;
+ break;
+ case 0:
+ freopen("/dev/null", "r", stdin);
+ freopen("/dev/null", "w", stdout);
+ freopen("/dev/null", "w", stderr);
+ execl(rpmExpand("%{__fixfiles}", NULL), "fixfiles", "-C", prevFC, "restore", NULL);
+ exit(1);
+ default:
+ waitpid(pid, &status, 0);
+ if (!WIFEXITED(status) || WEXITSTATUS(status)) {
+ goto exit;
+ }
+ }
+
+ rc = RPMRC_OK;
+
+exit:
+ /* exit chroot */
+ if (rpmtsChrootDone(ts)) {
+ const char * currDir = rpmtsCurrDir(ts);
+ chroot(".");
+ rpmtsSetChrootDone(ts, 0);
+ if (currDir != NULL) {
+ chdir(currDir);
+ }
+ }
+
+ return rc;
+}
+
+/*
* Extract and load selinux policy for transaction set
* @param ts Transaction set
* @return RPMRC_OK on success, rpmRC error code otherwise
@@ -1122,11 +1278,9 @@ static int rpmtsSetup(rpmts ts, rpmprobFilterFlags ignoreSet)
return -1;
}
}
- char *fn = rpmGetPath("%{?_install_file_context_path}", NULL);
- if (matchpathcon_init(fn) == -1) {
+ if (matchpathcon_init(selinux_file_context_path()) == -1) {
rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_NOCONTEXTS));
}
- _free(fn);
if (dochroot) {
if (chroot(".") == -1) {
rpmlog(RPMLOG_ERR, "Failed to exit chroot: %s\n", strerror(errno));
@@ -1302,6 +1456,8 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
{
int rc = -1; /* assume failure */
void * lock = NULL;
+ int postponePolicy = 0;
+ char * savedFC = NULL;
/* XXX programmer error segfault avoidance. */
if (rpmtsNElements(ts) <= 0) {
@@ -1326,7 +1482,11 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
if (!((rpmtsFlags(ts) & (RPMTRANS_FLAG_BUILD_PROBS|RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_NOPOLICY))
|| (rpmpsNumProblems(ts->probs) &&
(okProbs == NULL || rpmpsTrim(ts->probs, okProbs))))) {
- if (rpmtsLoadPolicy(ts) != RPMRC_OK) {
+ int xx = rpmtsLoadPolicy(ts);
+ if (xx == RPMRC_MISSINGDEPS) {
+ rpmtsSaveFileContexts(ts, &savedFC);
+ postponePolicy = 1;
+ } else if (xx != RPMRC_OK) {
goto exit;
}
}
@@ -1362,6 +1522,22 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
runTransScripts(ts, RPMTAG_POSTTRANS);
}
+ /* load policy and relabel files if policy was postponed */
+ if (postponePolicy) {
+ selinux_reset_config();
+
+ if (rpmtsLoadPolicy(ts) == RPMRC_OK) {
+ if (rpmtsRelabelFiles(ts, savedFC) != RPMRC_OK) {
+ rpmlog(RPMLOG_WARNING, "Failed to relabel files after installing policy. Some files may be mislabeled.\n");
+ }
+ }
+
+ if (savedFC) {
+ unlink(savedFC);
+ _free(savedFC);
+ }
+ }
+
/* Finish up... */
(void) rpmtsFinish(ts);
diff --git a/macros.in b/macros.in
index c7c6564..1f569e4 100644
--- a/macros.in
+++ b/macros.in
@@ -40,6 +40,7 @@
%__cp @__CP@
%__cpio @__CPIO@
%__file @__FILE@
+%__fixfiles @__FIXFILES@
%__gpg @__GPG@
%__grep @__GREP@
%__gzip @__GZIP@
--
1.6.0.6
More information about the Rpm-maint
mailing list