From cbb49e8c846d05707103946c4f53783d99e2e322 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 2 Apr 2026 08:01:47 +0000 Subject: [PATCH 1/6] Fix NULL dereference in sort.c, from Dane Jensen. --- sort.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sort.c b/sort.c index 1b18d370..8a8f7028 100644 --- a/sort.c +++ b/sort.c @@ -505,6 +505,7 @@ sort_get_panes_session(struct session *s, u_int *n, i = 0; RB_FOREACH(wl, winlinks, &s->windows) { + w = wl->window; TAILQ_FOREACH(wp, &w->panes, entry) { if (lsz <= i) { lsz += 100; From 8b51abef08b9b63bd14526d3c9834795c93bdc38 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 2 Apr 2026 08:37:14 +0000 Subject: [PATCH 2/6] Check for \0 after skipping # not before in format_expand1, from ossfuzz. --- format.c | 2 +- window-copy.c | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/format.c b/format.c index 031d38e1..d84dfd35 100644 --- a/format.c +++ b/format.c @@ -5444,7 +5444,7 @@ format_expand1(struct format_expand_state *es, const char *fmt) buf[off++] = *fmt++; continue; } - if (*fmt++ == '\0') + if (*++fmt == '\0') break; ch = (u_char)*fmt++; diff --git a/window-copy.c b/window-copy.c index cc9f3e5d..16626563 100644 --- a/window-copy.c +++ b/window-copy.c @@ -3333,7 +3333,7 @@ window_copy_command(struct window_mode_entry *wme, struct client *c, enum window_copy_cmd_clear clear = WINDOW_COPY_CMD_CLEAR_NEVER; const char *command; u_int i, count = args_count(args); - int keys; + int keys, flags; char *error = NULL; if (count == 0) @@ -3355,9 +3355,10 @@ window_copy_command(struct window_mode_entry *wme, struct client *c, action = WINDOW_COPY_CMD_NOTHING; for (i = 0; i < nitems(window_copy_cmd_table); i++) { if (strcmp(window_copy_cmd_table[i].command, command) == 0) { - if (c->flags & CLIENT_READONLY && - (~window_copy_cmd_table[i].flags & - WINDOW_COPY_CMD_FLAG_READONLY)) { + flags = window_copy_cmd_table[i].flags; + if (c != NULL && + c->flags & CLIENT_READONLY && + (~flags & WINDOW_COPY_CMD_FLAG_READONLY)) { status_message_set(c, -1, 1, 0, 0, "client is read-only"); return; From 1a51193899293367201e0698ce08a94f404f059a Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 2 Apr 2026 08:45:35 +0000 Subject: [PATCH 3/6] Handle empty regular expression in substitution, found by ossfuzz. --- regsub.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/regsub.c b/regsub.c index 61a9c324..91be3994 100644 --- a/regsub.c +++ b/regsub.c @@ -68,6 +68,8 @@ regsub(const char *pattern, const char *with, const char *text, int flags) if (*text == '\0') return (xstrdup("")); + if (*pattern == '\0') + return (xstrdup(text)); if (regcomp(&r, pattern, flags) != 0) return (NULL); From 2d5736f2971f712a30c320c8e5a170523fae2787 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 2 Apr 2026 09:11:39 +0000 Subject: [PATCH 4/6] Limit argc to between 0 and 1000 to prevent fatal from MSG_COMMAND, from Michal Majchrowicz. --- cmd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd.c b/cmd.c index e5ec9cc5..04a4caf0 100644 --- a/cmd.c +++ b/cmd.c @@ -304,6 +304,8 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv) if (argc == 0) return (0); + if (argc < 0 || argc > 1000) + return (-1); *argv = xcalloc(argc, sizeof **argv); buf[len - 1] = '\0'; From be2c6f3b5e6de66f132fe7934de5cc5d9486836b Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 2 Apr 2026 09:28:22 +0000 Subject: [PATCH 5/6] Use INT_MIN + 1 as strtonum lower limits in formats so -ve works, found by ossfuzz. --- format.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/format.c b/format.c index d84dfd35..3dadbf34 100644 --- a/format.c +++ b/format.c @@ -4189,6 +4189,8 @@ format_build_modifiers(struct format_expand_state *es, const char **s, /* Skip any separator character. */ if (*cp == ';') cp++; + if (*cp == '\0') + break; /* Check single character modifiers with no arguments. */ if (strchr("labcdnwETSWPL!<>", cp[0]) != NULL && @@ -4749,7 +4751,7 @@ format_replace_expression(struct format_modifier *mexp, /* The third argument may be precision. */ if (argc >= 3) { - prec = strtonum(mexp->argv[2], INT_MIN, INT_MAX, &errstr); + prec = strtonum(mexp->argv[2], INT_MIN + 1, INT_MAX, &errstr); if (errstr != NULL) { format_log(es, "expression precision %s: %s", errstr, mexp->argv[2]); @@ -4894,8 +4896,8 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen, case '=': if (fm->argc < 1) break; - limit = strtonum(fm->argv[0], INT_MIN, INT_MAX, - &errstr); + limit = strtonum(fm->argv[0], INT_MIN + 1, + INT_MAX, &errstr); if (errstr != NULL) limit = 0; if (fm->argc >= 2 && fm->argv[1] != NULL) @@ -4904,8 +4906,8 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen, case 'p': if (fm->argc < 1) break; - width = strtonum(fm->argv[0], INT_MIN, INT_MAX, - &errstr); + width = strtonum(fm->argv[0], INT_MIN + 1, + INT_MAX, &errstr); if (errstr != NULL) width = 0; break; From c95d34122086627d72ea21aa0d5e0099142f4669 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 2 Apr 2026 09:35:46 +0000 Subject: [PATCH 6/6] Do not leak trimmed string when expanding, found by ossfuzz. --- format-draw.c | 2 +- format.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/format-draw.c b/format-draw.c index c8cb74b6..03fad05f 100644 --- a/format-draw.c +++ b/format-draw.c @@ -1116,7 +1116,7 @@ format_width(const char *expanded) /* * Trim on the left, taking #[] into account. Note, we copy the whole set of * unescaped #s, but only add their escaped size to width. This is because the - * format_draw function will actually do the escaping when it runs + * format_draw function will actually do the escaping. */ char * format_trim_left(const char *expanded, u_int limit) diff --git a/format.c b/format.c index 3dadbf34..e30c67d8 100644 --- a/format.c +++ b/format.c @@ -5325,6 +5325,7 @@ done: if (marker != NULL && strcmp(new, value) != 0) { free(value); xasprintf(&value, "%s%s", new, marker); + free(new); } else { free(value); value = new; @@ -5335,6 +5336,7 @@ done: if (marker != NULL && strcmp(new, value) != 0) { free(value); xasprintf(&value, "%s%s", marker, new); + free(new); } else { free(value); value = new;