Parcourir la source

dpkg: Execute maintainer scripts in a new SELinux execution context

Try to create a new execution context based on the current one and the
specific maintainer script filename. If it is the same as the current
one, use "dpkg_script_t" as a fallback.

The maintscript_set_exec_context() function is heavily based on the
libselinux rpm_execcon() function, which is licensed as Public Domain.
Guillem Jover il y a 13 ans
Parent
commit
99529be532
2 fichiers modifiés avec 74 ajouts et 0 suppressions
  1. 3 0
      debian/changelog
  2. 71 0
      src/script.c

+ 3 - 0
debian/changelog

@@ -56,6 +56,9 @@ dpkg (1.17.0) UNRELEASED; urgency=low
     architectures on «dpkg-query --list».
     architectures on «dpkg-query --list».
   * Rework SELinux code on unpack to reload the label database if it has
   * Rework SELinux code on unpack to reload the label database if it has
     changed, for example while upgrading the SELinux policy package.
     changed, for example while upgrading the SELinux policy package.
+  * Execute maintainer scripts in a new execution context, based on the
+    current one and the specific maintainer script filename, and if it's
+    not different to the current one, use "dpkg_script_t" as a fallback.
 
 
  -- Guillem Jover <guillem@debian.org>  Fri, 03 Aug 2012 13:21:00 +0200
  -- Guillem Jover <guillem@debian.org>  Fri, 03 Aug 2012 13:21:00 +0200
 
 

+ 71 - 0
src/script.c

@@ -31,6 +31,12 @@
 #include <unistd.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdlib.h>
 
 
+#ifdef WITH_SELINUX
+#include <selinux/selinux.h>
+#include <selinux/flask.h>
+#include <selinux/context.h>
+#endif
+
 #include <dpkg/i18n.h>
 #include <dpkg/i18n.h>
 #include <dpkg/dpkg.h>
 #include <dpkg/dpkg.h>
 #include <dpkg/dpkg-db.h>
 #include <dpkg/dpkg-db.h>
@@ -136,6 +142,66 @@ preexecscript(struct command *cmd)
 	return cmd->filename + instdirl;
 	return cmd->filename + instdirl;
 }
 }
 
 
+/**
+ * Set a new security execution context for the maintainer script.
+ *
+ * Try to create a new execution context based on the current one and the
+ * specific maintainer script filename. If it's the same as the current
+ * one, use the given fallback.
+ */
+static int
+maintscript_set_exec_context(struct command *cmd, const char *fallback)
+{
+	int rc = 0;
+#ifdef WITH_SELINUX
+	security_context_t curcon = NULL, newcon = NULL, filecon = NULL;
+	context_t tmpcon = NULL;
+
+	if (is_selinux_enabled() < 1)
+		return 0;
+
+	rc = getcon(&curcon);
+	if (rc < 0)
+		goto out;
+
+	rc = getfilecon(cmd->filename, &filecon);
+	if (rc < 0)
+		goto out;
+
+	rc = security_compute_create(curcon, filecon, SECCLASS_PROCESS, &newcon);
+	if (rc < 0)
+		goto out;
+
+	if (strcmp(curcon, newcon) == 0) {
+		/* No default transition, use fallback for now. */
+		rc = -1;
+		tmpcon = context_new(curcon);
+		if (tmpcon == NULL)
+			goto out;
+		if (context_type_set(tmpcon, fallback))
+			goto out;
+		freecon(newcon);
+		newcon = strdup(context_str(tmpcon));
+		if (newcon == NULL)
+			goto out;
+		rc = 0;
+	}
+
+	rc = setexeccon(newcon);
+
+out:
+	if (rc < 0 && security_getenforce() == 0)
+		rc = 0;
+
+	context_free(tmpcon);
+	freecon(newcon);
+	freecon(curcon);
+	freecon(filecon);
+#endif
+
+	return rc < 0 ? rc : 0;
+}
+
 static int
 static int
 do_script(struct pkginfo *pkg, struct pkgbin *pkgbin,
 do_script(struct pkginfo *pkg, struct pkgbin *pkgbin,
           struct command *cmd, struct stat *stab, int warn)
           struct command *cmd, struct stat *stab, int warn)
@@ -156,6 +222,11 @@ do_script(struct pkginfo *pkg, struct pkgbin *pkgbin,
 			ohshite(_("unable to setenv for maintainer script"));
 			ohshite(_("unable to setenv for maintainer script"));
 
 
 		cmd->filename = cmd->argv[0] = preexecscript(cmd);
 		cmd->filename = cmd->argv[0] = preexecscript(cmd);
+
+		if (maintscript_set_exec_context(cmd, "dpkg_script_t") < 0)
+			ohshite(_("cannot set security execution context for "
+			          "maintainer script"));
+
 		command_exec(cmd);
 		command_exec(cmd);
 	}
 	}
 	subproc_signals_setup(cmd->name); /* This does a push_cleanup(). */
 	subproc_signals_setup(cmd->name); /* This does a push_cleanup(). */