From 2f0a18b499b9b0e1afbdab8a8bb31d38f2acc6d8 Mon Sep 17 00:00:00 2001 From: Jakub Filak Date: Fri, 17 Apr 2015 16:06:33 +0200 Subject: [ABRT PATCH] ccpp: emulate selinux for creation of compat cores This issue was discovered by Florian Weimer of Red Hat Product Security. http://article.gmane.org/gmane.comp.security.selinux/21842 v2: use the _raw interface and do the preparation steps as root v3: don't fail if SELinux is disabled https://github.com/abrt/abrt/commit/c4f06d4198658c82550e93bb2617b96022c06cf4#commitcomment-11021276 Signed-off-by: Jakub Filak --- configure.ac | 1 + src/hooks/Makefile.am | 4 ++- src/hooks/abrt-hook-ccpp.c | 85 ++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 86 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 9ff616d..6c6d2e8 100644 --- a/configure.ac +++ b/configure.ac @@ -106,6 +106,7 @@ PKG_CHECK_MODULES([LIBREPORT_GTK], [libreport-gtk]) PKG_CHECK_MODULES([POLKIT], [polkit-gobject-1]) PKG_CHECK_MODULES([GIO], [gio-2.0]) PKG_CHECK_MODULES([SATYR], [satyr]) +PKG_CHECK_MODULES([LIBSELINUX], [libselinux]) PKG_PROG_PKG_CONFIG AC_ARG_WITH([systemdsystemunitdir], diff --git a/src/hooks/Makefile.am b/src/hooks/Makefile.am index e536089..9a527f4 100644 --- a/src/hooks/Makefile.am +++ b/src/hooks/Makefile.am @@ -33,10 +33,12 @@ abrt_hook_ccpp_CPPFLAGS = \ -DDEFAULT_DUMP_DIR_MODE=$(DEFAULT_DUMP_DIR_MODE) \ $(GLIB_CFLAGS) \ $(LIBREPORT_CFLAGS) \ + $(LIBSELINUX_CFLAGS) \ -D_GNU_SOURCE abrt_hook_ccpp_LDADD = \ ../lib/libabrt.la \ - $(LIBREPORT_LIBS) + $(LIBREPORT_LIBS) \ + $(LIBSELINUX_LIBS) # abrt-merge-pstoreoops abrt_merge_pstoreoops_SOURCES = \ diff --git a/src/hooks/abrt-hook-ccpp.c b/src/hooks/abrt-hook-ccpp.c index 81f9349..00ae621 100644 --- a/src/hooks/abrt-hook-ccpp.c +++ b/src/hooks/abrt-hook-ccpp.c @@ -20,6 +20,7 @@ */ #include #include "libabrt.h" +#include #define DUMP_SUID_UNSAFE 1 #define DUMP_SUID_SAFE 2 @@ -286,6 +287,54 @@ static int dump_suid_policy() return suid_dump_policy; } +/* Computes a security context of new file created by the given process with + * pid in the given directory represented by file descriptor. + * + * On errors returns negative number. Returns 0 if the function succeeds and + * computes the context and returns positive number and assigns NULL to newcon + * if the security context is not needed (SELinux disabled). + */ +static int compute_selinux_con_for_new_file(pid_t pid, int dir_fd, security_context_t *newcon) +{ + security_context_t srccon; + security_context_t dstcon; + + const int r = is_selinux_enabled(); + if (r == 0) + { + *newcon = NULL; + return 1; + } + else if (r == -1) + { + perror_msg("Couldn't get state of SELinux"); + return -1; + } + else if (r != 1) + error_msg_and_die("Unexpected SELinux return value: %d", r); + + + if (getpidcon_raw(pid, &srccon) < 0) + { + perror_msg("getpidcon_raw(%d)", pid); + return -1; + } + + if (fgetfilecon_raw(dir_fd, &dstcon) < 0) + { + perror_msg("getfilecon_raw(%s)", user_pwd); + return -1; + } + + if (security_compute_create_raw(srccon, dstcon, string_to_security_class("file"), newcon) < 0) + { + perror_msg("security_compute_create_raw(%s, %s, 'file')", srccon, dstcon); + return -1; + } + + return 0; +} + static int open_user_core(uid_t uid, uid_t fsuid, pid_t pid, char **percent_values) { proc_cwd = open_cwd(pid); @@ -294,6 +343,14 @@ static int open_user_core(uid_t uid, uid_t fsuid, pid_t pid, char **percent_valu errno = 0; + /* http://article.gmane.org/gmane.comp.security.selinux/21842 */ + security_context_t newcon; + if (compute_selinux_con_for_new_file(pid, dirfd(proc_cwd), &newcon) < 0) + { + log_notice("Not going to create a user core due to SELinux errors"); + return -1; + } + xsetegid(get_fsgid()); xseteuid(fsuid); @@ -388,10 +445,25 @@ static int open_user_core(uid_t uid, uid_t fsuid, pid_t pid, char **percent_valu * (However, see the description of the prctl(2) PR_SET_DUMPABLE operation, * and the description of the /proc/sys/fs/suid_dumpable file in proc(5).) */ + + /* Set SELinux context like kernel when creating core dump file */ + if (newcon != NULL && setfscreatecon_raw(newcon) < 0) + { + perror_msg("setfscreatecon_raw(%s)", newcon); + return -1; + } + struct stat sb; errno = 0; /* Do not O_TRUNC: if later checks fail, we do not want to have file already modified here */ 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 */ + + if (newcon != NULL && setfscreatecon_raw(NULL) < 0) + { + error_msg("setfscreatecon_raw(NULL)"); + goto user_core_fail; + } + xsetegid(0); xseteuid(0); if (user_core_fd < 0 @@ -404,16 +476,23 @@ static int open_user_core(uid_t uid, uid_t fsuid, pid_t pid, char **percent_valu perror_msg("Can't open '%s' at '%s'", core_basename, user_pwd); else perror_msg("'%s' at '%s' is not a regular file with link count 1 owned by UID(%d)", core_basename, user_pwd, fsuid); - return -1; + goto user_core_fail; } if (ftruncate(user_core_fd, 0) != 0) { /* perror first, otherwise unlink may trash errno */ perror_msg("Can't truncate '%s' at '%s' to size 0", core_basename, user_pwd); - unlinkat(dirfd(proc_cwd), core_basename, /*unlink file*/0); - return -1; + goto user_core_fail; } return user_core_fd; + +user_core_fail: + if (user_core_fd >= 0) + { + close(user_core_fd); + unlinkat(dirfd(proc_cwd), core_basename, /*unlink file*/0); + } + return -1; } static bool dump_fd_info(const char *dest_filename, char *source_filename, int source_base_ofs, uid_t uid, gid_t gid) -- 1.8.3.1