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

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