From 2b1fa2caf4ef3cb253e931f53b43fc9499661da4 Mon Sep 17 00:00:00 2001
From: Jakub Filak <jfilak@redhat.com>
Date: Thu, 16 Apr 2015 11:12:40 +0200
Subject: [PATCH] turn off exploring crashed process's root directories

A local user can arrange a process root directory in way that abrt will
make a copy of file not accessible by the attacker.

I don't want to remove the chroot code entirely because it might be
useful for non-production environments.

Related: #1211835

Signed-off-by: Jakub Filak <jfilak@redhat.com>
---
 src/daemon/abrt-action-save-package-data.c |  6 +++++-
 src/daemon/abrt.conf                       | 16 ++++++++++++++++
 src/hooks/abrt-hook-ccpp.c                 | 12 +++++++++++-
 src/include/libabrt.h                      |  2 ++
 src/lib/abrt_conf.c                        | 10 ++++++++++
 5 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/src/daemon/abrt-action-save-package-data.c b/src/daemon/abrt-action-save-package-data.c
index cc86327..816e0d0 100644
--- a/src/daemon/abrt-action-save-package-data.c
+++ b/src/daemon/abrt-action-save-package-data.c
@@ -239,7 +239,11 @@ static int SavePackageDescriptionToDebugDump(const char *dump_dir_name)
 
     cmdline = dd_load_text_ext(dd, FILENAME_CMDLINE, DD_FAIL_QUIETLY_ENOENT);
     executable = dd_load_text(dd, FILENAME_EXECUTABLE);
-    rootdir = dd_load_text_ext(dd, FILENAME_ROOTDIR,
+
+    /* Do not implicitly query rpm database in process's root dir, if
+     * ExploreChroots is disabled. */
+    if (g_settings_explorechroots)
+        rootdir = dd_load_text_ext(dd, FILENAME_ROOTDIR,
                                DD_FAIL_QUIETLY_ENOENT | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE);
 
     /* Close dd while we query package database. It can take some time,
diff --git a/src/daemon/abrt.conf b/src/daemon/abrt.conf
index 59d1831..02e969d 100644
--- a/src/daemon/abrt.conf
+++ b/src/daemon/abrt.conf
@@ -43,3 +43,19 @@ AutoreportingEnabled = no
 #                session; otherwise No.
 #
 # ShortenedReporting = yes
+
+# Enables various features exploring process's root directories if they differ
+# from the default root directory. The folowing list includes examples of
+# enabled features:
+#   * query the rpm database in the process's root directory
+#   * save files like /etc/os-release from the process's root directory
+#
+# This feature is disabled by default because it might be used by a local user
+# to steal your data.
+#
+# Caution:
+#
+# THIS FEATURE MIGHT BE USED BY A LOCAL USER TO STEEL YOUR DATA BY ARRANGING A
+# SPECIAL ROOT DIRECTORY IN USER MOUNT NAMESAPCE
+#
+# ExploreChroots = false
diff --git a/src/hooks/abrt-hook-ccpp.c b/src/hooks/abrt-hook-ccpp.c
index e1d81b6..7626a97 100644
--- a/src/hooks/abrt-hook-ccpp.c
+++ b/src/hooks/abrt-hook-ccpp.c
@@ -601,7 +601,17 @@ int main(int argc, char** argv)
     {
         char *rootdir = get_rootdir(pid);
 
-        dd_create_basic_files(dd, fsuid, (rootdir && strcmp(rootdir, "/") != 0) ? rootdir : NULL);
+        /* Reading data from an arbitrary root directory is not secure. */
+        if (g_settings_explorechroots)
+        {
+            /* Yes, test 'rootdir' but use 'source_filename' because 'rootdir' can
+             * be '/' for a process with own namespace. 'source_filename' is /proc/[pid]/root. */
+            dd_create_basic_files(dd, fsuid, (rootdir != NULL) ? rootdir : NULL);
+        }
+        else
+        {
+            dd_create_basic_files(dd, fsuid, NULL);
+        }
 
         char source_filename[sizeof("/proc/%lu/somewhat_long_name") + sizeof(long)*3];
         int source_base_ofs = sprintf(source_filename, "/proc/%lu/smaps", (long)pid);
diff --git a/src/include/libabrt.h b/src/include/libabrt.h
index 65d30a1..abfbc97 100644
--- a/src/include/libabrt.h
+++ b/src/include/libabrt.h
@@ -62,6 +62,8 @@ extern bool          g_settings_autoreporting;
 extern char *        g_settings_autoreporting_event;
 #define g_settings_shortenedreporting abrt_g_settings_shortenedreporting
 extern bool          g_settings_shortenedreporting;
+#define g_settings_explorechroots abrt_g_settings_explorechroots
+extern bool          g_settings_explorechroots;
 
 
 #define load_abrt_conf abrt_load_abrt_conf
diff --git a/src/lib/abrt_conf.c b/src/lib/abrt_conf.c
index f7fdc6d..46ff689 100644
--- a/src/lib/abrt_conf.c
+++ b/src/lib/abrt_conf.c
@@ -27,6 +27,7 @@ bool          g_settings_delete_uploaded = 0;
 bool          g_settings_autoreporting = 0;
 char *        g_settings_autoreporting_event = NULL;
 bool          g_settings_shortenedreporting = 0;
+bool          g_settings_explorechroots = 0;
 
 void free_abrt_conf_data()
 {
@@ -106,6 +107,15 @@ static void ParseCommon(map_string_t *settings, const char *conf_filename)
         g_settings_shortenedreporting = (desktop_env && strcasestr(desktop_env, "gnome") != NULL);
     }
 
+    value = get_map_string_item_or_NULL(settings, "ExploreChroots");
+    if (value)
+    {
+        g_settings_explorechroots = string_to_bool(value);
+        remove_map_string_item(settings, "ExploreChroots");
+    }
+    else
+        g_settings_explorechroots = false;
+
     GHashTableIter iter;
     const char *name;
     /*char *value; - already declared */
-- 
2.1.0

