Просмотр исходного кода

dpkg: Reload the SELinux label database if it has changed

Rework the code to use the selabel API instead of the matchpathcon
wrappers, so that we can query if the label database has changed
during the previous unpack, for example while upgrading the SELinux
policy package. This also allows us to more easily free the resources
allocated for the label database.
Guillem Jover лет назад: 13
Родитель
Сommit
866f5d2a97
2 измененных файлов с 78 добавлено и 16 удалено
  1. 2 0
      debian/changelog
  2. 76 16
      src/archives.c

+ 2 - 0
debian/changelog

@@ -54,6 +54,8 @@ dpkg (1.17.0) UNRELEASED; urgency=low
   * Refer to path instead of file on dpkg-statoverride.
   * Always print a descriptive architecture column, even for empty or missing
     architectures on «dpkg-query --list».
+  * Rework SELinux code on unpack to reload the label database if it has
+    changed, for example while upgrading the SELinux policy package.
 
  -- Guillem Jover <guillem@debian.org>  Fri, 03 Aug 2012 13:21:00 +0200
 

+ 76 - 16
src/archives.c

@@ -59,6 +59,8 @@
 
 #ifdef WITH_SELINUX
 #include <selinux/selinux.h>
+#include <selinux/avc.h>
+#include <selinux/label.h>
 #endif
 
 #include "filesdb.h"
@@ -476,11 +478,71 @@ tarobject_set_perms(struct tar_entry *te, const char *path, struct file_stat *st
   }
 }
 
+#ifdef WITH_SELINUX
+static struct selabel_handle *dpkg_sehandle;
+
+static struct selabel_handle *
+dpkg_selabel_get_handle(void)
+{
+  return dpkg_sehandle;
+}
+#endif
+
 static void
-tarobject_set_se_context(const char *matchpath, const char *path, mode_t mode)
+dpkg_selabel_load(void)
 {
 #ifdef WITH_SELINUX
   static int selinux_enabled = -1;
+
+  if (selinux_enabled < 0) {
+    int rc;
+
+    /* Set selinux_enabled if it is not already set (singleton). */
+    selinux_enabled = (is_selinux_enabled() > 0);
+    if (!selinux_enabled)
+      return;
+
+    /* Open the SELinux status notification channel, with fallback enabled
+     * for older kernels. */
+    rc = selinux_status_open(1);
+    if (rc < 0)
+      ohshit(_("cannot open security status notification channel"));
+
+    /* XXX: We could use selinux_set_callback() to redirect the errors from
+     * the other SELinux calls, but that does not seem worth it right now. */
+  } else if (selinux_enabled && selinux_status_updated()) {
+    /* The SELinux policy got updated in the kernel, usually after upgrading
+     * the package shipping it, we need to reload. */
+    selabel_close(dpkg_sehandle);
+  } else {
+    /* SELinux is either disabled or it does not need a reload. */
+    return;
+  }
+
+  dpkg_sehandle = selabel_open(SELABEL_CTX_FILE, NULL, 0);
+  if (dpkg_sehandle == NULL)
+    ohshite(_("cannot get security labeling handle"));
+#endif
+}
+
+static void
+dpkg_selabel_close(void)
+{
+#ifdef WITH_SELINUX
+  if (dpkg_sehandle == NULL)
+    return;
+
+  selinux_status_close();
+  selabel_close(dpkg_sehandle);
+  dpkg_sehandle = NULL;
+#endif
+}
+
+static void
+tarobject_set_se_context(const char *matchpath, const char *path, mode_t mode)
+{
+#ifdef WITH_SELINUX
+  struct selabel_handle *sehandle;
   security_context_t scontext = NULL;
   int ret;
 
@@ -488,26 +550,20 @@ tarobject_set_se_context(const char *matchpath, const char *path, mode_t mode)
   if ((mode & S_IFMT) == 0)
     return;
 
-  /* Set selinux_enabled if it is not already set (singleton). */
-  if (selinux_enabled < 0) {
-    selinux_enabled = (is_selinux_enabled() > 0);
-
-    /* Do not translate from computer to human readable forms, to avoid
-     * issues when mcstransd has disappeared during the unpack process. */
-    if (selinux_enabled)
-      set_matchpathcon_flags(MATCHPATHCON_NOTRANS);
-  }
-
-  /* If SE Linux is not enabled just do nothing. */
-  if (!selinux_enabled)
+  /* If SELinux is not enabled just do nothing. */
+  sehandle = dpkg_selabel_get_handle();
+  if (sehandle == NULL)
     return;
 
-  /* XXX: Well, we could use set_matchpathcon_printf() to redirect the
-   * errors from the following bit, but that seems too much effort. */
+  /*
+   * We use the _raw function variants here so that no translation happens
+   * from computer to human readable forms, to avoid issues when mcstransd
+   * has disappeared during the unpack process.
+   */
 
   /* Do nothing if we can't figure out what the context is, or if it has
    * no context; in which case the default context shall be applied. */
-  ret = matchpathcon(matchpath, mode & S_IFMT, &scontext);
+  ret = selabel_lookup_raw(sehandle, &scontext, matchpath, mode & S_IFMT);
   if (ret == -1 || (ret == 0 && scontext == NULL))
     return;
 
@@ -1590,6 +1646,8 @@ archivefiles(const char *const *argv)
     }
     push_error_context_jump(&ejbuf, print_error_perpackage, thisarg);
 
+    dpkg_selabel_load();
+
     process_archive(thisarg);
     onerr_abort++;
     m_output(stdout, _("<standard output>"));
@@ -1599,6 +1657,8 @@ archivefiles(const char *const *argv)
     pop_error_context(ehflag_normaltidy);
   }
 
+  dpkg_selabel_close();
+
   switch (cipaction->arg_int) {
   case act_install:
   case act_configure: