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

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