Blame SOURCES/0110-a-a-i-d-t-a-cache-sanitize-arguments.patch

06486d
From 9943a77bca37a0829ccd3784d1dfab37f8c24e7b Mon Sep 17 00:00:00 2001
06486d
From: Jakub Filak <jfilak@redhat.com>
06486d
Date: Wed, 29 Apr 2015 13:57:39 +0200
06486d
Subject: [ABRT PATCH] a-a-i-d-t-a-cache: sanitize arguments
06486d
06486d
Parse command lines arguments and use them to create new arguments for
06486d
exec(). No black listing algorithm would be safe enough. The only
06486d
allowed arguments are the following:
06486d
* v - verbose
06486d
* y - noninteractive
06486d
* repo - enable only repositories whose names match the pattern
06486d
* exact - download packages for the specified files
06486d
* ids - passed as magic proc fd path to the wrapped executable
06486d
06486d
The wrapper opens the list of needed build ids passes /proc/self/fd/[fd]
06486d
to the wrapped process. This allows us to open the file with caller's
06486d
UID/GID in order to avoid information disclosures.
06486d
06486d
Forbidden arguments:
06486d
* cache - allows regular users to create a user writable dump directory
06486d
* tmpdir - the same as above
06486d
* size_mb - no need to allow users to fiddle with the cache size
06486d
06486d
Related: #1216962
06486d
06486d
Signed-off-by: Jakub Filak <jfilak@redhat.com>
06486d
---
06486d
 po/POTFILES.in                                     |   1 +
06486d
 .../abrt-action-install-debuginfo-to-abrt-cache.c  | 106 ++++++++++++++++-----
06486d
 2 files changed, 85 insertions(+), 22 deletions(-)
06486d
06486d
diff --git a/po/POTFILES.in b/po/POTFILES.in
06486d
index cbe89fa..1248c46 100644
06486d
--- a/po/POTFILES.in
06486d
+++ b/po/POTFILES.in
06486d
@@ -31,6 +31,7 @@ src/plugins/abrt-action-check-oops-for-hw-error.in
06486d
 src/plugins/abrt-action-generate-backtrace.c
06486d
 src/plugins/abrt-action-generate-core-backtrace.c
06486d
 src/plugins/abrt-action-install-debuginfo.in
06486d
+src/plugins/abrt-action-install-debuginfo-to-abrt-cache.c
06486d
 src/plugins/abrt-action-perform-ccpp-analysis.in
06486d
 src/plugins/abrt-action-trim-files.c
06486d
 src/plugins/abrt-action-ureport
06486d
diff --git a/src/plugins/abrt-action-install-debuginfo-to-abrt-cache.c b/src/plugins/abrt-action-install-debuginfo-to-abrt-cache.c
06486d
index e0eccc0..eb2f7c5 100644
06486d
--- a/src/plugins/abrt-action-install-debuginfo-to-abrt-cache.c
06486d
+++ b/src/plugins/abrt-action-install-debuginfo-to-abrt-cache.c
06486d
@@ -29,28 +29,90 @@
06486d
  */
06486d
 int main(int argc, char **argv)
06486d
 {
06486d
-    /*
06486d
-     * We disallow passing of arguments which point to writable dirs
06486d
-     * and other files possibly not accessible to calling user.
06486d
-     * This way, the script will always use default values for these arguments.
06486d
-     */
06486d
-    char **pp = argv;
06486d
-    char *arg;
06486d
-    while ((arg = *++pp) != NULL)
06486d
+    /* I18n */
06486d
+    setlocale(LC_ALL, "");
06486d
+#if ENABLE_NLS
06486d
+    bindtextdomain(PACKAGE, LOCALEDIR);
06486d
+    textdomain(PACKAGE);
06486d
+#endif
06486d
+
06486d
+    abrt_init(argv);
06486d
+
06486d
+    /* Can't keep these strings/structs static: _() doesn't support that */
06486d
+    const char *program_usage_string = _(
06486d
+        "& [-y] [-i BUILD_IDS_FILE|-i -] [-e PATH[:PATH]...]\n"
06486d
+        "\t[-r REPO]\n"
06486d
+        "\n"
06486d
+        "Installs debuginfo packages for all build-ids listed in BUILD_IDS_FILE to\n"
06486d
+        "ABRT system cache."
06486d
+    );
06486d
+
06486d
+    enum {
06486d
+        OPT_v = 1 << 0,
06486d
+        OPT_y = 1 << 1,
06486d
+        OPT_i = 1 << 2,
06486d
+        OPT_e = 1 << 3,
06486d
+        OPT_r = 1 << 4,
06486d
+        OPT_s = 1 << 5,
06486d
+    };
06486d
+
06486d
+    const char *build_ids = "build_ids";
06486d
+    const char *exact = NULL;
06486d
+    const char *repo = NULL;
06486d
+    const char *size_mb = NULL;
06486d
+
06486d
+    struct options program_options[] = {
06486d
+        OPT__VERBOSE(&g_verbose),
06486d
+        OPT_BOOL  ('y', "yes",         NULL,                   _("Noninteractive, assume 'Yes' to all questions")),
06486d
+        OPT_STRING('i', "ids",   &build_ids, "BUILD_IDS_FILE", _("- means STDIN, default: build_ids")),
06486d
+        OPT_STRING('e', "exact",     &exact, "EXACT",          _("Download only specified files")),
06486d
+        OPT_STRING('r', "repo",       &repo, "REPO",           _("Pattern to use when searching for repos, default: *debug*")),
06486d
+        OPT_STRING('s', "size_mb", &size_mb, "SIZE_MB",        _("Ignored option")),
06486d
+        OPT_END()
06486d
+    };
06486d
+    const unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
06486d
+
06486d
+    /* We need to open the build ids file under the caller's UID/GID to avoid
06486d
+     * information disclosures when reading files with changed UID.
06486d
+     * Unfortunately, we cannot replace STDIN with the new fd because ABRT uses
06486d
+     * STDIN to communicate with the caller. So, the following code opens a
06486d
+     * dummy file descriptor to the build ids file and passes the new fd's proc
06486d
+     * path to the wrapped program in the ids argument.
06486d
+     * The new fd remains opened, the OS will close it for us. */
06486d
+    char *build_ids_self_fd = NULL;
06486d
+    if (strcmp("-", build_ids) != 0)
06486d
+    {
06486d
+        const int build_ids_fd = open(build_ids, O_RDONLY);
06486d
+        if (build_ids_fd < 0)
06486d
+            perror_msg_and_die("Failed to open file '%s'", build_ids);
06486d
+
06486d
+        /* We are not going to free this memory. There is no place to do so. */
06486d
+        build_ids_self_fd = xasprintf("/proc/self/fd/%d", build_ids_fd);
06486d
+    }
06486d
+
06486d
+    /* name, -v, --ids, -, -y, -e, EXACT, -r, REPO, --, NULL */
06486d
+    const char *args[11];
06486d
     {
06486d
-        /* Allow taking ids from stdin */
06486d
-        if (strcmp(arg, "--ids=-") == 0)
06486d
-            continue;
06486d
-
06486d
-        if (strncmp(arg, "--exact", 7) == 0)
06486d
-            continue;
06486d
-
06486d
-        if (strncmp(arg, "--cache", 7) == 0)
06486d
-            error_msg_and_die("bad option %s", arg);
06486d
-        if (strncmp(arg, "--tmpdir", 8) == 0)
06486d
-            error_msg_and_die("bad option %s", arg);
06486d
-        if (strncmp(arg, "--ids", 5) == 0)
06486d
-            error_msg_and_die("bad option %s", arg);
06486d
+        const char *verbs[] = { "", "-v", "-vv", "-vvv" };
06486d
+        unsigned i = 0;
06486d
+        args[i++] = EXECUTABLE;
06486d
+        args[i++] = "--ids";
06486d
+        args[i++] = (build_ids_self_fd != NULL) ? build_ids_self_fd : "-";
06486d
+        args[i++] = verbs[g_verbose <= 3 ? g_verbose : 3];
06486d
+        if ((opts & OPT_y))
06486d
+            args[i++] = "-y";
06486d
+        if ((opts & OPT_e))
06486d
+        {
06486d
+            args[i++] = "--exact";
06486d
+            args[i++] = exact;
06486d
+        }
06486d
+        if ((opts & OPT_r))
06486d
+        {
06486d
+            args[i++] = "--repo";
06486d
+            args[i++] = repo;
06486d
+        }
06486d
+        args[i++] = "--";
06486d
+        args[i] = NULL;
06486d
     }
06486d
 
06486d
     /* Switch real user/group to effective ones.
06486d
@@ -122,6 +184,6 @@ int main(int argc, char **argv)
06486d
         putenv(path_env);
06486d
     }
06486d
 
06486d
-    execvp(EXECUTABLE, argv);
06486d
+    execvp(EXECUTABLE, (char **)args);
06486d
     error_msg_and_die("Can't execute %s", EXECUTABLE);
06486d
 }
06486d
-- 
06486d
1.8.3.1
06486d