Matej Habrnal fa1950
From cfc1a5da0a0f2273e0ce39da0c2fa81053ed0eaa Mon Sep 17 00:00:00 2001
Matej Habrnal fa1950
From: Jakub Filak <jfilak@redhat.com>
Matej Habrnal fa1950
Date: Fri, 17 Apr 2015 16:06:33 +0200
Matej Habrnal fa1950
Subject: [PATCH] ccpp: emulate selinux for creation of compat cores
Matej Habrnal fa1950
Matej Habrnal fa1950
This issue was discovered by Florian Weimer of Red Hat Product Security.
Matej Habrnal fa1950
Matej Habrnal fa1950
http://article.gmane.org/gmane.comp.security.selinux/21842
Matej Habrnal fa1950
Matej Habrnal fa1950
Signed-off-by: Jakub Filak <jfilak@redhat.com>
Matej Habrnal fa1950
---
Matej Habrnal fa1950
 configure.ac               |  1 +
Matej Habrnal fa1950
 src/hooks/Makefile.am      |  4 ++-
Matej Habrnal fa1950
 src/hooks/abrt-hook-ccpp.c | 85 ++++++++++++++++++++++++++++++++++++++++++++--
Matej Habrnal fa1950
 3 files changed, 86 insertions(+), 4 deletions(-)
Matej Habrnal fa1950
Matej Habrnal fa1950
diff --git a/configure.ac b/configure.ac
Matej Habrnal fa1950
index d7e0ea5..430f23c 100644
Matej Habrnal fa1950
--- a/configure.ac
Matej Habrnal fa1950
+++ b/configure.ac
Matej Habrnal fa1950
@@ -141,6 +141,7 @@ PKG_CHECK_MODULES([POLKIT], [polkit-gobject-1])
Matej Habrnal fa1950
 PKG_CHECK_MODULES([GIO], [gio-2.0])
Matej Habrnal fa1950
 PKG_CHECK_MODULES([SATYR], [satyr])
Matej Habrnal fa1950
 PKG_CHECK_MODULES([SYSTEMD_JOURNAL], [libsystemd-journal])
Matej Habrnal fa1950
+PKG_CHECK_MODULES([LIBSELINUX], [libselinux])
Matej Habrnal fa1950
 
Matej Habrnal fa1950
 PKG_PROG_PKG_CONFIG
Matej Habrnal fa1950
 AC_ARG_WITH([systemdsystemunitdir],
Matej Habrnal fa1950
diff --git a/src/hooks/Makefile.am b/src/hooks/Makefile.am
Matej Habrnal fa1950
index 13702b5..ff070cf 100644
Matej Habrnal fa1950
--- a/src/hooks/Makefile.am
Matej Habrnal fa1950
+++ b/src/hooks/Makefile.am
Matej Habrnal fa1950
@@ -33,10 +33,12 @@ abrt_hook_ccpp_CPPFLAGS = \
Matej Habrnal fa1950
     -DDEFAULT_DUMP_DIR_MODE=$(DEFAULT_DUMP_DIR_MODE) \
Matej Habrnal fa1950
     $(GLIB_CFLAGS) \
Matej Habrnal fa1950
     $(LIBREPORT_CFLAGS) \
Matej Habrnal fa1950
+    $(LIBSELINUX_CFLAGS) \
Matej Habrnal fa1950
     -D_GNU_SOURCE
Matej Habrnal fa1950
 abrt_hook_ccpp_LDADD = \
Matej Habrnal fa1950
     ../lib/libabrt.la \
Matej Habrnal fa1950
-    $(LIBREPORT_LIBS)
Matej Habrnal fa1950
+    $(LIBREPORT_LIBS) \
Matej Habrnal fa1950
+    $(LIBSELINUX_LIBS)
Matej Habrnal fa1950
 
Matej Habrnal fa1950
 # abrt-merge-pstoreoops
Matej Habrnal fa1950
 abrt_merge_pstoreoops_SOURCES = \
Matej Habrnal fa1950
diff --git a/src/hooks/abrt-hook-ccpp.c b/src/hooks/abrt-hook-ccpp.c
Matej Habrnal fa1950
index 53700e4..9696423 100644
Matej Habrnal fa1950
--- a/src/hooks/abrt-hook-ccpp.c
Matej Habrnal fa1950
+++ b/src/hooks/abrt-hook-ccpp.c
Matej Habrnal fa1950
@@ -20,6 +20,7 @@
Matej Habrnal fa1950
 */
Matej Habrnal fa1950
 #include <sys/utsname.h>
Matej Habrnal fa1950
 #include "libabrt.h"
Matej Habrnal fa1950
+#include <selinux/selinux.h>
Matej Habrnal fa1950
 
Matej Habrnal fa1950
 #ifdef ENABLE_DUMP_TIME_UNWIND
Matej Habrnal fa1950
 #include <satyr/abrt.h>
Matej Habrnal fa1950
@@ -163,12 +164,68 @@ static DIR *open_cwd(pid_t pid)
Matej Habrnal fa1950
     return cwd;
Matej Habrnal fa1950
 }
Matej Habrnal fa1950
 
Matej Habrnal fa1950
+/* Computes a security context of new file created by the given process with
Matej Habrnal fa1950
+ * pid in the given directory represented by file descriptor.
Matej Habrnal fa1950
+ *
Matej Habrnal fa1950
+ * On errors returns negative number. Returns 0 if the function succeeds and
Matej Habrnal fa1950
+ * computes the context and returns positive number and assigns NULL to newcon
Matej Habrnal fa1950
+ * if the security context is not needed (SELinux disabled).
Matej Habrnal fa1950
+ */
Matej Habrnal fa1950
+static int compute_selinux_con_for_new_file(pid_t pid, int dir_fd, security_context_t *newcon)
Matej Habrnal fa1950
+{
Matej Habrnal fa1950
+    security_context_t srccon;
Matej Habrnal fa1950
+    security_context_t dstcon;
Matej Habrnal fa1950
+
Matej Habrnal fa1950
+    const int r = is_selinux_enabled();
Matej Habrnal fa1950
+    if (r == 0)
Matej Habrnal fa1950
+    {
Matej Habrnal fa1950
+        *newcon = NULL;
Matej Habrnal fa1950
+        return 1;
Matej Habrnal fa1950
+    }
Matej Habrnal fa1950
+    else if (r == -1)
Matej Habrnal fa1950
+    {
Matej Habrnal fa1950
+        perror_msg("Couldn't get state of SELinux");
Matej Habrnal fa1950
+        return -1;
Matej Habrnal fa1950
+    }
Matej Habrnal fa1950
+    else if (r != 1)
Matej Habrnal fa1950
+        error_msg_and_die("Unexpected SELinux return value: %d", r);
Matej Habrnal fa1950
+
Matej Habrnal fa1950
+
Matej Habrnal fa1950
+    if (getpidcon_raw(pid, &srccon) < 0)
Matej Habrnal fa1950
+    {
Matej Habrnal fa1950
+        perror_msg("getpidcon_raw(%d)", pid);
Matej Habrnal fa1950
+        return -1;
Matej Habrnal fa1950
+    }
Matej Habrnal fa1950
+
Matej Habrnal fa1950
+    if (fgetfilecon_raw(dir_fd, &dstcon) < 0)
Matej Habrnal fa1950
+    {
Matej Habrnal fa1950
+        perror_msg("getfilecon_raw(%s)", user_pwd);
Matej Habrnal fa1950
+        return -1;
Matej Habrnal fa1950
+    }
Matej Habrnal fa1950
+
Matej Habrnal fa1950
+    if (security_compute_create_raw(srccon, dstcon, string_to_security_class("file"), newcon) < 0)
Matej Habrnal fa1950
+    {
Matej Habrnal fa1950
+        perror_msg("security_compute_create_raw(%s, %s, 'file')", srccon, dstcon);
Matej Habrnal fa1950
+        return -1;
Matej Habrnal fa1950
+    }
Matej Habrnal fa1950
+
Matej Habrnal fa1950
+    return 0;
Matej Habrnal fa1950
+}
Matej Habrnal fa1950
+
Matej Habrnal fa1950
 static int open_user_core(uid_t uid, uid_t fsuid, gid_t fsgid, pid_t pid, char **percent_values)
Matej Habrnal fa1950
 {
Matej Habrnal fa1950
     proc_cwd = open_cwd(pid);
Matej Habrnal fa1950
     if (proc_cwd == NULL)
Matej Habrnal fa1950
         return -1;
Matej Habrnal fa1950
 
Matej Habrnal fa1950
+    /* http://article.gmane.org/gmane.comp.security.selinux/21842 */
Matej Habrnal fa1950
+    security_context_t newcon;
Matej Habrnal fa1950
+    if (compute_selinux_con_for_new_file(pid, dirfd(proc_cwd), &newcon) < 0)
Matej Habrnal fa1950
+    {
Matej Habrnal fa1950
+        log_notice("Not going to create a user core due to SELinux errors");
Matej Habrnal fa1950
+        return -1;
Matej Habrnal fa1950
+    }
Matej Habrnal fa1950
+
Matej Habrnal fa1950
     xsetegid(fsgid);
Matej Habrnal fa1950
     xseteuid(fsuid);
Matej Habrnal fa1950
 
Matej Habrnal fa1950
@@ -263,10 +320,25 @@ static int open_user_core(uid_t uid, uid_t fsuid, gid_t fsgid, pid_t pid, char *
Matej Habrnal fa1950
      * (However, see the description of the prctl(2) PR_SET_DUMPABLE operation,
Matej Habrnal fa1950
      * and the description of the /proc/sys/fs/suid_dumpable file in proc(5).)
Matej Habrnal fa1950
      */
Matej Habrnal fa1950
+
Matej Habrnal fa1950
+    /* Set SELinux context like kernel when creating core dump file */
Matej Habrnal fa1950
+    if (newcon != NULL && setfscreatecon_raw(newcon) < 0)
Matej Habrnal fa1950
+    {
Matej Habrnal fa1950
+        perror_msg("setfscreatecon_raw(%s)", newcon);
Matej Habrnal fa1950
+        return -1;
Matej Habrnal fa1950
+    }
Matej Habrnal fa1950
+
Matej Habrnal fa1950
     struct stat sb;
Matej Habrnal fa1950
     errno = 0;
Matej Habrnal fa1950
     /* Do not O_TRUNC: if later checks fail, we do not want to have file already modified here */
Matej Habrnal fa1950
     int user_core_fd = openat(dirfd(proc_cwd), core_basename, O_WRONLY | O_CREAT | O_NOFOLLOW | g_user_core_flags, 0600); /* kernel makes 0600 too */
Matej Habrnal fa1950
+
Matej Habrnal fa1950
+    if (newcon != NULL && setfscreatecon_raw(NULL) < 0)
Matej Habrnal fa1950
+    {
Matej Habrnal fa1950
+        error_msg("setfscreatecon_raw(NULL)");
Matej Habrnal fa1950
+        goto user_core_fail;
Matej Habrnal fa1950
+    }
Matej Habrnal fa1950
+
Matej Habrnal fa1950
     xsetegid(0);
Matej Habrnal fa1950
     xseteuid(0);
Matej Habrnal fa1950
     if (user_core_fd < 0
Matej Habrnal fa1950
@@ -279,16 +351,23 @@ static int open_user_core(uid_t uid, uid_t fsuid, gid_t fsgid, pid_t pid, char *
Matej Habrnal fa1950
             perror_msg("Can't open '%s' at '%s'", core_basename, user_pwd);
Matej Habrnal fa1950
         else
Matej Habrnal fa1950
             perror_msg("'%s' at '%s' is not a regular file with link count 1 owned by UID(%d)", core_basename, user_pwd, fsuid);
Matej Habrnal fa1950
-        return -1;
Matej Habrnal fa1950
+        goto user_core_fail;
Matej Habrnal fa1950
     }
Matej Habrnal fa1950
     if (ftruncate(user_core_fd, 0) != 0) {
Matej Habrnal fa1950
         /* perror first, otherwise unlink may trash errno */
Matej Habrnal fa1950
         perror_msg("Can't truncate '%s' at '%s' to size 0", core_basename, user_pwd);
Matej Habrnal fa1950
-        unlinkat(dirfd(proc_cwd), core_basename, /*unlink file*/0);
Matej Habrnal fa1950
-        return -1;
Matej Habrnal fa1950
+        goto user_core_fail;
Matej Habrnal fa1950
     }
Matej Habrnal fa1950
 
Matej Habrnal fa1950
     return user_core_fd;
Matej Habrnal fa1950
+
Matej Habrnal fa1950
+user_core_fail:
Matej Habrnal fa1950
+    if (user_core_fd >= 0)
Matej Habrnal fa1950
+    {
Matej Habrnal fa1950
+        close(user_core_fd);
Matej Habrnal fa1950
+        unlinkat(dirfd(proc_cwd), core_basename, /*unlink file*/0);
Matej Habrnal fa1950
+    }
Matej Habrnal fa1950
+    return -1;
Matej Habrnal fa1950
 }
Matej Habrnal fa1950
 
Matej Habrnal fa1950
 /* Like xopen, but on error, unlocks and deletes dd and user core */
Matej Habrnal fa1950
-- 
Matej Habrnal fa1950
2.1.0
Matej Habrnal fa1950