diff --git a/backport-CVE-2023-27320.patch b/backport-CVE-2023-27320.patch deleted file mode 100644 index 6f55e01233ad56d68344b5da7995b86d3dba1817..0000000000000000000000000000000000000000 --- a/backport-CVE-2023-27320.patch +++ /dev/null @@ -1,38 +0,0 @@ -diff --git a/plugins/sudoers/match_command.c b/plugins/sudoers/match_command.c -index 37d376d..bda7082 100644 ---- a/plugins/sudoers/match_command.c -+++ b/plugins/sudoers/match_command.c -@@ -818,12 +818,16 @@ command_matches(const char *sudoers_cmnd, const char *sudoers_args, - /* Rule-specific runchroot, reset user_cmnd and user_stat. */ - int status; - -+ /* Save old user_cmnd first, set_cmnd_path() will free it. */ - saved_user_cmnd = user_cmnd; -+ user_cmnd = NULL; - if (user_stat != NULL) - saved_user_stat = *user_stat; - status = set_cmnd_path(runchroot); -- if (status != FOUND) -+ if (status != FOUND) { -+ user_cmnd = saved_user_cmnd; - saved_user_cmnd = NULL; -+ } - if (info != NULL) - info->status = status; - } -diff --git a/plugins/sudoers/visudo.c b/plugins/sudoers/visudo.c -index 3f43382..ec8deab 100644 ---- a/plugins/sudoers/visudo.c -+++ b/plugins/sudoers/visudo.c -@@ -260,7 +260,9 @@ main(int argc, char *argv[]) - } - - /* Mock up a fake sudo_user struct. */ -- user_cmnd = user_base = (char *)""; -+ user_cmnd = user_base = strdup("true"); -+ if (user_cmnd == NULL) -+ sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); - if (geteuid() == 0) { - const char *user = getenv("SUDO_USER"); - if (user != NULL && *user != '\0') - diff --git a/backport-CVE-2023-28486_CVE-2023-28487.patch b/backport-CVE-2023-28486_CVE-2023-28487.patch deleted file mode 100644 index e3ea4cb793a4285aa29948f269b31775bab92382..0000000000000000000000000000000000000000 --- a/backport-CVE-2023-28486_CVE-2023-28487.patch +++ /dev/null @@ -1,970 +0,0 @@ -From 334daf92b31b79ce68ed75e2ee14fca265f029ca Mon Sep 17 00:00:00 2001 -From: "Todd C. Miller" -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). ---- - docs/sudoers.man.in | 44 ++++++-- - docs/sudoers.mdoc.in | 38 +++++-- - docs/sudoreplay.man.in | 9 ++ - docs/sudoreplay.mdoc.in | 10 ++ - include/sudo_lbuf.h | 7 ++ - lib/eventlog/eventlog.c | 210 ++++++++++------------------------- - lib/iolog/iolog_json.c | 39 ------- - lib/util/lbuf.c | 106 ++++++++++++++++++ - lib/util/util.exp.in | 1 + - plugins/sudoers/sudoreplay.c | 144 ++++++++++++++++++++---- - 10 files changed, 383 insertions(+), 225 deletions(-) - -diff --git a/docs/sudoers.man.in b/docs/sudoers.man.in -index 787591111..be9dc327e 100644 ---- a/docs/sudoers.man.in -+++ b/docs/sudoers.man.in -@@ -5877,14 +5877,31 @@ can log events via - syslog(3), - to a local log file, or both. - The log format is almost identical in both cases. -+Any control characters present in the log data are formatted in octal -+with a leading -+\(oq#\(cq -+character. -+For example, a horizontal tab is stored as -+\(oq#011\(cq -+and an embedded carriage return is stored as -+\(oq#015\(cq. -+In addition, space characters in the command path are stored as -+\(oq#040\(cq. -+Command line arguments that contain spaces are enclosed in single quotes -+(''). -+This makes it possible to distinguish multiple command line arguments -+from a single argument that contains spaces. -+Literal single quotes and backslash characters -+(\(oq\e\(cq) -+in command line arguments are escaped with a backslash. - .SS "Accepted command log entries" - Commands that sudo runs are logged using the following format (split - into multiple lines for readability): - .nf - .sp - .RS 4n --date hostname progname: username : TTY=ttyname ; PWD=cwd ; \e -- USER=runasuser ; GROUP=runasgroup ; TSID=logid ; \e -+date hostname progname: username : TTY=ttyname ; CHROOT=chroot ; \e -+ PWD=cwd ; USER=runasuser ; GROUP=runasgroup ; TSID=logid ; \e - ENV=env_vars COMMAND=command - .RE - .fi -@@ -5933,6 +5950,9 @@ was run on, or - \(lqunknown\(rq - if there was no terminal present. - .TP 14n -+chroot -+The root directory that the command was run in, if one was specified. -+.TP 14n - cwd - The current working directory that - \fBsudo\fR -@@ -5957,7 +5977,7 @@ A list of environment variables specified on the command line, - if specified. - .TP 14n - command --The actual command that was executed. -+The actual command that was executed, including any command line arguments. - .PP - Messages are logged using the locale specified by - \fIsudoers_locale\fR, -@@ -6195,17 +6215,21 @@ with a few important differences: - 1.\& - The - \fIprogname\fR --and --\fIhostname\fR --fields are not present. -+field is not present. - .TP 5n - 2.\& --If the --\fIlog_year\fR --option is enabled, --the date will also include the year. -+The -+\fIhostname\fR -+is only logged if the -+\fIlog_host\fR -+option is enabled. - .TP 5n - 3.\& -+The date does not include the year unless the -+\fIlog_year\fR -+option is enabled. -+.TP 5n -+4.\& - Lines that are longer than - \fIloglinelen\fR - characters (80 by default) are word-wrapped and continued on the -diff --git a/docs/sudoers.mdoc.in b/docs/sudoers.mdoc.in -index c72bc660d..92edacb9d 100644 ---- a/docs/sudoers.mdoc.in -+++ b/docs/sudoers.mdoc.in -@@ -5503,12 +5503,29 @@ can log events via - .Xr syslog 3 , - to a local log file, or both. - The log format is almost identical in both cases. -+Any control characters present in the log data are formatted in octal -+with a leading -+.Ql # -+character. -+For example, a horizontal tab is stored as -+.Ql #011 -+and an embedded carriage return is stored as -+.Ql #015 . -+In addition, space characters in the command path are stored as -+.Ql #040 . -+Command line arguments that contain spaces are enclosed in single quotes -+.Pq '' . -+This makes it possible to distinguish multiple command line arguments -+from a single argument that contains spaces. -+Literal single quotes and backslash characters -+.Pq Ql \e -+in command line arguments are escaped with a backslash. - .Ss Accepted command log entries - Commands that sudo runs are logged using the following format (split - into multiple lines for readability): - .Bd -literal -offset 4n --date hostname progname: username : TTY=ttyname ; PWD=cwd ; \e -- USER=runasuser ; GROUP=runasgroup ; TSID=logid ; \e -+date hostname progname: username : TTY=ttyname ; CHROOT=chroot ; \e -+ PWD=cwd ; USER=runasuser ; GROUP=runasgroup ; TSID=logid ; \e - ENV=env_vars COMMAND=command - .Ed - .Pp -@@ -5551,6 +5568,8 @@ or - was run on, or - .Dq unknown - if there was no terminal present. -+.It chroot -+The root directory that the command was run in, if one was specified. - .It cwd - The current working directory that - .Nm sudo -@@ -5570,7 +5589,7 @@ option is enabled. - A list of environment variables specified on the command line, - if specified. - .It command --The actual command that was executed. -+The actual command that was executed, including any command line arguments. - .El - .Pp - Messages are logged using the locale specified by -@@ -5794,14 +5813,17 @@ with a few important differences: - .It - The - .Em progname --and -+field is not present. -+.It -+The - .Em hostname --fields are not present. -+is only logged if the -+.Em log_host -+option is enabled. - .It --If the -+The date does not include the year unless the - .Em log_year --option is enabled, --the date will also include the year. -+option is enabled. - .It - Lines that are longer than - .Em loglinelen -diff --git a/docs/sudoreplay.man.in b/docs/sudoreplay.man.in -index f1fed2d42..73dbd52f9 100644 ---- a/docs/sudoreplay.man.in -+++ b/docs/sudoreplay.man.in -@@ -170,6 +170,15 @@ In this mode, - will list available sessions in a format similar to the - \fBsudo\fR - log file format, sorted by file name (or sequence number). -+Any control characters present in the log data are formated in octal -+with a leading -+\(oq#\(cq -+character. -+For example, a horizontal tab is displayed as -+\(oq#011\(cq -+and an embedded carriage return is displayed as -+\(oq#015\(cq. -+.sp - If a - \fIsearch expression\fR - is specified, it will be used to restrict the IDs that are displayed. -diff --git a/docs/sudoreplay.mdoc.in b/docs/sudoreplay.mdoc.in -index 940a41462..005cf1f7f 100644 ---- a/docs/sudoreplay.mdoc.in -+++ b/docs/sudoreplay.mdoc.in -@@ -162,6 +162,16 @@ In this mode, - will list available sessions in a format similar to the - .Nm sudo - log file format, sorted by file name (or sequence number). -+Any control characters present in the log data are formatted in octal -+with a leading -+.Ql # -+character. -+For example, a horizontal tab is displayed as -+.Ql #011 -+and an embedded carriage return is displayed as -+.Ql #015 . -+Space characters in the command name and arguments are also formatted in octal. -+.Pp - If a - .Ar search expression - is specified, it will be used to restrict the IDs that are displayed. -diff --git a/include/sudo_lbuf.h b/include/sudo_lbuf.h -index be0a04f73..29090cb8d 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 -+ - sudo_dso_public void sudo_lbuf_init_v1(struct sudo_lbuf *lbuf, sudo_lbuf_output_t output, int indent, const char *continuation, int cols); - sudo_dso_public void sudo_lbuf_destroy_v1(struct sudo_lbuf *lbuf); - sudo_dso_public bool sudo_lbuf_append_v1(struct sudo_lbuf *lbuf, const char *fmt, ...) sudo_printflike(2, 3); -+sudo_dso_public bool sudo_lbuf_append_esc_v1(struct sudo_lbuf *lbuf, int flags, const char *fmt, ...) sudo_printflike(3, 4); - sudo_dso_public bool sudo_lbuf_append_quoted_v1(struct sudo_lbuf *lbuf, const char *set, const char *fmt, ...) sudo_printflike(3, 4); - sudo_dso_public void sudo_lbuf_print_v1(struct sudo_lbuf *lbuf); - sudo_dso_public bool sudo_lbuf_error_v1(struct sudo_lbuf *lbuf); -@@ -47,6 +53,7 @@ sudo_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/eventlog/eventlog.c b/lib/eventlog/eventlog.c -index c0183d3d2..e5dae626a 100644 ---- a/lib/eventlog/eventlog.c -+++ b/lib/eventlog/eventlog.c -@@ -1,7 +1,7 @@ - /* - * SPDX-License-Identifier: ISC - * -- * Copyright (c) 1994-1996, 1998-2021 Todd C. Miller -+ * Copyright (c) 1994-1996, 1998-2023 Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above -@@ -51,24 +51,13 @@ - #include "sudo_compat.h" - #include "sudo_debug.h" - #include "sudo_eventlog.h" -+#include "sudo_lbuf.h" - #include "sudo_fatal.h" - #include "sudo_gettext.h" - #include "sudo_json.h" - #include "sudo_queue.h" - #include "sudo_util.h" - --#define LL_HOST_STR "HOST=" --#define LL_TTY_STR "TTY=" --#define LL_CHROOT_STR "CHROOT=" --#define LL_CWD_STR "PWD=" --#define LL_USER_STR "USER=" --#define LL_GROUP_STR "GROUP=" --#define LL_ENV_STR "ENV=" --#define LL_CMND_STR "COMMAND=" --#define LL_TSID_STR "TSID=" --#define LL_EXIT_STR "EXIT=" --#define LL_SIGNAL_STR "SIGNAL=" -- - #define IS_SESSID(s) ( \ - isalnum((unsigned char)(s)[0]) && isalnum((unsigned char)(s)[1]) && \ - (s)[2] == '/' && \ -@@ -93,26 +82,28 @@ new_logline(int event_type, int flags, struct eventlog_args *args, - const struct eventlog *evlog) - { - const struct eventlog_config *evl_conf = eventlog_getconf(); -- char *line = NULL, *evstr = NULL; - const char *iolog_file; - const char *tty, *tsid = NULL; - char exit_str[(((sizeof(int) * 8) + 2) / 3) + 2]; - char sessid[7], offsetstr[64] = ""; -- 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); -+ - if (ISSET(flags, EVLOG_RAW) || evlog == NULL) { - if (args->reason != NULL) { - if (args->errstr != NULL) { -- if (asprintf(&line, "%s: %s", args->reason, args->errstr) == -1) -- goto oom; -+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s: %s", -+ args->reason, args->errstr); - } else { -- if ((line = strdup(args->reason)) == NULL) -- goto oom; -+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s", args->reason); - } -+ if (sudo_lbuf_error(&lbuf)) -+ goto oom; - } -- debug_return_str(line); -+ debug_return_str(lbuf.buf); - } - - /* A TSID may be a sudoers-style session ID or a free-form string. */ -@@ -150,169 +141,90 @@ new_logline(int event_type, int flags, struct eventlog_args *args, - } - - /* -- * 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 (args->reason != NULL) -- len += strlen(args->reason) + 3; -- if (args->errstr != NULL) -- len += strlen(args->errstr) + 3; -- if (evlog->submithost != NULL && !evl_conf->omit_hostname) -- len += sizeof(LL_HOST_STR) + 2 + strlen(evlog->submithost); -- if (tty != NULL) -- len += sizeof(LL_TTY_STR) + 2 + strlen(tty); -- if (evlog->runchroot != NULL) -- len += sizeof(LL_CHROOT_STR) + 2 + strlen(evlog->runchroot); -- if (evlog->runcwd != NULL) -- len += sizeof(LL_CWD_STR) + 2 + strlen(evlog->runcwd); -- if (evlog->runuser != NULL) -- len += sizeof(LL_USER_STR) + 2 + strlen(evlog->runuser); -- if (evlog->rungroup != NULL) -- len += sizeof(LL_GROUP_STR) + 2 + strlen(evlog->rungroup); -- if (tsid != NULL) { -- len += sizeof(LL_TSID_STR) + 2 + strlen(tsid) + strlen(offsetstr); -- } -- if (evlog->env_add != NULL) { -- size_t evlen = 0; -- char * const *ep; -- -- for (ep = evlog->env_add; *ep != NULL; ep++) -- evlen += strlen(*ep) + 1; -- if (evlen != 0) { -- if ((evstr = malloc(evlen)) == NULL) -- goto oom; -- ep = evlog->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 (evlog->command != NULL) { -- len += sizeof(LL_CMND_STR) - 1 + strlen(evlog->command); -- if (evlog->argv != NULL && evlog->argv[0] != NULL) { -- for (i = 1; evlog->argv[i] != NULL; i++) -- len += strlen(evlog->argv[i]) + 1; -- } -- if (event_type == EVLOG_EXIT) { -- if (evlog->signal_name != NULL) -- len += sizeof(LL_SIGNAL_STR) + 2 + strlen(evlog->signal_name); -- if (evlog->exit_value != -1) { -- (void)snprintf(exit_str, sizeof(exit_str), "%d", evlog->exit_value); -- len += sizeof(LL_EXIT_STR) + 2 + strlen(exit_str); -- } -- } -- } -- -- /* -- * Allocate and build up the line. -- */ -- if ((line = malloc(++len)) == NULL) -- goto oom; -- line[0] = '\0'; -- - if (args->reason != NULL) { -- if (strlcat(line, args->reason, len) >= len || -- strlcat(line, args->errstr ? " : " : " ; ", len) >= len) -- goto toobig; -+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s%s", args->reason, -+ args->errstr ? " : " : " ; "); - } - if (args->errstr != NULL) { -- if (strlcat(line, args->errstr, len) >= len || -- strlcat(line, " ; ", len) >= len) -- goto toobig; -+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "%s ; ", args->errstr); - } - if (evlog->submithost != NULL && !evl_conf->omit_hostname) { -- if (strlcat(line, LL_HOST_STR, len) >= len || -- strlcat(line, evlog->submithost, len) >= len || -- strlcat(line, " ; ", len) >= len) -- goto toobig; -+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "HOST=%s ; ", -+ evlog->submithost); - } - if (tty != NULL) { -- if (strlcat(line, LL_TTY_STR, len) >= len || -- strlcat(line, tty, len) >= len || -- strlcat(line, " ; ", len) >= len) -- goto toobig; -+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "TTY=%s ; ", tty); - } - if (evlog->runchroot != NULL) { -- if (strlcat(line, LL_CHROOT_STR, len) >= len || -- strlcat(line, evlog->runchroot, len) >= len || -- strlcat(line, " ; ", len) >= len) -- goto toobig; -+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "CHROOT=%s ; ", -+ evlog->runchroot); - } - if (evlog->runcwd != NULL) { -- if (strlcat(line, LL_CWD_STR, len) >= len || -- strlcat(line, evlog->runcwd, len) >= len || -- strlcat(line, " ; ", len) >= len) -- goto toobig; -+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "PWD=%s ; ", -+ evlog->runcwd); - } - if (evlog->runuser != NULL) { -- if (strlcat(line, LL_USER_STR, len) >= len || -- strlcat(line, evlog->runuser, len) >= len || -- strlcat(line, " ; ", len) >= len) -- goto toobig; -+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "USER=%s ; ", -+ evlog->runuser); - } - if (evlog->rungroup != NULL) { -- if (strlcat(line, LL_GROUP_STR, len) >= len || -- strlcat(line, evlog->rungroup, len) >= len || -- strlcat(line, " ; ", len) >= len) -- goto toobig; -+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "GROUP=%s ; ", -+ evlog->rungroup); - } - if (tsid != NULL) { -- if (strlcat(line, LL_TSID_STR, len) >= len || -- strlcat(line, tsid, len) >= len || -- strlcat(line, offsetstr, 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, "TSID=%s%s ; ", tsid, -+ offsetstr); -+ } -+ if (evlog->env_add != NULL && evlog->env_add[0] != NULL) { -+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, "ENV=%s", -+ evlog->env_add[0]); -+ for (i = 1; evlog->env_add[i] != NULL; i++) { -+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, " %s", -+ evlog->env_add[i]); -+ } - } - if (evlog->command != NULL) { -- if (strlcat(line, LL_CMND_STR, len) >= len) -- goto toobig; -- if (strlcat(line, evlog->command, len) >= len) -- goto toobig; -+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL|LBUF_ESC_BLANK, -+ "COMMAND=%s", evlog->command); - if (evlog->argv != NULL && evlog->argv[0] != NULL) { - for (i = 1; evlog->argv[i] != NULL; i++) { -- if (strlcat(line, " ", len) >= len || -- strlcat(line, evlog->argv[i], len) >= len) -- goto toobig; -+ sudo_lbuf_append(&lbuf, " "); -+ if (strchr(evlog->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", evlog->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", evlog->argv[i]); -+ } - } - } - if (event_type == EVLOG_EXIT) { - if (evlog->signal_name != NULL) { -- if (strlcat(line, " ; ", len) >= len || -- strlcat(line, LL_SIGNAL_STR, len) >= len || -- strlcat(line, evlog->signal_name, len) >= len) -- goto toobig; -+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, " ; SIGNAL=%s", -+ evlog->signal_name); - } - if (evlog->exit_value != -1) { -- if (strlcat(line, " ; ", len) >= len || -- strlcat(line, LL_EXIT_STR, len) >= len || -- strlcat(line, exit_str, len) >= len) -- goto toobig; -+ (void)snprintf(exit_str, sizeof(exit_str), "%d", -+ evlog->exit_value); -+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, " ; EXIT=%s", -+ exit_str); - } - } - } -- -- debug_return_str(line); -+ if (!sudo_lbuf_error(&lbuf)) -+ debug_return_str(lbuf.buf); - 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 void -diff --git a/lib/iolog/iolog_json.c b/lib/iolog/iolog_json.c -index 5ea338e5d..6f384ea59 100644 ---- a/lib/iolog/iolog_json.c -+++ b/lib/iolog/iolog_json.c -@@ -551,45 +551,6 @@ iolog_parse_json_object(struct json_object *object, struct eventlog *evlog) - } - } - -- /* Merge cmd and argv as sudoreplay expects. */ -- if (evlog->command != NULL && evlog->argv != NULL && evlog->argv[0] != NULL) { -- size_t len, bufsize = strlen(evlog->command) + 1; -- char *cp, *buf; -- int ac; -- -- /* Skip argv[0], we use evlog->command instead. */ -- for (ac = 1; evlog->argv[ac] != NULL; ac++) -- bufsize += strlen(evlog->argv[ac]) + 1; -- -- if ((buf = malloc(bufsize)) == NULL) { -- sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); -- goto done; -- } -- cp = buf; -- -- len = strlcpy(cp, evlog->command, 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; -- } -- -- free(evlog->command); -- evlog->command = buf; -- } -- - ret = true; - - done: -diff --git a/lib/util/lbuf.c b/lib/util/lbuf.c -index 101982065..72bcac26f 100644 ---- a/lib/util/lbuf.c -+++ b/lib/util/lbuf.c -@@ -94,6 +94,112 @@ sudo_lbuf_expand(struct sudo_lbuf *lbuf, unsigned 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; -+ FALLTHROUGH; -+ case 4: -+ buf[3] = (ch & 7) + '0'; -+ ch >>= 3; -+ FALLTHROUGH; -+ 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 554904c5f..6c8130a02 100644 ---- a/lib/util/util.exp.in -+++ b/lib/util/util.exp.in -@@ -98,6 +98,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/plugins/sudoers/sudoreplay.c b/plugins/sudoers/sudoreplay.c -index 750dfeed9..43ff23999 100644 ---- a/plugins/sudoers/sudoreplay.c -+++ b/plugins/sudoers/sudoreplay.c -@@ -62,6 +62,7 @@ - #include "sudo_debug.h" - #include "sudo_event.h" - #include "sudo_eventlog.h" -+#include "sudo_lbuf.h" - #include "sudo_fatal.h" - #include "sudo_gettext.h" - #include "sudo_iolog.h" -@@ -373,6 +374,10 @@ main(int argc, char *argv[]) - if ((evlog = iolog_parse_loginfo(iolog_dir_fd, iolog_dir)) == NULL) - goto done; - printf(_("Replaying sudo session: %s"), evlog->command); -+ if (evlog->argv != NULL && evlog->argv[0] != NULL) { -+ for (i = 1; evlog->argv[i] != NULL; i++) -+ printf(" %s", evlog->argv[i]); -+ } - - /* Setup terminal if appropriate. */ - if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO)) -@@ -1315,11 +1320,57 @@ parse_expr(struct search_node_list *head, char *argv[], bool sub_expr) - debug_return_int(av - argv); - } - -+static char * -+expand_command(struct eventlog *evlog, char **newbuf) -+{ -+ size_t len, bufsize = strlen(evlog->command) + 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 command as-is. */ -+ *newbuf = NULL; -+ debug_return_str(evlog->command); -+ } -+ -+ /* Skip argv[0], we use evlog->command 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->command, 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 eventlog *evlog, bool last_match) - { - struct search_node *sn; - bool res = false, matched = last_match; -+ char *tofree; - int rc; - debug_decl(match_expr, SUDO_DEBUG_UTIL); - -@@ -1353,13 +1404,15 @@ match_expr(struct search_node_list *head, struct eventlog *evlog, bool last_matc - res = strcmp(sn->u.user, evlog->submituser) == 0; - break; - case ST_PATTERN: -- rc = regexec(&sn->u.cmdre, evlog->command, 0, NULL, 0); -+ rc = regexec(&sn->u.cmdre, expand_command(evlog, &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(&evlog->submit_time, &sn->u.tstamp, >=); -@@ -1380,12 +1433,13 @@ match_expr(struct search_node_list *head, struct eventlog *evlog, 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 eventlog *evlog = NULL; - const char *timestr; -- int ret = -1; -+ int i, ret = -1; - debug_decl(list_session, SUDO_DEBUG_UTIL); - - if ((evlog = iolog_parse_loginfo(-1, log_dir)) == NULL) -@@ -1417,23 +1471,71 @@ list_session(char *log_dir, regex_t *re, const char *user, const char *tty) - } - /* XXX - print lines + cols? */ - timestr = get_timestr(evlog->submit_time.tv_sec, 1); -- printf("%s : %s : ", timestr ? timestr : "invalid date", evlog->submituser); -- if (evlog->submithost != NULL) -- printf("HOST=%s ; ", evlog->submithost); -- if (evlog->ttyname != NULL) -- printf("TTY=%s ; ", evlog->ttyname); -- if (evlog->runchroot != NULL) -- printf("CHROOT=%s ; ", evlog->runchroot); -- if (evlog->runcwd != NULL || evlog->cwd != NULL) -- printf("CWD=%s ; ", evlog->runcwd ? evlog->runcwd : evlog->cwd); -- printf("USER=%s ; ", evlog->runuser); -- if (evlog->rungroup != NULL) -- printf("GROUP=%s ; ", evlog->rungroup); -- printf("TSID=%s ; COMMAND=%s\n", idstr, evlog->command); -- -- ret = 0; -+ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "%s : %s : ", -+ timestr ? timestr : "invalid date", evlog->submituser); -+ if (evlog->submithost != NULL) { -+ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "HOST=%s ; ", -+ evlog->submithost); -+ } -+ if (evlog->ttyname != NULL) { -+ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "TTY=%s ; ", -+ evlog->ttyname); -+ } -+ if (evlog->runchroot != NULL) { -+ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "CHROOT=%s ; ", -+ evlog->runchroot); -+ } -+ if (evlog->runcwd != NULL || evlog->cwd != NULL) { -+ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "CWD=%s ; ", -+ evlog->runcwd ? evlog->runcwd : evlog->cwd); -+ } -+ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "USER=%s ; ", evlog->runuser); -+ if (evlog->rungroup != NULL) { -+ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "GROUP=%s ; ", -+ evlog->rungroup); -+ } -+ 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 (evlog->argv != NULL) { -+ /* Command plus argv from the info.json file. */ -+ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL|LBUF_ESC_BLANK, -+ "COMMAND=%s", evlog->command); -+ if (evlog->argv[0] != NULL) { -+ for (i = 1; evlog->argv[i] != NULL; i++) { -+ sudo_lbuf_append(lbuf, " "); -+ if (strchr(evlog->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", evlog->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", evlog->argv[i]); -+ } -+ } -+ } -+ } else { -+ /* Single string from the legacy info file. */ -+ sudo_lbuf_append_esc(lbuf, LBUF_ESC_CNTRL, "COMMAND=%s", -+ evlog->command); -+ } -+ -+ if (!sudo_lbuf_error(lbuf)) { -+ puts(lbuf->buf); -+ ret = 0; -+ } - - done: -+ lbuf->error = 0; -+ lbuf->len = 0; - eventlog_free(evlog); - debug_return_int(ret); - } -@@ -1453,6 +1555,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; -@@ -1464,6 +1567,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); -@@ -1524,7 +1629,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'; -@@ -1535,6 +1640,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); - } diff --git a/sudo-1.9.12p2.tar.gz b/sudo-1.9.14p1.tar.gz similarity index 39% rename from sudo-1.9.12p2.tar.gz rename to sudo-1.9.14p1.tar.gz index 860d2aff75fcc6106e20bf757e8f60d7678a1a2d..3a84c7d00ceef52a95393eca27369a50fb42f034 100644 Binary files a/sudo-1.9.12p2.tar.gz and b/sudo-1.9.14p1.tar.gz differ diff --git a/sudo.spec b/sudo.spec index 8258d197e9d8ac18ad17baf5f4eac60924cbac50..369d2ad7eb22723c72b13b844b77398eecd86dfe 100644 --- a/sudo.spec +++ b/sudo.spec @@ -1,6 +1,6 @@ Name: sudo -Version: 1.9.12p2 -Release: 5 +Version: 1.9.14p1 +Release: 1 Summary: Allows restricted root access for specified users License: ISC URL: https://www.sudo.ws @@ -10,9 +10,7 @@ Source1: sudoers Source2: sudo Source3: sudo-i -Patch0: backport-CVE-2023-27320.patch -Patch1: backport-CVE-2023-28486_CVE-2023-28487.patch -Patch2: Fix-compilation-error-on-sw64-arch.patch +Patch0: Fix-compilation-error-on-sw64-arch.patch Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Requires: pam @@ -157,6 +155,9 @@ chrpath -d $RPM_BUILD_ROOT/usr/libexec/sudo/* %exclude %{_pkgdocdir}/ChangeLog %changelog +* Wed Jul 19 2023 zhoushuiqing - 1.9.14p1-1 +- Upgrade to 1.9.14p1 + * Wed Apr 12 2023 wangyu - 1.9.12p2-5 - Fix compilation error on sw64 arch.