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

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