On Thu, Aug 21, 2025 at 22:56:20 +0000, Kyle Steere wrote:
> In BusyBox netstat, local users can launch a network application with an
> argv[0] containing ANSI terminal escape sequences, leading to a denial of
> service (terminal locked up) when netstat is used by a victim.
>
> This patch sanitizes the process name before storing it in the cache,
> replacing any non-printable characters (including escape sequences) with
> '?'.
>
> CVE-2024-58251: https://nvd.nist.gov/vuln/detail/CVE-2024-58251
This might, pedantically speaking, tick off the CVE as reported, but
the very same process will trigger the exact same problem with ps(1)
&c that sanitizes C0 controls, but doesn't sanitize C1 controls (and
doesn't sanitize the {comm} part at all, btw, even for C0). I
recently posted about that, but got no feedback:
https://lists.busybox.net/pipermail/busybox/2025-August/091682.html
https://lists.busybox.net/pipermail/busybox/2025-August/091683.html
With ps &c you don't even need the argv[0] trickery that you need with
netstat (as neststat only shows argv[0]), just passing the offending
string as an argument is enough.
The attached patch tries to address that issue too. It's probably
better done with some refactoring, but for now I did it defadvice
style. It's not very thoroughly tested.
As explained in the second patch description, you cannot make this
completely fool-proof, b/c C1 bytes may be part of UTF-8 encoding for
normal characters.
-uwe
>From 81b33c6975cd9059624837c73fb591150988b316 Mon Sep 17 00:00:00 2001
From: Valery Ushakov <[email protected]>
Date: Thu, 21 Aug 2025 12:31:53 +0000
Subject: [PATCH 1/2] netstat: CVE-2024-58251 - sanitize argv0 for -p
Signed-off-by: Valery Ushakov <[email protected]>
---
networking/netstat.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/networking/netstat.c b/networking/netstat.c
index 807800a62..d979f6079 100644
--- a/networking/netstat.c
+++ b/networking/netstat.c
@@ -41,6 +41,7 @@
#include "libbb.h"
#include "inet_common.h"
+#include "unicode.h"
//usage:#define netstat_trivial_usage
//usage: "[-"IF_ROUTE("r")"al] [-tuwx] [-en"IF_FEATURE_NETSTAT_WIDE("W")IF_FEATURE_NETSTAT_PRG("p")"]"
@@ -314,9 +315,12 @@ static int FAST_FUNC dir_act(struct recursive_state *state,
return FALSE;
cmdline_buf[n] = '\0';
+ /* don't write process-controlled argv[0] to the user's terminal as-is */
+ const char *argv0base = printable_string(bb_basename(cmdline_buf));
+
/* go through all files in /proc/PID/fd and check whether they are sockets */
strcpy(proc_pid_fname + len - (sizeof("cmdline")-1), "fd");
- pid_slash_progname = concat_path_file(pid, bb_basename(cmdline_buf)); /* "PID/argv0" */
+ pid_slash_progname = concat_path_file(pid, argv0base); /* "PID/argv0" */
n = recursive_action(proc_pid_fname,
ACTION_RECURSE | ACTION_QUIET,
add_to_prg_cache_if_socket,
@@ -686,6 +690,7 @@ int netstat_main(int argc UNUSED_PARAM, char **argv)
unsigned opt;
INIT_G();
+ init_unicode();
/* Option string must match NETSTAT_xxx constants */
opt = getopt32(argv, NETSTAT_OPTS);
--
2.34.1
>From 683f1ad81823800271d6f000e3e8b2155a3e386a Mon Sep 17 00:00:00 2001
From: Valery Ushakov <[email protected]>
Date: Fri, 22 Aug 2025 10:52:30 +0000
Subject: [PATCH 2/2] read_cmdline: wrap in printable_string
This is the same issue as CVE-2024-58251 for netstat -p vs. control
characters in argv0. read_cmdline() had rudimentary sanitation code
that masked C0 controls, but there are C1 controls too and gnome
terminal seems to always interpret them, and xterm interprets them in
non-utf-8 mode. So wrap read_cmdline() in a piece of advice that
applies printable_string to the buffer and add init_unicode() calls to
ps(1), top(1) and pmap(1) that call read_cmdline().
Note that this is not _completely_ fool-proof as you may have C1 bytes
as part of valid UTF-8 sequences for characters outside C1, e.g.
\u3add0;Gotcha\u3adc is a valid UTF-8 string, but it also a valid OSC
sequence _if_ interpreted as a single-byte 8-bit string. procps-ng
will pass that kind of sequence through as well. But this is,
strictly speaking, a misconfiguration, and you are supposed to use
Ubik's self-winding Swiss chromium never-ending blade only as
directed, and with caution.
Signed-off-by: Valery Ushakov <[email protected]>
---
libbb/procps.c | 16 ++++++++++++++--
procps/pmap.c | 3 +++
procps/ps.c | 2 ++
procps/top.c | 2 ++
4 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/libbb/procps.c b/libbb/procps.c
index f56b71b21..f8aae9af0 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -566,7 +566,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
return sp;
}
-void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
+static void FAST_FUNC read_cmdline2(char *buf, int col, unsigned pid, const char *comm)
{
int sz;
char filename[sizeof("/proc/%u/cmdline") + sizeof(int)*3];
@@ -584,7 +584,8 @@ void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
strchrnul(buf, ' ')[0] = '\0';
base = bb_basename(buf); /* before we replace argv0's NUL with space */
while (sz >= 0) {
- if ((unsigned char)(buf[sz]) < ' ')
+ /* controls will be dealt with by printable_string */
+ if (buf[sz] == '\0')
buf[sz] = ' ';
sz--;
}
@@ -618,6 +619,17 @@ void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
}
}
+// defadvice (read_cmdline :after)
+void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
+{
+ read_cmdline2(buf, col, pid, comm);
+ char *printable = printable_string(buf);
+ if (printable == buf)
+ return;
+
+ snprintf(buf, col, "%s", printable);
+}
+
/* from kernel:
// pid comm S ppid pgid sid tty_nr tty_pgrp flg
sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
diff --git a/procps/pmap.c b/procps/pmap.c
index 49f7688d9..3b367d34c 100644
--- a/procps/pmap.c
+++ b/procps/pmap.c
@@ -26,6 +26,7 @@
//usage: "\n -q Quiet"
#include "libbb.h"
+#include "unicode.h"
#if ULLONG_MAX == 0xffffffff
# define TABS "\t"
@@ -96,6 +97,8 @@ int pmap_main(int argc UNUSED_PARAM, char **argv)
unsigned opts;
int ret;
+ init_unicode();
+
opts = getopt32(argv, "^" "xq" "\0" "-1"); /* min one arg */
argv += optind;
diff --git a/procps/ps.c b/procps/ps.c
index 5b521aebd..f184f25ac 100644
--- a/procps/ps.c
+++ b/procps/ps.c
@@ -109,6 +109,7 @@
//usage: " 2990 andersen andersen R ps\n"
#include "libbb.h"
+#include "unicode.h"
#include "common_bufsiz.h"
#ifdef __linux__
# include <sys/sysinfo.h>
@@ -576,6 +577,7 @@ int ps_main(int argc UNUSED_PARAM, char **argv)
G.kernel_HZ = bb_clk_tck(); /* this is sysconf(_SC_CLK_TCK) */
# endif
#endif
+ init_unicode();
// POSIX:
// -a Write information for all processes associated with terminals
diff --git a/procps/top.c b/procps/top.c
index 09d31c673..64acbafcb 100644
--- a/procps/top.c
+++ b/procps/top.c
@@ -116,6 +116,7 @@
//kbuild:lib-$(CONFIG_TOP) += top.o
#include "libbb.h"
+#include "unicode.h"
#define ESC "\033"
@@ -1160,6 +1161,7 @@ int top_main(int argc UNUSED_PARAM, char **argv)
unsigned scan_mask = TOP_MASK;
INIT_G();
+ init_unicode();
interval = 5; /* default update interval is 5 seconds */
iterations = 0; /* infinite */
--
2.34.1
_______________________________________________
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox