fix CVE-2023-28486 and CVE-2023-28487
(cherry picked from commit 454d23bbb22f13dfb02f5bfaf5bffb3f8dc59bb1)
This commit is contained in:
parent
a27b1a0d68
commit
90dc8973d0
847
backport-CVE-2023-28486_CVE-2023-28487.patch
Normal file
847
backport-CVE-2023-28486_CVE-2023-28487.patch
Normal file
@ -0,0 +1,847 @@
|
||||
From 334daf92b31b79ce68ed75e2ee14fca265f029ca Mon Sep 17 00:00:00 2001
|
||||
From: "Todd C. Miller" <Todd.Miller@sudo.ws>
|
||||
Date: Wed, 18 Jan 2023 08:21:34 -0700
|
||||
Subject: [PATCH] Escape control characters in log messages and "sudoreplay -l"
|
||||
output. The log message contains user-controlled strings that could include
|
||||
things like terminal control characters. Space characters in the command
|
||||
path are now also escaped.
|
||||
|
||||
Command line arguments that contain spaces are surrounded with
|
||||
single quotes and any literal single quote or backslash characters
|
||||
are escaped with a backslash. This makes it possible to distinguish
|
||||
multiple command line arguments from a single argument that contains
|
||||
spaces.
|
||||
|
||||
Issue found by Matthieu Barjole and Victor Cutillas of Synacktiv
|
||||
(https://synacktiv.com).
|
||||
---
|
||||
include/sudo_lbuf.h | 7 ++
|
||||
lib/iolog/iolog_json.c | 29 -------
|
||||
lib/util/lbuf.c | 106 +++++++++++++++++++++++
|
||||
lib/util/util.exp.in | 1 +
|
||||
logsrvd/eventlog.c | 161 ++++++++++++-----------------------
|
||||
plugins/sudoers/logging.c | 138 +++++++++---------------------
|
||||
plugins/sudoers/sudoreplay.c | 132 +++++++++++++++++++++++++---
|
||||
7 files changed, 329 insertions(+), 245 deletions(-)
|
||||
|
||||
diff --git a/include/sudo_lbuf.h b/include/sudo_lbuf.h
|
||||
index 4c81780..9404193 100644
|
||||
--- a/include/sudo_lbuf.h
|
||||
+++ b/include/sudo_lbuf.h
|
||||
@@ -36,9 +36,15 @@ struct sudo_lbuf {
|
||||
|
||||
typedef int (*sudo_lbuf_output_t)(const char *);
|
||||
|
||||
+/* Flags for sudo_lbuf_append_esc() */
|
||||
+#define LBUF_ESC_CNTRL 0x01
|
||||
+#define LBUF_ESC_BLANK 0x02
|
||||
+#define LBUF_ESC_QUOTE 0x04
|
||||
+
|
||||
__dso_public void sudo_lbuf_init_v1(struct sudo_lbuf *lbuf, sudo_lbuf_output_t output, int indent, const char *continuation, int cols);
|
||||
__dso_public void sudo_lbuf_destroy_v1(struct sudo_lbuf *lbuf);
|
||||
__dso_public bool sudo_lbuf_append_v1(struct sudo_lbuf *lbuf, const char *fmt, ...) __printflike(2, 3);
|
||||
+__dso_public bool sudo_lbuf_append_esc_v1(struct sudo_lbuf *lbuf, int flags, const char *fmt, ...) __printflike(3, 4);
|
||||
__dso_public bool sudo_lbuf_append_quoted_v1(struct sudo_lbuf *lbuf, const char *set, const char *fmt, ...) __printflike(3, 4);
|
||||
__dso_public void sudo_lbuf_print_v1(struct sudo_lbuf *lbuf);
|
||||
__dso_public bool sudo_lbuf_error_v1(struct sudo_lbuf *lbuf);
|
||||
@@ -47,6 +53,7 @@ __dso_public void sudo_lbuf_clearerr_v1(struct sudo_lbuf *lbuf);
|
||||
#define sudo_lbuf_init(_a, _b, _c, _d, _e) sudo_lbuf_init_v1((_a), (_b), (_c), (_d), (_e))
|
||||
#define sudo_lbuf_destroy(_a) sudo_lbuf_destroy_v1((_a))
|
||||
#define sudo_lbuf_append sudo_lbuf_append_v1
|
||||
+#define sudo_lbuf_append_esc sudo_lbuf_append_esc_v1
|
||||
#define sudo_lbuf_append_quoted sudo_lbuf_append_quoted_v1
|
||||
#define sudo_lbuf_print(_a) sudo_lbuf_print_v1((_a))
|
||||
#define sudo_lbuf_error(_a) sudo_lbuf_error_v1((_a))
|
||||
diff --git a/lib/iolog/iolog_json.c b/lib/iolog/iolog_json.c
|
||||
index db4d785..652b876 100644
|
||||
--- a/lib/iolog/iolog_json.c
|
||||
+++ b/lib/iolog/iolog_json.c
|
||||
@@ -421,35 +421,6 @@ iolog_parse_json_object(struct json_object *object, struct iolog_info *li)
|
||||
}
|
||||
}
|
||||
|
||||
- /* Merge cmd and argv as sudoreplay expects. */
|
||||
- if (li->cmd != NULL && li->argv != NULL) {
|
||||
- size_t len = strlen(li->cmd) + 1;
|
||||
- char *newcmd;
|
||||
- int ac;
|
||||
-
|
||||
- /* Skip argv[0], we use li->cmd instead. */
|
||||
- for (ac = 1; li->argv[ac] != NULL; ac++)
|
||||
- len += strlen(li->argv[ac]) + 1;
|
||||
-
|
||||
- if ((newcmd = malloc(len)) == NULL) {
|
||||
- sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||
- goto done;
|
||||
- }
|
||||
-
|
||||
- /* TODO: optimize this. */
|
||||
- if (strlcpy(newcmd, li->cmd, len) >= len)
|
||||
- sudo_fatalx(U_("internal error, %s overflow"), __func__);
|
||||
- for (ac = 1; li->argv[ac] != NULL; ac++) {
|
||||
- if (strlcat(newcmd, " ", len) >= len)
|
||||
- sudo_fatalx(U_("internal error, %s overflow"), __func__);
|
||||
- if (strlcat(newcmd, li->argv[ac], len) >= len)
|
||||
- sudo_fatalx(U_("internal error, %s overflow"), __func__);
|
||||
- }
|
||||
-
|
||||
- free(li->cmd);
|
||||
- li->cmd = newcmd;
|
||||
- }
|
||||
-
|
||||
ret = true;
|
||||
|
||||
done:
|
||||
diff --git a/lib/util/lbuf.c b/lib/util/lbuf.c
|
||||
index f17ae0c..a9a57c9 100644
|
||||
--- a/lib/util/lbuf.c
|
||||
+++ b/lib/util/lbuf.c
|
||||
@@ -87,6 +87,112 @@ sudo_lbuf_expand(struct sudo_lbuf *lbuf, int extra)
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Escape a character in octal form (#0n) and store it as a string
|
||||
+ * in buf, which must have at least 6 bytes available.
|
||||
+ * Returns the length of buf, not counting the terminating NUL byte.
|
||||
+ */
|
||||
+static int
|
||||
+escape(unsigned char ch, char *buf)
|
||||
+{
|
||||
+ const int len = ch < 0100 ? (ch < 010 ? 3 : 4) : 5;
|
||||
+
|
||||
+ /* Work backwards from the least significant digit to most significant. */
|
||||
+ switch (len) {
|
||||
+ case 5:
|
||||
+ buf[4] = (ch & 7) + '0';
|
||||
+ ch >>= 3;
|
||||
+
|
||||
+ case 4:
|
||||
+ buf[3] = (ch & 7) + '0';
|
||||
+ ch >>= 3;
|
||||
+
|
||||
+ case 3:
|
||||
+ buf[2] = (ch & 7) + '0';
|
||||
+ buf[1] = '0';
|
||||
+ buf[0] = '#';
|
||||
+ break;
|
||||
+ }
|
||||
+ buf[len] = '\0';
|
||||
+
|
||||
+ return len;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Parse the format and append strings, only %s and %% escapes are supported.
|
||||
+ * Any non-printable characters are escaped in octal as #0nn.
|
||||
+ */
|
||||
+bool
|
||||
+sudo_lbuf_append_esc_v1(struct sudo_lbuf *lbuf, int flags, const char *fmt, ...)
|
||||
+{
|
||||
+ unsigned int saved_len = lbuf->len;
|
||||
+ bool ret = false;
|
||||
+ const char *s;
|
||||
+ va_list ap;
|
||||
+ debug_decl(sudo_lbuf_append_esc, SUDO_DEBUG_UTIL);
|
||||
+
|
||||
+ if (sudo_lbuf_error(lbuf))
|
||||
+ debug_return_bool(false);
|
||||
+
|
||||
+#define should_escape(ch) \
|
||||
+ ((ISSET(flags, LBUF_ESC_CNTRL) && iscntrl((unsigned char)ch)) || \
|
||||
+ (ISSET(flags, LBUF_ESC_BLANK) && isblank((unsigned char)ch)))
|
||||
+#define should_quote(ch) \
|
||||
+ (ISSET(flags, LBUF_ESC_QUOTE) && (ch == '\'' || ch == '\\'))
|
||||
+
|
||||
+ va_start(ap, fmt);
|
||||
+ while (*fmt != '\0') {
|
||||
+ if (fmt[0] == '%' && fmt[1] == 's') {
|
||||
+ if ((s = va_arg(ap, char *)) == NULL)
|
||||
+ s = "(NULL)";
|
||||
+ while (*s != '\0') {
|
||||
+ if (should_escape(*s)) {
|
||||
+ if (!sudo_lbuf_expand(lbuf, sizeof("#0177") - 1))
|
||||
+ goto done;
|
||||
+ lbuf->len += escape(*s++, lbuf->buf + lbuf->len);
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (should_quote(*s)) {
|
||||
+ if (!sudo_lbuf_expand(lbuf, 2))
|
||||
+ goto done;
|
||||
+ lbuf->buf[lbuf->len++] = '\\';
|
||||
+ lbuf->buf[lbuf->len++] = *s++;
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (!sudo_lbuf_expand(lbuf, 1))
|
||||
+ goto done;
|
||||
+ lbuf->buf[lbuf->len++] = *s++;
|
||||
+ }
|
||||
+ fmt += 2;
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (should_escape(*fmt)) {
|
||||
+ if (!sudo_lbuf_expand(lbuf, sizeof("#0177") - 1))
|
||||
+ goto done;
|
||||
+ if (*fmt == '\'') {
|
||||
+ lbuf->buf[lbuf->len++] = '\\';
|
||||
+ lbuf->buf[lbuf->len++] = *fmt++;
|
||||
+ } else {
|
||||
+ lbuf->len += escape(*fmt++, lbuf->buf + lbuf->len);
|
||||
+ }
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (!sudo_lbuf_expand(lbuf, 1))
|
||||
+ goto done;
|
||||
+ lbuf->buf[lbuf->len++] = *fmt++;
|
||||
+ }
|
||||
+ ret = true;
|
||||
+
|
||||
+done:
|
||||
+ if (!ret)
|
||||
+ lbuf->len = saved_len;
|
||||
+ if (lbuf->size != 0)
|
||||
+ lbuf->buf[lbuf->len] = '\0';
|
||||
+ va_end(ap);
|
||||
+
|
||||
+ debug_return_bool(ret);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Parse the format and append strings, only %s and %% escapes are supported.
|
||||
* Any characters in set are quoted with a backslash.
|
||||
diff --git a/lib/util/util.exp.in b/lib/util/util.exp.in
|
||||
index 6095623..881b35b 100644
|
||||
--- a/lib/util/util.exp.in
|
||||
+++ b/lib/util/util.exp.in
|
||||
@@ -94,6 +94,7 @@ sudo_json_get_len_v1
|
||||
sudo_json_init_v1
|
||||
sudo_json_open_array_v1
|
||||
sudo_json_open_object_v1
|
||||
+sudo_lbuf_append_esc_v1
|
||||
sudo_lbuf_append_quoted_v1
|
||||
sudo_lbuf_append_v1
|
||||
sudo_lbuf_clearerr_v1
|
||||
diff --git a/logsrvd/eventlog.c b/logsrvd/eventlog.c
|
||||
index 2c7920c..c5f37d4 100644
|
||||
--- a/logsrvd/eventlog.c
|
||||
+++ b/logsrvd/eventlog.c
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "log_server.pb-c.h"
|
||||
#include "sudo_gettext.h" /* must be included before sudo_compat.h */
|
||||
#include "sudo_compat.h"
|
||||
+#include "sudo_lbuf.h"
|
||||
#include "sudo_fatal.h"
|
||||
#include "sudo_json.h"
|
||||
#include "sudo_queue.h"
|
||||
@@ -80,14 +81,15 @@ static char *
|
||||
new_logline(const char *message, const char *errstr,
|
||||
const struct iolog_details *details)
|
||||
{
|
||||
- char *line = NULL, *evstr = NULL;
|
||||
const char *iolog_file = details->iolog_file;
|
||||
char sessid[7];
|
||||
const char *tsid = NULL;
|
||||
- size_t len = 0;
|
||||
+ struct sudo_lbuf lbuf;
|
||||
int i;
|
||||
debug_decl(new_logline, SUDO_DEBUG_UTIL);
|
||||
|
||||
+ sudo_lbuf_init(&lbuf, NULL, 0, NULL, 0);
|
||||
+
|
||||
/* A TSID may be a sudoers-style session ID or a free-form string. */
|
||||
if (iolog_file != NULL) {
|
||||
if (IS_SESSID(iolog_file)) {
|
||||
@@ -105,128 +107,77 @@ new_logline(const char *message, const char *errstr,
|
||||
}
|
||||
|
||||
/*
|
||||
- * Compute line length
|
||||
- */
|
||||
- if (message != NULL)
|
||||
- len += strlen(message) + 3;
|
||||
- if (errstr != NULL)
|
||||
- len += strlen(errstr) + 3;
|
||||
- len += sizeof(LL_HOST_STR) + 2 + strlen(details->submithost);
|
||||
- len += sizeof(LL_TTY_STR) + 2 + strlen(details->ttyname);
|
||||
- len += sizeof(LL_CWD_STR) + 2 + strlen(details->cwd);
|
||||
- if (details->runuser != NULL)
|
||||
- len += sizeof(LL_USER_STR) + 2 + strlen(details->runuser);
|
||||
- if (details->rungroup != NULL)
|
||||
- len += sizeof(LL_GROUP_STR) + 2 + strlen(details->rungroup);
|
||||
- if (tsid != NULL)
|
||||
- len += sizeof(LL_TSID_STR) + 2 + strlen(tsid);
|
||||
- if (details->env_add != NULL) {
|
||||
- size_t evlen = 0;
|
||||
- char * const *ep;
|
||||
-
|
||||
- for (ep = details->env_add; *ep != NULL; ep++)
|
||||
- evlen += strlen(*ep) + 1;
|
||||
- if (evlen != 0) {
|
||||
- if ((evstr = malloc(evlen)) == NULL)
|
||||
- goto oom;
|
||||
- ep = details->env_add;
|
||||
- if (strlcpy(evstr, *ep, evlen) >= evlen)
|
||||
- goto toobig;
|
||||
- while (*++ep != NULL) {
|
||||
- if (strlcat(evstr, " ", evlen) >= evlen ||
|
||||
- strlcat(evstr, *ep, evlen) >= evlen)
|
||||
- goto toobig;
|
||||
- }
|
||||
- len += sizeof(LL_ENV_STR) + 2 + evlen;
|
||||
- }
|
||||
- }
|
||||
- if (details->command != NULL) {
|
||||
- len += sizeof(LL_CMND_STR) - 1 + strlen(details->command);
|
||||
- if (details->argc > 1) {
|
||||
- for (i = 1; i < details->argc; i++)
|
||||
- len += strlen(details->argv[i]) + 1;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- /*
|
||||
- * Allocate and build up the line.
|
||||
+ * Format the log line as an lbuf, escaping control characters in
|
||||
+ * octal form (#0nn). Error checking (ENOMEM) is done at the end.
|
||||
*/
|
||||
- if ((line = malloc(++len)) == NULL)
|
||||
- goto oom;
|
||||
- line[0] = '\0';
|
||||
-
|
||||
if (message != NULL) {
|
||||
- if (strlcat(line, message, len) >= len ||
|
||||
- strlcat(line, errstr ? " : " : " ; ", len) >= len)
|
||||
- goto toobig;
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s%s", message,
|
||||
+ errstr ? " : " : " ; ");
|
||||
}
|
||||
if (errstr != NULL) {
|
||||
- if (strlcat(line, errstr, len) >= len ||
|
||||
- strlcat(line, " ; ", len) >= len)
|
||||
- goto toobig;
|
||||
- }
|
||||
- if (strlcat(line, LL_HOST_STR, len) >= len ||
|
||||
- strlcat(line, details->submithost, len) >= len ||
|
||||
- strlcat(line, " ; ", len) >= len)
|
||||
- goto toobig;
|
||||
- if (strlcat(line, LL_TTY_STR, len) >= len ||
|
||||
- strlcat(line, details->ttyname, len) >= len ||
|
||||
- strlcat(line, " ; ", len) >= len)
|
||||
- goto toobig;
|
||||
- if (strlcat(line, LL_CWD_STR, len) >= len ||
|
||||
- strlcat(line, details->cwd, len) >= len ||
|
||||
- strlcat(line, " ; ", len) >= len)
|
||||
- goto toobig;
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s ; ", errstr);
|
||||
+ }
|
||||
+ if (details->submithost != NULL) {
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s%s ; ",
|
||||
+ LL_HOST_STR, details->submithost);
|
||||
+ }
|
||||
+ if (details->ttyname != NULL) {
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s%s ; ",
|
||||
+ LL_TTY_STR, details->ttyname);
|
||||
+ }
|
||||
+ if (details->cwd != NULL) {
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s%s ; ",
|
||||
+ LL_CWD_STR, details->cwd);
|
||||
+ }
|
||||
if (details->runuser != NULL) {
|
||||
- if (strlcat(line, LL_USER_STR, len) >= len ||
|
||||
- strlcat(line, details->runuser, len) >= len ||
|
||||
- strlcat(line, " ; ", len) >= len)
|
||||
- goto toobig;
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s%s ; ",
|
||||
+ LL_USER_STR, details->runuser);
|
||||
}
|
||||
if (details->rungroup != NULL) {
|
||||
- if (strlcat(line, LL_GROUP_STR, len) >= len ||
|
||||
- strlcat(line, details->rungroup, len) >= len ||
|
||||
- strlcat(line, " ; ", len) >= len)
|
||||
- goto toobig;
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s%s ; ",
|
||||
+ LL_GROUP_STR, details->rungroup);
|
||||
}
|
||||
if (tsid != NULL) {
|
||||
- if (strlcat(line, LL_TSID_STR, len) >= len ||
|
||||
- strlcat(line, tsid, len) >= len ||
|
||||
- strlcat(line, " ; ", len) >= len)
|
||||
- goto toobig;
|
||||
- }
|
||||
- if (evstr != NULL) {
|
||||
- if (strlcat(line, LL_ENV_STR, len) >= len ||
|
||||
- strlcat(line, evstr, len) >= len ||
|
||||
- strlcat(line, " ; ", len) >= len)
|
||||
- goto toobig;
|
||||
- free(evstr);
|
||||
- evstr = NULL;
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s%s ; ",
|
||||
+ LL_TSID_STR, tsid);
|
||||
}
|
||||
+ if (details->env_add != NULL && details->env_add[0] != NULL) {
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s%s",
|
||||
+ LL_ENV_STR, details->env_add[0]);
|
||||
+ for (i = 1; details->env_add[i] != NULL; i++) {
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, " %s",
|
||||
+ details->env_add[i]);
|
||||
+ }
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "; ");
|
||||
+ }
|
||||
+
|
||||
if (details->command != NULL) {
|
||||
- if (strlcat(line, LL_CMND_STR, len) >= len)
|
||||
- goto toobig;
|
||||
- if (strlcat(line, details->command, len) >= len)
|
||||
- goto toobig;
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL|LBUF_ESC_BLANK,
|
||||
+ "%s%s", LL_CMND_STR, details->command);
|
||||
if (details->argc > 1) {
|
||||
for (i = 1; i < details->argc; i++) {
|
||||
- if (strlcat(line, " ", len) >= len ||
|
||||
- strlcat(line, details->argv[i], len) >= len)
|
||||
- goto toobig;
|
||||
+ sudo_lbuf_append(&lbuf, " ");
|
||||
+ if (strchr(details->argv[i], ' ') != NULL) {
|
||||
+ /* Wrap args containing spaces in single quotes. */
|
||||
+ sudo_lbuf_append(&lbuf, "'");
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL|LBUF_ESC_QUOTE,
|
||||
+ "%s", details->argv[i]);
|
||||
+ sudo_lbuf_append(&lbuf, "'");
|
||||
+ } else {
|
||||
+ /* Escape quotes here too for consistency. */
|
||||
+ sudo_lbuf_append_esc(&lbuf,
|
||||
+ LBUF_ESC_CNTRL|LBUF_ESC_BLANK|LBUF_ESC_QUOTE,
|
||||
+ "%s", details->argv[i]);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
||||
+ if (!sudo_lbuf_error(&lbuf))
|
||||
+ debug_return_str(lbuf.buf);
|
||||
|
||||
- debug_return_str(line);
|
||||
-oom:
|
||||
- free(evstr);
|
||||
+ sudo_lbuf_destroy(&lbuf);
|
||||
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||
debug_return_str(NULL);
|
||||
-toobig:
|
||||
- free(evstr);
|
||||
- free(line);
|
||||
- sudo_warnx(U_("internal error, %s overflow"), __func__);
|
||||
- debug_return_str(NULL);
|
||||
}
|
||||
|
||||
static bool
|
||||
diff --git a/plugins/sudoers/logging.c b/plugins/sudoers/logging.c
|
||||
index a68fba7..de5bb30 100644
|
||||
--- a/plugins/sudoers/logging.c
|
||||
+++ b/plugins/sudoers/logging.c
|
||||
@@ -50,6 +50,7 @@
|
||||
#include <syslog.h>
|
||||
|
||||
#include "sudoers.h"
|
||||
+#include "sudo_lbuf.h"
|
||||
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
# include "compat/getaddrinfo.h"
|
||||
@@ -945,14 +946,16 @@ should_mail(int status)
|
||||
char *
|
||||
new_logline(const char *message, const char *errstr)
|
||||
{
|
||||
- char *line = NULL, *evstr = NULL;
|
||||
#ifndef SUDOERS_NO_SEQ
|
||||
char sessid[7];
|
||||
#endif
|
||||
const char *tsid = NULL;
|
||||
- size_t len = 0;
|
||||
+ struct sudo_lbuf lbuf;
|
||||
+ int i;
|
||||
debug_decl(new_logline, SUDOERS_DEBUG_LOGGING);
|
||||
|
||||
+ sudo_lbuf_init(&lbuf, NULL, 0, NULL, 0);
|
||||
+
|
||||
#ifndef SUDOERS_NO_SEQ
|
||||
/* A TSID may be a sudoers-style session ID or a free-form string. */
|
||||
if (sudo_user.iolog_file != NULL) {
|
||||
@@ -972,119 +975,58 @@ new_logline(const char *message, const char *errstr)
|
||||
#endif
|
||||
|
||||
/*
|
||||
- * Compute line length
|
||||
+ * Format the log line as an lbuf, escaping control characters in
|
||||
+ * octal form (#0nn). Error checking (ENOMEM) is done at the end.
|
||||
*/
|
||||
- if (message != NULL)
|
||||
- len += strlen(message) + 3;
|
||||
- if (errstr != NULL)
|
||||
- len += strlen(errstr) + 3;
|
||||
- len += sizeof(LL_TTY_STR) + 2 + strlen(user_tty);
|
||||
- len += sizeof(LL_CWD_STR) + 2 + strlen(user_cwd);
|
||||
- if (runas_pw != NULL)
|
||||
- len += sizeof(LL_USER_STR) + 2 + strlen(runas_pw->pw_name);
|
||||
- if (runas_gr != NULL)
|
||||
- len += sizeof(LL_GROUP_STR) + 2 + strlen(runas_gr->gr_name);
|
||||
- if (tsid != NULL)
|
||||
- len += sizeof(LL_TSID_STR) + 2 + strlen(tsid);
|
||||
- if (sudo_user.env_vars != NULL) {
|
||||
- size_t evlen = 0;
|
||||
- char * const *ep;
|
||||
-
|
||||
- for (ep = sudo_user.env_vars; *ep != NULL; ep++)
|
||||
- evlen += strlen(*ep) + 1;
|
||||
- if (evlen != 0) {
|
||||
- if ((evstr = malloc(evlen)) == NULL)
|
||||
- goto oom;
|
||||
- evstr[0] = '\0';
|
||||
- for (ep = sudo_user.env_vars; *ep != NULL; ep++) {
|
||||
- strlcat(evstr, *ep, evlen);
|
||||
- strlcat(evstr, " ", evlen); /* NOTE: last one will fail */
|
||||
- }
|
||||
- len += sizeof(LL_ENV_STR) + 2 + evlen;
|
||||
- }
|
||||
- }
|
||||
- if (user_cmnd != NULL) {
|
||||
- /* Note: we log "sudo -l command arg ..." as "list command arg ..." */
|
||||
- len += sizeof(LL_CMND_STR) - 1 + strlen(user_cmnd);
|
||||
- if (ISSET(sudo_mode, MODE_CHECK))
|
||||
- len += sizeof("list ") - 1;
|
||||
- if (user_args != NULL)
|
||||
- len += strlen(user_args) + 1;
|
||||
- }
|
||||
-
|
||||
- /*
|
||||
- * Allocate and build up the line.
|
||||
- */
|
||||
- if ((line = malloc(++len)) == NULL)
|
||||
- goto oom;
|
||||
- line[0] = '\0';
|
||||
-
|
||||
if (message != NULL) {
|
||||
- if (strlcat(line, message, len) >= len ||
|
||||
- strlcat(line, errstr ? " : " : " ; ", len) >= len)
|
||||
- goto toobig;
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s%s", message,
|
||||
+ errstr ? " : " : " ; ");
|
||||
}
|
||||
if (errstr != NULL) {
|
||||
- if (strlcat(line, errstr, len) >= len ||
|
||||
- strlcat(line, " ; ", len) >= len)
|
||||
- goto toobig;
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s ; ", errstr);
|
||||
+ }
|
||||
+ if (user_tty != NULL) {
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s%s ; ", LL_TTY_STR,
|
||||
+ user_tty);
|
||||
+ }
|
||||
+ if (user_cwd != NULL) {
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s%s ; ", LL_CWD_STR,
|
||||
+ user_cwd);
|
||||
}
|
||||
- if (strlcat(line, LL_TTY_STR, len) >= len ||
|
||||
- strlcat(line, user_tty, len) >= len ||
|
||||
- strlcat(line, " ; ", len) >= len)
|
||||
- goto toobig;
|
||||
- if (strlcat(line, LL_CWD_STR, len) >= len ||
|
||||
- strlcat(line, user_cwd, len) >= len ||
|
||||
- strlcat(line, " ; ", len) >= len)
|
||||
- goto toobig;
|
||||
if (runas_pw != NULL) {
|
||||
- if (strlcat(line, LL_USER_STR, len) >= len ||
|
||||
- strlcat(line, runas_pw->pw_name, len) >= len ||
|
||||
- strlcat(line, " ; ", len) >= len)
|
||||
- goto toobig;
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s%s ; ", LL_USER_STR,
|
||||
+ runas_pw->pw_name);
|
||||
}
|
||||
if (runas_gr != NULL) {
|
||||
- if (strlcat(line, LL_GROUP_STR, len) >= len ||
|
||||
- strlcat(line, runas_gr->gr_name, len) >= len ||
|
||||
- strlcat(line, " ; ", len) >= len)
|
||||
- goto toobig;
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s%s ; ", LL_GROUP_STR,
|
||||
+ runas_gr->gr_name);
|
||||
}
|
||||
if (tsid != NULL) {
|
||||
- if (strlcat(line, LL_TSID_STR, len) >= len ||
|
||||
- strlcat(line, tsid, len) >= len ||
|
||||
- strlcat(line, " ; ", len) >= len)
|
||||
- goto toobig;
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s%s ; ", LL_TSID_STR,
|
||||
+ tsid);
|
||||
}
|
||||
- if (evstr != NULL) {
|
||||
- if (strlcat(line, LL_ENV_STR, len) >= len ||
|
||||
- strlcat(line, evstr, len) >= len ||
|
||||
- strlcat(line, " ; ", len) >= len)
|
||||
- goto toobig;
|
||||
- free(evstr);
|
||||
- evstr = NULL;
|
||||
+ if (sudo_user.env_vars != NULL && sudo_user.env_vars[0] != NULL) {
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s%s",
|
||||
+ LL_ENV_STR, sudo_user.env_vars[0]);
|
||||
+ for (i = 1; sudo_user.env_vars[i] != NULL; i++) {
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, " %s",
|
||||
+ sudo_user.env_vars[i]);
|
||||
+ }
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "; ");
|
||||
}
|
||||
if (user_cmnd != NULL) {
|
||||
- if (strlcat(line, LL_CMND_STR, len) >= len)
|
||||
- goto toobig;
|
||||
- if (ISSET(sudo_mode, MODE_CHECK) && strlcat(line, "list ", len) >= len)
|
||||
- goto toobig;
|
||||
- if (strlcat(line, user_cmnd, len) >= len)
|
||||
- goto toobig;
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL|LBUF_ESC_BLANK, "%s", LL_CMND_STR);
|
||||
+ if (ISSET(sudo_mode, MODE_CHECK))
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL|LBUF_ESC_BLANK, "%s", "list ");
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL|LBUF_ESC_BLANK, "%s", user_cmnd);
|
||||
if (user_args != NULL) {
|
||||
- if (strlcat(line, " ", len) >= len ||
|
||||
- strlcat(line, user_args, len) >= len)
|
||||
- goto toobig;
|
||||
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL|LBUF_ESC_BLANK|LBUF_ESC_QUOTE, " %s", user_args);
|
||||
}
|
||||
}
|
||||
|
||||
- debug_return_str(line);
|
||||
-oom:
|
||||
- free(evstr);
|
||||
+ if (!sudo_lbuf_error(&lbuf))
|
||||
+ debug_return_str(lbuf.buf);
|
||||
+ sudo_lbuf_destroy(&lbuf);
|
||||
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||
debug_return_str(NULL);
|
||||
-toobig:
|
||||
- free(evstr);
|
||||
- free(line);
|
||||
- sudo_warnx(U_("internal error, %s overflow"), __func__);
|
||||
- debug_return_str(NULL);
|
||||
}
|
||||
diff --git a/plugins/sudoers/sudoreplay.c b/plugins/sudoers/sudoreplay.c
|
||||
index a8f7b61..2c58c38 100644
|
||||
--- a/plugins/sudoers/sudoreplay.c
|
||||
+++ b/plugins/sudoers/sudoreplay.c
|
||||
@@ -64,6 +64,7 @@
|
||||
#include "sudo_conf.h"
|
||||
#include "sudo_debug.h"
|
||||
#include "sudo_event.h"
|
||||
+#include "sudo_lbuf.h"
|
||||
#include "sudo_util.h"
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
@@ -364,6 +365,11 @@ main(int argc, char *argv[])
|
||||
if ((li = iolog_parse_loginfo(iolog_dir_fd, iolog_dir)) == NULL)
|
||||
goto done;
|
||||
printf(_("Replaying sudo session: %s"), li->cmd);
|
||||
+ if (li->argv != NULL && li->argv[0] != NULL) {
|
||||
+ for (i = 1; li->argv[i] != NULL; i++)
|
||||
+ printf(" %s", li->argv[i]);
|
||||
+ }
|
||||
+
|
||||
|
||||
/* Setup terminal if appropriate. */
|
||||
if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO))
|
||||
@@ -1292,11 +1298,57 @@ parse_expr(struct search_node_list *head, char *argv[], bool sub_expr)
|
||||
debug_return_int(av - argv);
|
||||
}
|
||||
|
||||
+static char *
|
||||
+expand_command(struct iolog_info *evlog, char **newbuf)
|
||||
+{
|
||||
+ size_t len, bufsize = strlen(evlog->cmd) + 1;
|
||||
+ char *cp, *buf;
|
||||
+ int ac;
|
||||
+ debug_decl(expand_command, SUDO_DEBUG_UTIL);
|
||||
+
|
||||
+ if (evlog->argv == NULL || evlog->argv[0] == NULL || evlog->argv[1] == NULL) {
|
||||
+ /* No arguments, we can use the cmd as-is. */
|
||||
+ *newbuf = NULL;
|
||||
+ debug_return_str(evlog->cmd);
|
||||
+ }
|
||||
+
|
||||
+ /* Skip argv[0], we use evlog->cmd instead. */
|
||||
+ for (ac = 1; evlog->argv[ac] != NULL; ac++)
|
||||
+ bufsize += strlen(evlog->argv[ac]) + 1;
|
||||
+
|
||||
+ if ((buf = malloc(bufsize)) == NULL)
|
||||
+ sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||
+ cp = buf;
|
||||
+
|
||||
+ len = strlcpy(cp, evlog->cmd, bufsize);
|
||||
+ if (len >= bufsize)
|
||||
+ sudo_fatalx(U_("internal error, %s overflow"), __func__);
|
||||
+ cp += len;
|
||||
+ bufsize -= len;
|
||||
+
|
||||
+ for (ac = 1; evlog->argv[ac] != NULL; ac++) {
|
||||
+ if (bufsize < 2)
|
||||
+ sudo_fatalx(U_("internal error, %s overflow"), __func__);
|
||||
+ *cp++ = ' ';
|
||||
+ bufsize--;
|
||||
+
|
||||
+ len = strlcpy(cp, evlog->argv[ac], bufsize);
|
||||
+ if (len >= bufsize)
|
||||
+ sudo_fatalx(U_("internal error, %s overflow"), __func__);
|
||||
+ cp += len;
|
||||
+ bufsize -= len;
|
||||
+ }
|
||||
+
|
||||
+ *newbuf = buf;
|
||||
+ debug_return_str(buf);
|
||||
+}
|
||||
+
|
||||
static bool
|
||||
match_expr(struct search_node_list *head, struct iolog_info *log, bool last_match)
|
||||
{
|
||||
struct search_node *sn;
|
||||
bool res = false, matched = last_match;
|
||||
+ char *tofree;
|
||||
int rc;
|
||||
debug_decl(match_expr, SUDO_DEBUG_UTIL);
|
||||
|
||||
@@ -1330,13 +1382,14 @@ match_expr(struct search_node_list *head, struct iolog_info *log, bool last_matc
|
||||
res = strcmp(sn->u.user, log->user) == 0;
|
||||
break;
|
||||
case ST_PATTERN:
|
||||
- rc = regexec(&sn->u.cmdre, log->cmd, 0, NULL, 0);
|
||||
+ rc = regexec(&sn->u.cmdre, expand_command(log, &tofree), 0, NULL, 0);
|
||||
if (rc && rc != REG_NOMATCH) {
|
||||
char buf[BUFSIZ];
|
||||
regerror(rc, &sn->u.cmdre, buf, sizeof(buf));
|
||||
sudo_fatalx("%s", buf);
|
||||
}
|
||||
res = rc == REG_NOMATCH ? 0 : 1;
|
||||
+ free(tofree);
|
||||
break;
|
||||
case ST_FROMDATE:
|
||||
res = sudo_timespeccmp(&log->tstamp, &sn->u.tstamp, >=);
|
||||
@@ -1357,12 +1410,12 @@ match_expr(struct search_node_list *head, struct iolog_info *log, bool last_matc
|
||||
}
|
||||
|
||||
static int
|
||||
-list_session(char *log_dir, regex_t *re, const char *user, const char *tty)
|
||||
+list_session(struct sudo_lbuf *lbuf, char *log_dir, regex_t *re, const char *user, const char *tty)
|
||||
{
|
||||
char idbuf[7], *idstr, *cp;
|
||||
struct iolog_info *li = NULL;
|
||||
const char *timestr;
|
||||
- int ret = -1;
|
||||
+ int i, ret = -1;
|
||||
debug_decl(list_session, SUDO_DEBUG_UTIL);
|
||||
|
||||
if ((li = iolog_parse_loginfo(-1, log_dir)) == NULL)
|
||||
@@ -1389,18 +1442,67 @@ list_session(char *log_dir, regex_t *re, const char *user, const char *tty)
|
||||
}
|
||||
/* XXX - print lines + cols? */
|
||||
timestr = get_timestr(li->tstamp.tv_sec, 1);
|
||||
- printf("%s : %s : TTY=%s ; CWD=%s ; USER=%s ; ",
|
||||
- timestr ? timestr : "invalid date",
|
||||
- li->user, li->tty, li->cwd, li->runas_user);
|
||||
- if (li->runas_group)
|
||||
- printf("GROUP=%s ; ", li->runas_group);
|
||||
- if (li->host)
|
||||
- printf("HOST=%s ; ", li->host);
|
||||
- printf("TSID=%s ; COMMAND=%s\n", idstr, li->cmd);
|
||||
+ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "%s : %s : ",
|
||||
+ timestr ? timestr : "invalid date", li->user);
|
||||
+ if (li->tty != NULL) {
|
||||
+ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "TTY=%s ; ",
|
||||
+ li->tty);
|
||||
+ }
|
||||
+ if (li->cwd != NULL) {
|
||||
+ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "CWD=%s ; ",
|
||||
+ li->cwd);
|
||||
+ }
|
||||
+ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "USER=%s ; ", li->runas_user);
|
||||
+ if (li->runas_group != NULL) {
|
||||
+ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "GROUP=%s ; ",
|
||||
+ li->runas_group);
|
||||
+ }
|
||||
+ if (li->host != NULL) {
|
||||
+ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "HOST=%s ; ",
|
||||
+ li->host);
|
||||
+ }
|
||||
+ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "TSID=%s ; ", idstr);
|
||||
+
|
||||
+ /*
|
||||
+ * If we have both command and argv from info.json we can escape
|
||||
+ * blanks in the the command and arguments. If all we have is a
|
||||
+ * single string containing both the command and arguments we cannot.
|
||||
+ */
|
||||
+ if (li->argv != NULL) {
|
||||
+ /* Command plus argv from the info.json file. */
|
||||
+ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL|LBUF_ESC_BLANK,
|
||||
+ "COMMAND=%s", li->cmd);
|
||||
+ if (li->argv[0] != NULL) {
|
||||
+ for (i = 1; li->argv[i] != NULL; i++) {
|
||||
+ sudo_lbuf_append(lbuf, " ");
|
||||
+ if (strchr(li->argv[i], ' ') != NULL) {
|
||||
+ /* Wrap args containing spaces in single quotes. */
|
||||
+ sudo_lbuf_append(lbuf, "'");
|
||||
+ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL|LBUF_ESC_QUOTE,
|
||||
+ "%s", li->argv[i]);
|
||||
+ sudo_lbuf_append(lbuf, "'");
|
||||
+ } else {
|
||||
+ /* Escape quotes here too for consistency. */
|
||||
+ sudo_lbuf_append_esc(lbuf,
|
||||
+ LBUF_ESC_CNTRL|LBUF_ESC_BLANK|LBUF_ESC_QUOTE,
|
||||
+ "%s", li->argv[i]);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* Single string from the legacy info file. */
|
||||
+ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "COMMAND=%s",
|
||||
+ li->cmd);
|
||||
+ }
|
||||
|
||||
- ret = 0;
|
||||
+ if (!sudo_lbuf_error(lbuf)) {
|
||||
+ puts(lbuf->buf);
|
||||
+ ret = 0;
|
||||
+ }
|
||||
|
||||
done:
|
||||
+ lbuf->error = 0;
|
||||
+ lbuf->len = 0;
|
||||
iolog_free_loginfo(li);
|
||||
debug_return_int(ret);
|
||||
}
|
||||
@@ -1420,6 +1522,7 @@ find_sessions(const char *dir, regex_t *re, const char *user, const char *tty)
|
||||
DIR *d;
|
||||
struct dirent *dp;
|
||||
struct stat sb;
|
||||
+ struct sudo_lbuf lbuf;
|
||||
size_t sdlen, sessions_len = 0, sessions_size = 0;
|
||||
unsigned int i;
|
||||
int len;
|
||||
@@ -1431,6 +1534,8 @@ find_sessions(const char *dir, regex_t *re, const char *user, const char *tty)
|
||||
#endif
|
||||
debug_decl(find_sessions, SUDO_DEBUG_UTIL);
|
||||
|
||||
+ sudo_lbuf_init(&lbuf, NULL, 0, NULL, 0);
|
||||
+
|
||||
d = opendir(dir);
|
||||
if (d == NULL)
|
||||
sudo_fatal(U_("unable to open %s"), dir);
|
||||
@@ -1491,7 +1596,7 @@ find_sessions(const char *dir, regex_t *re, const char *user, const char *tty)
|
||||
/* Check for dir with a log file. */
|
||||
if (lstat(pathbuf, &sb) == 0 && S_ISREG(sb.st_mode)) {
|
||||
pathbuf[sdlen + len - 4] = '\0';
|
||||
- list_session(pathbuf, re, user, tty);
|
||||
+ list_session(&lbuf, pathbuf, re, user, tty);
|
||||
} else {
|
||||
/* Strip off "/log" and recurse if a non-log dir. */
|
||||
pathbuf[sdlen + len - 4] = '\0';
|
||||
@@ -1502,6 +1607,7 @@ find_sessions(const char *dir, regex_t *re, const char *user, const char *tty)
|
||||
}
|
||||
free(sessions);
|
||||
}
|
||||
+ sudo_lbuf_destroy(&lbuf);
|
||||
|
||||
debug_return_int(0);
|
||||
}
|
||||
--
|
||||
2.27.0
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
Name: sudo
|
||||
Version: 1.9.2
|
||||
Release: 10
|
||||
Release: 11
|
||||
Summary: Allows restricted root access for specified users
|
||||
License: ISC
|
||||
URL: http://www.courtesan.com/sudo/
|
||||
@ -34,6 +34,7 @@ Patch20: backport-Fix-a-potential-use-after-free-bug-with-cvtsudoers-f.patch
|
||||
Patch21: backport-Fix-memory-leak-of-pass-in-converse.patch
|
||||
Patch22: backport-sudo_passwd_cleanup-Set-auth-data-to-NULL-after-free.patch
|
||||
Patch23: backport-CVE-2023-22809.patch
|
||||
Patch24: backport-CVE-2023-28486_CVE-2023-28487.patch
|
||||
|
||||
Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
Requires: pam
|
||||
@ -174,6 +175,9 @@ install -p -c -m 0644 %{SOURCE3} $RPM_BUILD_ROOT/etc/pam.d/sudo-i
|
||||
%exclude %{_pkgdocdir}/ChangeLog
|
||||
|
||||
%changelog
|
||||
* Tue Mar 28 2023 wangcheng <wangcheng156@huawei.com> - 1.9.2-11
|
||||
- Fix CVE-2023-28486 and CVE-2023-28487
|
||||
|
||||
* Mon Jan 30 2023 wangyu <wangyu283@huawei.com> - 1.9.2-10
|
||||
- Fix CVE-2023-22809.
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user