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

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