Fix CVE-2023-28486 and CVE-2023-28487
(cherry picked from commit 9f6be52b9729bb23d8cbc8710757172362024f9a)
This commit is contained in:
parent
4190697938
commit
0e7140821b
748
backport-CVE-2023-28486_CVE-2023-28487.patch
Normal file
748
backport-CVE-2023-28486_CVE-2023-28487.patch
Normal file
@ -0,0 +1,748 @@
|
|||||||
|
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/eventlog/eventlog.c | 210 +++++++++++------------------------
|
||||||
|
lib/iolog/iolog_json.c | 29 -----
|
||||||
|
lib/util/lbuf.c | 106 ++++++++++++++++++
|
||||||
|
lib/util/util.exp.in | 1 +
|
||||||
|
plugins/sudoers/sudoreplay.c | 137 ++++++++++++++++++++---
|
||||||
|
6 files changed, 300 insertions(+), 190 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/include/sudo_lbuf.h b/include/sudo_lbuf.h
|
||||||
|
index c0a20c5..f52d59c 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, ...) __printflike(2, 3);
|
||||||
|
+sudo_dso_public bool sudo_lbuf_append_esc_v1(struct sudo_lbuf *lbuf, int flags, const char *fmt, ...) __printflike(3, 4);
|
||||||
|
sudo_dso_public bool sudo_lbuf_append_quoted_v1(struct sudo_lbuf *lbuf, const char *set, const char *fmt, ...) __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 314140c..a56b1d0 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 <Todd.Miller@sudo.ws>
|
||||||
|
+ * Copyright (c) 1994-1996, 1998-2023 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||||
|
*
|
||||||
|
* 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] == '/' && \
|
||||||
|
@@ -96,26 +85,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. */
|
||||||
|
@@ -153,165 +144,88 @@ new_logline(int event_type, int flags, struct eventlog_args *args,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
- * Compute line length
|
||||||
|
- */
|
||||||
|
- 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) {
|
||||||
|
- for (i = 1; evlog->argv[i] != NULL; i++)
|
||||||
|
- len += strlen(evlog->argv[i]) + 1;
|
||||||
|
- }
|
||||||
|
- if (event_type == EVLOG_EXIT) {
|
||||||
|
- if (args->signal_name != NULL)
|
||||||
|
- len += sizeof(LL_SIGNAL_STR) + 2 + strlen(args->signal_name);
|
||||||
|
- (void)snprintf(exit_str, sizeof(exit_str), "%d", args->exit_value);
|
||||||
|
- len += sizeof(LL_EXIT_STR) + 2 + strlen(exit_str);
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /*
|
||||||
|
- * 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 (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;
|
||||||
|
- if (evlog->argv != NULL) {
|
||||||
|
+ 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 (args->signal_name != NULL) {
|
||||||
|
- if (strlcat(line, " ; ", len) >= len ||
|
||||||
|
- strlcat(line, LL_SIGNAL_STR, len) >= len ||
|
||||||
|
- strlcat(line, args->signal_name, len) >= len)
|
||||||
|
- goto toobig;
|
||||||
|
+ sudo_lbuf_append_esc(&lbuf, LBUF_ESC_CNTRL, " ; SIGNAL=%s",
|
||||||
|
+ args->signal_name);
|
||||||
|
}
|
||||||
|
- 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",
|
||||||
|
+ args->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 a27fe4d..408bc31 100644
|
||||||
|
--- a/lib/iolog/iolog_json.c
|
||||||
|
+++ b/lib/iolog/iolog_json.c
|
||||||
|
@@ -489,35 +489,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 = strlen(evlog->command) + 1;
|
||||||
|
- char *newcmd;
|
||||||
|
- int ac;
|
||||||
|
-
|
||||||
|
- /* Skip argv[0], we use evlog->command instead. */
|
||||||
|
- for (ac = 1; evlog->argv[ac] != NULL; ac++)
|
||||||
|
- len += strlen(evlog->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, evlog->command, len) >= len)
|
||||||
|
- sudo_fatalx(U_("internal error, %s overflow"), __func__);
|
||||||
|
- for (ac = 1; evlog->argv[ac] != NULL; ac++) {
|
||||||
|
- if (strlcat(newcmd, " ", len) >= len)
|
||||||
|
- sudo_fatalx(U_("internal error, %s overflow"), __func__);
|
||||||
|
- if (strlcat(newcmd, evlog->argv[ac], len) >= len)
|
||||||
|
- sudo_fatalx(U_("internal error, %s overflow"), __func__);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- free(evlog->command);
|
||||||
|
- evlog->command = 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;
|
||||||
|
+ 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 5b760fa..c3829ec 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 f32d44e..7914135 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))
|
||||||
|
@@ -1312,11 +1317,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);
|
||||||
|
|
||||||
|
@@ -1350,13 +1401,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, >=);
|
||||||
|
@@ -1377,12 +1430,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)
|
||||||
|
@@ -1409,18 +1463,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 : TTY=%s ; CWD=%s ; USER=%s ; ",
|
||||||
|
- timestr ? timestr : "invalid date",
|
||||||
|
- evlog->submituser, evlog->ttyname, evlog->cwd, evlog->runuser);
|
||||||
|
- if (evlog->rungroup)
|
||||||
|
- printf("GROUP=%s ; ", evlog->rungroup);
|
||||||
|
- if (evlog->submithost)
|
||||||
|
- printf("HOST=%s ; ", evlog->submithost);
|
||||||
|
- printf("TSID=%s ; COMMAND=%s\n", idstr, evlog->command);
|
||||||
|
+ 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);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- ret = 0;
|
||||||
|
+ if (!sudo_lbuf_error(lbuf)) {
|
||||||
|
+ puts(lbuf->buf);
|
||||||
|
+ ret = 0;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
done:
|
||||||
|
+ lbuf->error = 0;
|
||||||
|
+ lbuf->len = 0;
|
||||||
|
eventlog_free(evlog);
|
||||||
|
debug_return_int(ret);
|
||||||
|
}
|
||||||
|
@@ -1440,6 +1547,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;
|
||||||
|
@@ -1451,6 +1559,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);
|
||||||
|
@@ -1511,7 +1621,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';
|
||||||
|
@@ -1522,6 +1632,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
|
Name: sudo
|
||||||
Version: 1.9.8p2
|
Version: 1.9.8p2
|
||||||
Release: 10
|
Release: 11
|
||||||
Summary: Allows restricted root access for specified users
|
Summary: Allows restricted root access for specified users
|
||||||
License: ISC
|
License: ISC
|
||||||
URL: http://www.courtesan.com/sudo/
|
URL: http://www.courtesan.com/sudo/
|
||||||
@ -30,6 +30,7 @@ Patch16: backport-sudo_rcstr_dup-Fix-potential-NULL-pointer-deref.patch
|
|||||||
Patch17: backport-CVE-2023-22809.patch
|
Patch17: backport-CVE-2023-22809.patch
|
||||||
Patch18: backport-Fix-a-NOPASSWD-issue-with-a-non-existent-command-whe.patch
|
Patch18: backport-Fix-a-NOPASSWD-issue-with-a-non-existent-command-whe.patch
|
||||||
Patch19: backport-CVE-2023-27320.patch
|
Patch19: backport-CVE-2023-27320.patch
|
||||||
|
Patch20: backport-CVE-2023-28486_CVE-2023-28487.patch
|
||||||
|
|
||||||
Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||||
Requires: pam
|
Requires: pam
|
||||||
@ -180,6 +181,9 @@ install -p -c -m 0644 %{SOURCE3} $RPM_BUILD_ROOT/etc/pam.d/sudo-i
|
|||||||
%exclude %{_pkgdocdir}/ChangeLog
|
%exclude %{_pkgdocdir}/ChangeLog
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Mar 28 2023 wangcheng <wangcheng156@huawei.com> - 1.9.8p2-11
|
||||||
|
- Fix CVE-2023-28486 and CVE-2023-28487
|
||||||
|
|
||||||
* Tue Mar 07 2023 wangyu <wangyu283@huawei.com> - 1.9.8p2-10
|
* Tue Mar 07 2023 wangyu <wangyu283@huawei.com> - 1.9.8p2-10
|
||||||
- Fix CVE-2023-27320.
|
- Fix CVE-2023-27320.
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user