Package: dpkg Version: 1.18.18 User: selinux-de...@lists.alioth.debian.org Usertags: selinux
Currently, dpkg runs its maintainer tasks in the SELinux type dpkg_script_t without changing the SELinux user or role. So when running root as sysadm_u:sysadm_r:sysadm_t, the tasks will be run in unconfined_u:unconfined_r:dpkg_script_t. The problem are the postinst scripts: They create files and run binaries. Almost all the files created in this way do not have the correct file context system_u:object_r:*, which can break a ubac enabled system. e.g.: Would relabel /usr/share/info/dir.old from staff_u:object_r:usr_t:s0 to system_u:object_r:usr_t:s0 Would relabel /usr/share/info/dir from staff_u:object_r:usr_t:s0 to system_u:object_r:usr_t:s0 Would relabel /var/cache/man/pt/index.db from unconfined_u:object_r:man_cache_t:s0 to system_u:object_r:man_cache_t:s0 Also, for example, the exim4 post install script does some work leading to run exim in system_mail_t, which is not allowed to run under the roles sysadm_r/unconfined_r. type=PROCTITLE msg=audit(01/24/17 15:51:28.963:2602) : proctitle=/usr/sbin/exim4 -C /var/lib/exim4/config.autogenerated.tmp -bV type=SYSCALL msg=audit(01/24/17 15:51:28.963:2602) : arch=armeb syscall=socket per=PER_LINUX_32BIT success=yes exit=4 a0=local a1=SOCK_STREAM a2=ip a3=0x0 items=0 ppid=22511 pid=22748 auid=christian uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=pts1 ses=359 comm=exim4 exe=/usr/sbin/exim4 subj=staff_u:sysadm_r:system_mail_t:s0 key=(null) type=SELINUX_ERR msg=audit(01/24/17 15:51:28.963:2602) : op=security_compute_sid invalid_context=staff_u:sysadm_r:system_mail_t:s0 scontext=staff_u:sysadm_r:system_mail_t:s0 tcontext=staff_u:sysadm_r:system_mail_t:s0 tclass=unix_stream_socket This can cause issues when upgrading packages in enforced mode even as unconfined user. The following dpkg patch runs the maintainer tasks in the context system_u:system_r:dpkg_script_t (may be altered inside the SELinux policy): Note: The patch does not touch the SELinux detection in the build logic and the SELinux policy has to be updated beforehand. From: root <root@debianSE> Date: Mon, 9 Jan 2017 22:42:03 +0100 Subject: [PATCH] dpkg: fix maintainer SELinux context --- src/script.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 85 insertions(+), 10 deletions(-) diff --git a/src/script.c b/src/script.c index 2f252ae..72b92cf 100644 --- a/src/script.c +++ b/src/script.c @@ -32,6 +32,7 @@ #include <stdlib.h> #ifdef WITH_LIBSELINUX +#include <ctype.h> // isspace #include <selinux/selinux.h> #endif @@ -141,23 +142,97 @@ maintscript_pre_exec(struct command *cmd) return cmd->filename + instdirlen; } +#ifdef WITH_LIBSELINUX +/* + * derived from get_init_context() + * https://github.com/SELinuxProject/selinux/blob/master/policycoreutils/run_init/run_init.c + * + * Get the CONTEXT associated with the context for the dpkg maint scripts. + * + * in: nothing + * out: The CONTEXT associated with the context. + * return: 0 on success, -1 on failure. + */ +static int +get_dpkg_context(char **context) +{ + FILE *fp; + char buf[255], *bufp; + size_t buf_len; + char context_file[4096]; + snprintf(context_file, sizeof(context_file) - 1, "%s/%s", selinux_contexts_path(), "dpkg_context"); + fp = fopen(context_file, "r"); + if (!fp) { + ohshite(_("Could not open file %s\n"), context_file); + return -1; + } + + while (1) { /* loop until we find a non-empty line */ + + if (!fgets(buf, sizeof buf, fp)) { + break; + } + + buf_len = strlen(buf); + if (buf[buf_len - 1] == '\n') { + buf[buf_len - 1] = 0; + } + + bufp = buf; + while (*bufp && isspace(*bufp)) { + bufp++; + } + + if (*bufp) { + *context = strdup(bufp); + if (!(*context)) { + goto out; + } + fclose(fp); + return 0; + } + } + out: + fclose(fp); + ohshit(_("No context in file %s\n"), context_file); + return -1; +} +#endif + /** * 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) +maintscript_set_exec_context(void) { +#ifdef WITH_LIBSELINUX int rc = 0; + char *dpkg_context = NULL; -#ifdef WITH_LIBSELINUX - rc = setexecfilecon(cmd->filename, fallback); -#endif + if (is_selinux_enabled() < 1) { + return 0; + } - return rc < 0 ? rc : 0; + if ((rc = get_dpkg_context(&dpkg_context)) < 0) { + ohshit(_("Can not get dpkg_context")); + goto out; + } + + if ((rc = setexeccon(dpkg_context)) < 0) { + ohshite(_("Can not set exec content to %s"), dpkg_context); + goto out;; + } + + out: + if (rc < 0 && security_getenforce() == 0) { + rc = 0; + } + + free(dpkg_context); + return rc; +#else + return 0; +#endif } static int @@ -190,7 +265,7 @@ maintscript_exec(struct pkginfo *pkg, struct pkgbin *pkgbin, cmd->filename = cmd->argv[0] = maintscript_pre_exec(cmd); - if (maintscript_set_exec_context(cmd, "dpkg_script_t") < 0) + if (maintscript_set_exec_context() < 0) ohshite(_("cannot set security execution context for " "maintainer script")); -- 2.11.0