You're correct, I was explicitly just trying to fix CVE-2024-58251 and not
make any other changes but I see what you're saying. I think this solution
would address most of the issues but like you said it's not fool-proof.
This is an update from my original.

From: Kyle Steere <[email protected]>
Date: Thu, 22 Aug 2024 12:00:00 -0500
Subject: [PATCH] Fix CVE-2024-58251: Filter escape sequences from process
names

Use the existing printable_string() function to sanitize process names
in ps, top, pmap, and netstat. Add init_unicode() calls to enable
filtering of C1 control characters (0x80-0x9F).

Signed-off-by: Kyle Steere <[email protected]>
---
diff --git a/libbb/procps.c b/libbb/procps.c
index f56b71b21..abc7c6b14 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -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]) < ' ')
+ /* Only replace NUL with space, other controls handled by
printable_string */
+ if (buf[sz] == '\0')
  buf[sz] = ' ';
  sz--;
  }
@@ -617,6 +618,14 @@ void FAST_FUNC read_cmdline(char *buf, int col,
unsigned pid, const char *comm)
  } else {
  snprintf(buf, col, "[%s]", comm ? comm : "?");
  }
+
+ /* Sanitize the entire command line for terminal safety */
+ const char *safe = printable_string(buf);
+ if (safe != buf) {
+ /* printable_string returned a new string, copy it back */
+ int len = strlen(safe);
+ snprintf(buf, col, "%s", safe);
+ }
 }

 /* from kernel:
diff --git a/networking/netstat.c b/networking/netstat.c
index 807800a62..b098e9f23 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")"]"
@@ -316,7 +317,8 @@ static int FAST_FUNC dir_act(struct recursive_state
*state,

  /* 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" */
+ /* Sanitize argv[0] to prevent terminal escape sequences (CVE-2024-58251)
*/
+ pid_slash_progname = concat_path_file(pid,
printable_string(bb_basename(cmdline_buf))); /* "PID/argv0" */
  n = recursive_action(proc_pid_fname,
  ACTION_RECURSE | ACTION_QUIET,
  add_to_prg_cache_if_socket,
@@ -686,6 +688,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);
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 */



Kyle Steere

Senior Software Engineer

Chainguard

[email protected]  | chainguard.dev <http://www.chainguard.dev>

<https://github.com/chainguard-dev>
<https://www.linkedin.com/company/chainguard-dev/>
<https://x.com/chainguard_dev>


On Fri, Aug 22, 2025 at 3:30 PM Valery Ushakov <[email protected]> wrote:

> 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
> _______________________________________________
> busybox mailing list
> [email protected]
> https://lists.busybox.net/mailman/listinfo/busybox
>
_______________________________________________
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox

Reply via email to