Matej Habrnal fa1950
From f15b6e0f53ceb5ba450e93e406272ffe8a398cbd Mon Sep 17 00:00:00 2001
Matej Habrnal fa1950
From: Jakub Filak <jfilak@redhat.com>
Matej Habrnal fa1950
Date: Mon, 1 Jun 2015 12:03:55 +0200
Matej Habrnal fa1950
Subject: [PATCH] hooks: use root for owner of all dump directories
Matej Habrnal fa1950
Matej Habrnal fa1950
This patch has two goals:
Matej Habrnal fa1950
* avoid hard and symbolic link attacks (race conditions)
Matej Habrnal fa1950
* keep security sensitive data private (in the near future, a problem
Matej Habrnal fa1950
  directories will contain elements accessible by privileged
Matej Habrnal fa1950
  users while the directory itself will be accessible by
Matej Habrnal fa1950
  non-privileged users (dmesg, journald, /var/log/messages)
Matej Habrnal fa1950
Matej Habrnal fa1950
Related: #1212868 (CVE-2015-1870), #1212861 (CVE-2015-1869)
Matej Habrnal fa1950
Matej Habrnal fa1950
Signed-off-by: Jakub Filak <jfilak@redhat.com>
Matej Habrnal fa1950
---
Matej Habrnal fa1950
 src/daemon/abrt-server.c     |  2 +-
Matej Habrnal fa1950
 src/dbus/abrt-dbus.c         | 11 ++++-------
Matej Habrnal fa1950
 src/hooks/abrt-hook-ccpp.c   | 18 +++++++++---------
Matej Habrnal fa1950
 src/lib/hooklib.c            |  2 +-
Matej Habrnal fa1950
 src/plugins/abrt-dump-xorg.c | 15 ++++-----------
Matej Habrnal fa1950
 src/plugins/oops-utils.c     | 15 ++++-----------
Matej Habrnal fa1950
 6 files changed, 23 insertions(+), 40 deletions(-)
Matej Habrnal fa1950
Matej Habrnal fa1950
diff --git a/src/daemon/abrt-server.c b/src/daemon/abrt-server.c
Matej Habrnal fa1950
index 90339ab..d7556e2 100644
Matej Habrnal fa1950
--- a/src/daemon/abrt-server.c
Matej Habrnal fa1950
+++ b/src/daemon/abrt-server.c
Matej Habrnal fa1950
@@ -391,7 +391,7 @@ static int create_problem_dir(GHashTable *problem_info, unsigned pid)
Matej Habrnal fa1950
     /* No need to check the path length, as all variables used are limited,
Matej Habrnal fa1950
      * and dd_create() fails if the path is too long.
Matej Habrnal fa1950
      */
Matej Habrnal fa1950
-    struct dump_dir *dd = dd_create(path, client_uid, DEFAULT_DUMP_DIR_MODE);
Matej Habrnal fa1950
+    struct dump_dir *dd = dd_create(path, /*fs owner*/0, DEFAULT_DUMP_DIR_MODE);
Matej Habrnal fa1950
     if (!dd)
Matej Habrnal fa1950
     {
Matej Habrnal fa1950
         error_msg_and_die("Error creating problem directory '%s'", path);
Matej Habrnal fa1950
diff --git a/src/dbus/abrt-dbus.c b/src/dbus/abrt-dbus.c
Matej Habrnal fa1950
index 62f331b..44778a2 100644
Matej Habrnal fa1950
--- a/src/dbus/abrt-dbus.c
Matej Habrnal fa1950
+++ b/src/dbus/abrt-dbus.c
Matej Habrnal fa1950
@@ -506,13 +506,10 @@ static void handle_method_call(GDBusConnection *connection,
Matej Habrnal fa1950
             return;
Matej Habrnal fa1950
         }
Matej Habrnal fa1950
 
Matej Habrnal fa1950
-        if (ddstat & DD_STAT_OWNED_BY_UID)
Matej Habrnal fa1950
-        {   //caller seems to be in group with access to this dir, so no action needed
Matej Habrnal fa1950
-            log_notice("caller has access to the requested directory %s", problem_dir);
Matej Habrnal fa1950
-            g_dbus_method_invocation_return_value(invocation, NULL);
Matej Habrnal fa1950
-            dd_close(dd);
Matej Habrnal fa1950
-            return;
Matej Habrnal fa1950
-        }
Matej Habrnal fa1950
+        /* It might happen that we will do chowing even if the UID is alreay fs
Matej Habrnal fa1950
+         * owner, but DD_STAT_OWNED_BY_UID no longer denotes fs owner and this
Matej Habrnal fa1950
+         * method has to ensure file system ownership for the uid.
Matej Habrnal fa1950
+         */
Matej Habrnal fa1950
 
Matej Habrnal fa1950
         if ((ddstat & DD_STAT_ACCESSIBLE_BY_UID) == 0 &&
Matej Habrnal fa1950
                 polkit_check_authorization_dname(caller, "org.freedesktop.problems.getall") != PolkitYes)
Matej Habrnal fa1950
diff --git a/src/hooks/abrt-hook-ccpp.c b/src/hooks/abrt-hook-ccpp.c
Matej Habrnal fa1950
index 59fcfce..06dd670 100644
Matej Habrnal fa1950
--- a/src/hooks/abrt-hook-ccpp.c
Matej Habrnal fa1950
+++ b/src/hooks/abrt-hook-ccpp.c
Matej Habrnal fa1950
@@ -707,14 +707,17 @@ int main(int argc, char** argv)
Matej Habrnal fa1950
         return create_user_core(user_core_fd, pid, ulimit_c);
Matej Habrnal fa1950
     }
Matej Habrnal fa1950
 
Matej Habrnal fa1950
-    /* use fsuid instead of uid, so we don't expose any sensitive
Matej Habrnal fa1950
-     * information of suided app in /var/tmp/abrt
Matej Habrnal fa1950
+    /* If you don't want to have fs owner as root then:
Matej Habrnal fa1950
      *
Matej Habrnal fa1950
-     * dd_create_skeleton() creates a new directory and leaves ownership to
Matej Habrnal fa1950
-     * the current user, hence, we have to call dd_reset_ownership() after the
Matej Habrnal fa1950
-     * directory is populated.
Matej Habrnal fa1950
+     * - use fsuid instead of uid for fs owner, so we don't expose any
Matej Habrnal fa1950
+     *   sensitive information of suided app in /var/(tmp|spool)/abrt
Matej Habrnal fa1950
+     *
Matej Habrnal fa1950
+     * - use dd_create_skeleton() and dd_reset_ownership(), when you finish
Matej Habrnal fa1950
+     *   creating the new dump directory, to prevent the real owner to write to
Matej Habrnal fa1950
+     *   the directory until the hook is done (avoid race conditions and defend
Matej Habrnal fa1950
+     *   hard and symbolic link attacs)
Matej Habrnal fa1950
      */
Matej Habrnal fa1950
-    dd = dd_create_skeleton(path, fsuid, DEFAULT_DUMP_DIR_MODE, /*no flags*/0);
Matej Habrnal fa1950
+    dd = dd_create(path, /*fs owner*/0, DEFAULT_DUMP_DIR_MODE);
Matej Habrnal fa1950
     if (dd)
Matej Habrnal fa1950
     {
Matej Habrnal fa1950
         char *rootdir = get_rootdir(pid);
Matej Habrnal fa1950
@@ -886,9 +889,6 @@ int main(int argc, char** argv)
Matej Habrnal fa1950
         if (tid > 0 && setting_CreateCoreBacktrace)
Matej Habrnal fa1950
             create_core_backtrace(tid, executable, signal_no, dd);
Matej Habrnal fa1950
 
Matej Habrnal fa1950
-        /* And finally set the right uid and gid */
Matej Habrnal fa1950
-        dd_reset_ownership(dd);
Matej Habrnal fa1950
-
Matej Habrnal fa1950
         /* We close dumpdir before we start catering for crash storm case.
Matej Habrnal fa1950
          * Otherwise, delete_dump_dir's from other concurrent
Matej Habrnal fa1950
          * CCpp's won't be able to delete our dump (their delete_dump_dir
Matej Habrnal fa1950
diff --git a/src/lib/hooklib.c b/src/lib/hooklib.c
Matej Habrnal fa1950
index 0a8d703..39a6ef4 100644
Matej Habrnal fa1950
--- a/src/lib/hooklib.c
Matej Habrnal fa1950
+++ b/src/lib/hooklib.c
Matej Habrnal fa1950
@@ -410,7 +410,7 @@ char* problem_data_save(problem_data_t *pd)
Matej Habrnal fa1950
 {
Matej Habrnal fa1950
     load_abrt_conf();
Matej Habrnal fa1950
 
Matej Habrnal fa1950
-    struct dump_dir *dd = create_dump_dir_from_problem_data(pd, g_settings_dump_location);
Matej Habrnal fa1950
+    struct dump_dir *dd = create_dump_dir_from_problem_data_ext(pd, g_settings_dump_location, /*fs owner*/0);
Matej Habrnal fa1950
 
Matej Habrnal fa1950
     char *problem_id = NULL;
Matej Habrnal fa1950
     if (dd)
Matej Habrnal fa1950
diff --git a/src/plugins/abrt-dump-xorg.c b/src/plugins/abrt-dump-xorg.c
Matej Habrnal fa1950
index 3500629..477ec9c 100644
Matej Habrnal fa1950
--- a/src/plugins/abrt-dump-xorg.c
Matej Habrnal fa1950
+++ b/src/plugins/abrt-dump-xorg.c
Matej Habrnal fa1950
@@ -73,15 +73,6 @@ static void save_bt_to_dump_dir(const char *bt, const char *exe, const char *rea
Matej Habrnal fa1950
 {
Matej Habrnal fa1950
     time_t t = time(NULL);
Matej Habrnal fa1950
     const char *iso_date = iso_date_string(&t);
Matej Habrnal fa1950
-    /* dump should be readable by all if we're run with -x */
Matej Habrnal fa1950
-    uid_t my_euid = (uid_t)-1L;
Matej Habrnal fa1950
-    mode_t mode = DEFAULT_DUMP_DIR_MODE | S_IROTH;
Matej Habrnal fa1950
-    /* and readable only for the owner otherwise */
Matej Habrnal fa1950
-    if (!(g_opts & OPT_x))
Matej Habrnal fa1950
-    {
Matej Habrnal fa1950
-        mode = DEFAULT_DUMP_DIR_MODE;
Matej Habrnal fa1950
-        my_euid = geteuid();
Matej Habrnal fa1950
-    }
Matej Habrnal fa1950
 
Matej Habrnal fa1950
     pid_t my_pid = getpid();
Matej Habrnal fa1950
 
Matej Habrnal fa1950
@@ -89,10 +80,10 @@ static void save_bt_to_dump_dir(const char *bt, const char *exe, const char *rea
Matej Habrnal fa1950
     sprintf(base, "xorg-%s-%lu-%u", iso_date, (long)my_pid, g_bt_count);
Matej Habrnal fa1950
     char *path = concat_path_file(debug_dumps_dir, base);
Matej Habrnal fa1950
 
Matej Habrnal fa1950
-    struct dump_dir *dd = dd_create(path, /*uid:*/ my_euid, mode);
Matej Habrnal fa1950
+    struct dump_dir *dd = dd_create(path, /*fs owner*/0, DEFAULT_DUMP_DIR_MODE);
Matej Habrnal fa1950
     if (dd)
Matej Habrnal fa1950
     {
Matej Habrnal fa1950
-        dd_create_basic_files(dd, /*uid:*/ my_euid, NULL);
Matej Habrnal fa1950
+        dd_create_basic_files(dd, /*no uid*/(uid_t)-1L, NULL);
Matej Habrnal fa1950
         dd_save_text(dd, FILENAME_ABRT_VERSION, VERSION);
Matej Habrnal fa1950
         dd_save_text(dd, FILENAME_ANALYZER, "xorg");
Matej Habrnal fa1950
         dd_save_text(dd, FILENAME_TYPE, "xorg");
Matej Habrnal fa1950
@@ -111,6 +102,8 @@ static void save_bt_to_dump_dir(const char *bt, const char *exe, const char *rea
Matej Habrnal fa1950
                 exe = "/usr/bin/Xorg";
Matej Habrnal fa1950
         }
Matej Habrnal fa1950
         dd_save_text(dd, FILENAME_EXECUTABLE, exe);
Matej Habrnal fa1950
+        if (!(g_opts & OPT_x))
Matej Habrnal fa1950
+            dd_set_no_owner(dd);
Matej Habrnal fa1950
         dd_close(dd);
Matej Habrnal fa1950
         notify_new_path(path);
Matej Habrnal fa1950
     }
Matej Habrnal fa1950
diff --git a/src/plugins/oops-utils.c b/src/plugins/oops-utils.c
Matej Habrnal fa1950
index ea6c639..bb6a79c 100644
Matej Habrnal fa1950
--- a/src/plugins/oops-utils.c
Matej Habrnal fa1950
+++ b/src/plugins/oops-utils.c
Matej Habrnal fa1950
@@ -92,15 +92,6 @@ unsigned abrt_oops_create_dump_dirs(GList *oops_list, const char *dump_location,
Matej Habrnal fa1950
 
Matej Habrnal fa1950
     time_t t = time(NULL);
Matej Habrnal fa1950
     const char *iso_date = iso_date_string(&t);
Matej Habrnal fa1950
-    /* dump should be readable by all if we're run with -x */
Matej Habrnal fa1950
-    uid_t my_euid = (uid_t)-1L;
Matej Habrnal fa1950
-    mode_t mode = DEFAULT_DUMP_DIR_MODE | S_IROTH;
Matej Habrnal fa1950
-    /* and readable only for the owner otherwise */
Matej Habrnal fa1950
-    if (!(flags & ABRT_OOPS_WORLD_READABLE))
Matej Habrnal fa1950
-    {
Matej Habrnal fa1950
-        mode = DEFAULT_DUMP_DIR_MODE;
Matej Habrnal fa1950
-        my_euid = geteuid();
Matej Habrnal fa1950
-    }
Matej Habrnal fa1950
 
Matej Habrnal fa1950
     pid_t my_pid = getpid();
Matej Habrnal fa1950
     unsigned idx = 0;
Matej Habrnal fa1950
@@ -111,10 +102,10 @@ unsigned abrt_oops_create_dump_dirs(GList *oops_list, const char *dump_location,
Matej Habrnal fa1950
         sprintf(base, "oops-%s-%lu-%lu", iso_date, (long)my_pid, (long)idx);
Matej Habrnal fa1950
         char *path = concat_path_file(dump_location, base);
Matej Habrnal fa1950
 
Matej Habrnal fa1950
-        struct dump_dir *dd = dd_create(path, /*uid:*/ my_euid, mode);
Matej Habrnal fa1950
+        struct dump_dir *dd = dd_create(path, /*fs owner*/0, DEFAULT_DUMP_DIR_MODE);
Matej Habrnal fa1950
         if (dd)
Matej Habrnal fa1950
         {
Matej Habrnal fa1950
-            dd_create_basic_files(dd, /*uid:*/ my_euid, NULL);
Matej Habrnal fa1950
+            dd_create_basic_files(dd, /*no uid*/(uid_t)-1L, NULL);
Matej Habrnal fa1950
             abrt_oops_save_data_in_dump_dir(dd, (char*)g_list_nth_data(oops_list, idx++), proc_modules);
Matej Habrnal fa1950
             dd_save_text(dd, FILENAME_ABRT_VERSION, VERSION);
Matej Habrnal fa1950
             dd_save_text(dd, FILENAME_ANALYZER, "Kerneloops");
Matej Habrnal fa1950
@@ -127,6 +118,8 @@ unsigned abrt_oops_create_dump_dirs(GList *oops_list, const char *dump_location,
Matej Habrnal fa1950
                 dd_save_text(dd, "fips_enabled", fips_enabled);
Matej Habrnal fa1950
             if (suspend_stats)
Matej Habrnal fa1950
                 dd_save_text(dd, "suspend_stats", suspend_stats);
Matej Habrnal fa1950
+            if ((flags & ABRT_OOPS_WORLD_READABLE))
Matej Habrnal fa1950
+                dd_set_no_owner(dd);
Matej Habrnal fa1950
             dd_close(dd);
Matej Habrnal fa1950
             notify_new_path(path);
Matej Habrnal fa1950
         }
Matej Habrnal fa1950
-- 
Matej Habrnal fa1950
2.1.0
Matej Habrnal fa1950