Blame SOURCES/0072-TOOLS-replace-system-with-execvp.patch

f9c044
From a0d310e2c86facc8727b781e060b2b769313a5dd Mon Sep 17 00:00:00 2001
f9c044
From: Alexey Tikhonov <atikhono@redhat.com>
f9c044
Date: Fri, 30 Jul 2021 19:05:31 +0200
f9c044
Subject: [PATCH] TOOLS: replace system() with execvp() to avoid execution of
f9c044
 user supplied command
f9c044
f9c044
A flaw was found in SSSD, where the sssctl command was vulnerable
f9c044
to shell command injection via the logs-fetch and cache-expire
f9c044
subcommands. This flaw allows an attacker to trick the root user
f9c044
into running a specially crafted sssctl command, such as via sudo,
f9c044
to gain root access. The highest threat from this vulnerability is
f9c044
to confidentiality, integrity, as well as system availability.
f9c044
f9c044
:fixes: CVE-2021-3621
f9c044
---
f9c044
 src/tools/sssctl/sssctl.c      | 40 +++++++++++++++++-------
f9c044
 src/tools/sssctl/sssctl.h      |  2 +-
f9c044
 src/tools/sssctl/sssctl_data.c | 57 +++++++++++-----------------------
f9c044
 src/tools/sssctl/sssctl_logs.c | 31 ++++++++++++++----
f9c044
 4 files changed, 73 insertions(+), 57 deletions(-)
f9c044
f9c044
diff --git a/src/tools/sssctl/sssctl.c b/src/tools/sssctl/sssctl.c
f9c044
index 4a50a1d..bfc791b 100644
f9c044
--- a/src/tools/sssctl/sssctl.c
f9c044
+++ b/src/tools/sssctl/sssctl.c
f9c044
@@ -97,22 +97,37 @@ sssctl_prompt(const char *message,
f9c044
     return SSSCTL_PROMPT_ERROR;
f9c044
 }
f9c044
 
f9c044
-errno_t sssctl_run_command(const char *command)
f9c044
+errno_t sssctl_run_command(const char *const argv[])
f9c044
 {
f9c044
     int ret;
f9c044
+    int wstatus;
f9c044
 
f9c044
-    DEBUG(SSSDBG_TRACE_FUNC, "Running %s\n", command);
f9c044
+    DEBUG(SSSDBG_TRACE_FUNC, "Running '%s'\n", argv[0]);
f9c044
 
f9c044
-    ret = system(command);
f9c044
+    ret = fork();
f9c044
     if (ret == -1) {
f9c044
-        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to execute %s\n", command);
f9c044
         fprintf(stderr, _("Error while executing external command\n"));
f9c044
         return EFAULT;
f9c044
-    } else if (WEXITSTATUS(ret) != 0) {
f9c044
-        DEBUG(SSSDBG_CRIT_FAILURE, "Command %s failed with [%d]\n",
f9c044
-              command, WEXITSTATUS(ret));
f9c044
+    }
f9c044
+
f9c044
+    if (ret == 0) {
f9c044
+        /* cast is safe - see
f9c044
+        https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html
f9c044
+        "The statement about argv[] and envp[] being constants ... "
f9c044
+        */
f9c044
+        execvp(argv[0], discard_const_p(char * const, argv));
f9c044
         fprintf(stderr, _("Error while executing external command\n"));
f9c044
-        return EIO;
f9c044
+        _exit(1);
f9c044
+    } else {
f9c044
+        if (waitpid(ret, &wstatus, 0) == -1) {
f9c044
+            fprintf(stderr,
f9c044
+                    _("Error while executing external command '%s'\n"), argv[0]);
f9c044
+            return EFAULT;
f9c044
+        } else if (WEXITSTATUS(wstatus) != 0) {
f9c044
+            fprintf(stderr,
f9c044
+                    _("Command '%s' failed with [%d]\n"), argv[0], WEXITSTATUS(wstatus));
f9c044
+            return EIO;
f9c044
+        }
f9c044
     }
f9c044
 
f9c044
     return EOK;
f9c044
@@ -132,11 +147,14 @@ static errno_t sssctl_manage_service(enum sssctl_svc_action action)
f9c044
 #elif defined(HAVE_SERVICE)
f9c044
     switch (action) {
f9c044
     case SSSCTL_SVC_START:
f9c044
-        return sssctl_run_command(SERVICE_PATH" sssd start");
f9c044
+        return sssctl_run_command(
f9c044
+                      (const char *[]){SERVICE_PATH, "sssd", "start", NULL});
f9c044
     case SSSCTL_SVC_STOP:
f9c044
-        return sssctl_run_command(SERVICE_PATH" sssd stop");
f9c044
+        return sssctl_run_command(
f9c044
+                      (const char *[]){SERVICE_PATH, "sssd", "stop", NULL});
f9c044
     case SSSCTL_SVC_RESTART:
f9c044
-        return sssctl_run_command(SERVICE_PATH" sssd restart");
f9c044
+        return sssctl_run_command(
f9c044
+                      (const char *[]){SERVICE_PATH, "sssd", "restart", NULL});
f9c044
     }
f9c044
 #endif
f9c044
 
f9c044
diff --git a/src/tools/sssctl/sssctl.h b/src/tools/sssctl/sssctl.h
f9c044
index 0115b24..599ef65 100644
f9c044
--- a/src/tools/sssctl/sssctl.h
f9c044
+++ b/src/tools/sssctl/sssctl.h
f9c044
@@ -47,7 +47,7 @@ enum sssctl_prompt_result
f9c044
 sssctl_prompt(const char *message,
f9c044
               enum sssctl_prompt_result defval);
f9c044
 
f9c044
-errno_t sssctl_run_command(const char *command);
f9c044
+errno_t sssctl_run_command(const char *const argv[]); /* argv[0] - command */
f9c044
 bool sssctl_start_sssd(bool force);
f9c044
 bool sssctl_stop_sssd(bool force);
f9c044
 bool sssctl_restart_sssd(bool force);
f9c044
diff --git a/src/tools/sssctl/sssctl_data.c b/src/tools/sssctl/sssctl_data.c
f9c044
index cc46caf..8a04266 100644
f9c044
--- a/src/tools/sssctl/sssctl_data.c
f9c044
+++ b/src/tools/sssctl/sssctl_data.c
f9c044
@@ -105,15 +105,15 @@ static errno_t sssctl_backup(bool force)
f9c044
         }
f9c044
     }
f9c044
 
f9c044
-    ret = sssctl_run_command("sss_override user-export "
f9c044
-                             SSS_BACKUP_USER_OVERRIDES);
f9c044
+    ret = sssctl_run_command((const char *[]){"sss_override", "user-export",
f9c044
+                                              SSS_BACKUP_USER_OVERRIDES, NULL});
f9c044
     if (ret != EOK) {
f9c044
         fprintf(stderr, _("Unable to export user overrides\n"));
f9c044
         return ret;
f9c044
     }
f9c044
 
f9c044
-    ret = sssctl_run_command("sss_override group-export "
f9c044
-                             SSS_BACKUP_GROUP_OVERRIDES);
f9c044
+    ret = sssctl_run_command((const char *[]){"sss_override", "group-export",
f9c044
+                                              SSS_BACKUP_GROUP_OVERRIDES, NULL});
f9c044
     if (ret != EOK) {
f9c044
         fprintf(stderr, _("Unable to export group overrides\n"));
f9c044
         return ret;
f9c044
@@ -158,8 +158,8 @@ static errno_t sssctl_restore(bool force_start, bool force_restart)
f9c044
     }
f9c044
 
f9c044
     if (sssctl_backup_file_exists(SSS_BACKUP_USER_OVERRIDES)) {
f9c044
-        ret = sssctl_run_command("sss_override user-import "
f9c044
-                                 SSS_BACKUP_USER_OVERRIDES);
f9c044
+        ret = sssctl_run_command((const char *[]){"sss_override", "user-import",
f9c044
+                                                  SSS_BACKUP_USER_OVERRIDES, NULL});
f9c044
         if (ret != EOK) {
f9c044
             fprintf(stderr, _("Unable to import user overrides\n"));
f9c044
             return ret;
f9c044
@@ -167,8 +167,8 @@ static errno_t sssctl_restore(bool force_start, bool force_restart)
f9c044
     }
f9c044
 
f9c044
     if (sssctl_backup_file_exists(SSS_BACKUP_USER_OVERRIDES)) {
f9c044
-        ret = sssctl_run_command("sss_override group-import "
f9c044
-                                 SSS_BACKUP_GROUP_OVERRIDES);
f9c044
+        ret = sssctl_run_command((const char *[]){"sss_override", "group-import",
f9c044
+                                                  SSS_BACKUP_GROUP_OVERRIDES, NULL});
f9c044
         if (ret != EOK) {
f9c044
             fprintf(stderr, _("Unable to import group overrides\n"));
f9c044
             return ret;
f9c044
@@ -296,40 +296,19 @@ errno_t sssctl_cache_expire(struct sss_cmdline *cmdline,
f9c044
                             void *pvt)
f9c044
 {
f9c044
     errno_t ret;
f9c044
-    char *cmd_args = NULL;
f9c044
-    const char *cachecmd = SSS_CACHE;
f9c044
-    char *cmd = NULL;
f9c044
-    int i;
f9c044
-
f9c044
-    if (cmdline->argc == 0) {
f9c044
-        ret = sssctl_run_command(cachecmd);
f9c044
-        goto done;
f9c044
-    }
f9c044
 
f9c044
-    cmd_args = talloc_strdup(tool_ctx, "");
f9c044
-    if (cmd_args == NULL) {
f9c044
-        ret = ENOMEM;
f9c044
-        goto done;
f9c044
+    const char **args = talloc_array_size(tool_ctx,
f9c044
+                                          sizeof(char *),
f9c044
+                                          cmdline->argc + 2);
f9c044
+    if (!args) {
f9c044
+        return ENOMEM;
f9c044
     }
f9c044
+    memcpy(&args[1], cmdline->argv, sizeof(char *) * cmdline->argc);
f9c044
+    args[0] = SSS_CACHE;
f9c044
+    args[cmdline->argc + 1] = NULL;
f9c044
 
f9c044
-    for (i = 0; i < cmdline->argc; i++) {
f9c044
-        cmd_args = talloc_strdup_append(cmd_args, cmdline->argv[i]);
f9c044
-        if (i != cmdline->argc - 1) {
f9c044
-            cmd_args = talloc_strdup_append(cmd_args, " ");
f9c044
-        }
f9c044
-    }
f9c044
-
f9c044
-    cmd = talloc_asprintf(tool_ctx, "%s %s", cachecmd, cmd_args);
f9c044
-    if (cmd == NULL) {
f9c044
-        ret = ENOMEM;
f9c044
-        goto done;
f9c044
-    }
f9c044
-
f9c044
-    ret = sssctl_run_command(cmd);
f9c044
-
f9c044
-done:
f9c044
-    talloc_free(cmd_args);
f9c044
-    talloc_free(cmd);
f9c044
+    ret = sssctl_run_command(args);
f9c044
 
f9c044
+    talloc_free(args);
f9c044
     return ret;
f9c044
 }
f9c044
diff --git a/src/tools/sssctl/sssctl_logs.c b/src/tools/sssctl/sssctl_logs.c
f9c044
index aca988c..c85cc7a 100644
f9c044
--- a/src/tools/sssctl/sssctl_logs.c
f9c044
+++ b/src/tools/sssctl/sssctl_logs.c
f9c044
@@ -32,6 +32,7 @@
f9c044
 #include <popt.h>
f9c044
 #include <stdio.h>
f9c044
 #include <signal.h>
f9c044
+#include <glob.h>
f9c044
 
f9c044
 #include "util/util.h"
f9c044
 #include "tools/common/sss_process.h"
f9c044
@@ -231,6 +232,7 @@ errno_t sssctl_logs_remove(struct sss_cmdline *cmdline,
f9c044
 {
f9c044
     struct sssctl_logs_opts opts = {0};
f9c044
     errno_t ret;
f9c044
+    glob_t globbuf;
f9c044
 
f9c044
     /* Parse command line. */
f9c044
     struct poptOption options[] = {
f9c044
@@ -254,8 +256,19 @@ errno_t sssctl_logs_remove(struct sss_cmdline *cmdline,
f9c044
 
f9c044
         sss_signal(SIGHUP);
f9c044
     } else {
f9c044
+        globbuf.gl_offs = 4;
f9c044
+        ret = glob(LOG_PATH"/*.log", GLOB_ERR|GLOB_DOOFFS, NULL, &globbuf);
f9c044
+        if (ret != 0) {
f9c044
+            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to expand log files list\n");
f9c044
+            return ret;
f9c044
+        }
f9c044
+        globbuf.gl_pathv[0] = discard_const_p(char, "truncate");
f9c044
+        globbuf.gl_pathv[2] = discard_const_p(char, "--size");
f9c044
+        globbuf.gl_pathv[3] = discard_const_p(char, "0");
f9c044
+
f9c044
         printf(_("Truncating log files...\n"));
f9c044
-        ret = sssctl_run_command("truncate --size 0 " LOG_FILES);
f9c044
+        ret = sssctl_run_command((const char * const*)globbuf.gl_pathv);
f9c044
+        globfree(&globbuf);
f9c044
         if (ret != EOK) {
f9c044
             fprintf(stderr, _("Unable to truncate log files\n"));
f9c044
             return ret;
f9c044
@@ -270,8 +283,8 @@ errno_t sssctl_logs_fetch(struct sss_cmdline *cmdline,
f9c044
                           void *pvt)
f9c044
 {
f9c044
     const char *file;
f9c044
-    const char *cmd;
f9c044
     errno_t ret;
f9c044
+    glob_t globbuf;
f9c044
 
f9c044
     /* Parse command line. */
f9c044
     ret = sss_tool_popt_ex(cmdline, NULL, SSS_TOOL_OPT_OPTIONAL, NULL, NULL,
f9c044
@@ -281,13 +294,19 @@ errno_t sssctl_logs_fetch(struct sss_cmdline *cmdline,
f9c044
         return ret;
f9c044
     }
f9c044
 
f9c044
-    cmd = talloc_asprintf(tool_ctx, "tar -czf %s %s", file, LOG_FILES);
f9c044
-    if (cmd == NULL) {
f9c044
-        fprintf(stderr, _("Out of memory!"));
f9c044
+    globbuf.gl_offs = 3;
f9c044
+    ret = glob(LOG_PATH"/*.log", GLOB_ERR|GLOB_DOOFFS, NULL, &globbuf);
f9c044
+    if (ret != 0) {
f9c044
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to expand log files list\n");
f9c044
+        return ret;
f9c044
     }
f9c044
+    globbuf.gl_pathv[0] = discard_const_p(char, "tar");
f9c044
+    globbuf.gl_pathv[1] = discard_const_p(char, "-czf");
f9c044
+    globbuf.gl_pathv[2] = discard_const_p(char, file);
f9c044
 
f9c044
     printf(_("Archiving log files into %s...\n"), file);
f9c044
-    ret = sssctl_run_command(cmd);
f9c044
+    ret = sssctl_run_command((const char * const*)globbuf.gl_pathv);
f9c044
+    globfree(&globbuf);
f9c044
     if (ret != EOK) {
f9c044
         fprintf(stderr, _("Unable to archive log files\n"));
f9c044
         return ret;
f9c044
-- 
f9c044
2.26.3
f9c044