|
| 1 | +From dce2d7df237424c76c1961a323664af60e228225 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Bala <Balakumaran.kannan@microsoft.com> |
| 3 | +Date: Thu, 18 Apr 2024 06:20:13 +0000 |
| 4 | +Subject: [PATCH] wall: fix escape sequence Injection [CVE-2024-28085] |
| 5 | + |
| 6 | +--- |
| 7 | + include/carefulputc.h | 73 +++++++++++++++++++++++++++++++++++++++++++ |
| 8 | + term-utils/wall.c | 51 ++++++++++-------------------- |
| 9 | + 2 files changed, 89 insertions(+), 35 deletions(-) |
| 10 | + |
| 11 | +diff --git a/include/carefulputc.h b/include/carefulputc.h |
| 12 | +index 66a0f15..50bb14c 100644 |
| 13 | +--- a/include/carefulputc.h |
| 14 | ++++ b/include/carefulputc.h |
| 15 | +@@ -9,9 +9,82 @@ |
| 16 | + #include <stdio.h> |
| 17 | + #include <string.h> |
| 18 | + #include <ctype.h> |
| 19 | ++#ifdef HAVE_WIDECHAR |
| 20 | ++#include <wctype.h> |
| 21 | ++#include <wchar.h> |
| 22 | ++#endif |
| 23 | ++#include <stdbool.h> |
| 24 | + |
| 25 | + #include "cctype.h" |
| 26 | + |
| 27 | ++/* |
| 28 | ++ * A puts() for use in write and wall (that sometimes are sgid tty). |
| 29 | ++ * It avoids control and invalid characters. |
| 30 | ++ * The locale of the recipient is nominally unknown, |
| 31 | ++ * but it's a solid bet that it's compatible with the author's. |
| 32 | ++ * Use soft_width=0 to disable wrapping. |
| 33 | ++ */ |
| 34 | ++static inline int fputs_careful(const char * s, FILE *fp, const char ctrl, bool cr_lf, int soft_width) |
| 35 | ++{ |
| 36 | ++ int ret = 0, col = 0; |
| 37 | ++ |
| 38 | ++ for (size_t slen = strlen(s); *s; ++s, --slen) { |
| 39 | ++ if (*s == '\t') |
| 40 | ++ col += (7 - (col % 8)) - 1; |
| 41 | ++ else if (*s == '\r') |
| 42 | ++ col = -1; |
| 43 | ++ else if (*s == '\a') |
| 44 | ++ --col; |
| 45 | ++ |
| 46 | ++ if ((soft_width && col >= soft_width) || *s == '\n') { |
| 47 | ++ if (soft_width) { |
| 48 | ++ fprintf(fp, "%*s", soft_width - col, ""); |
| 49 | ++ col = 0; |
| 50 | ++ } |
| 51 | ++ ret = fputs(cr_lf ? "\r\n" : "\n", fp); |
| 52 | ++ if (*s == '\n' || ret < 0) |
| 53 | ++ goto wrote; |
| 54 | ++ } |
| 55 | ++ |
| 56 | ++ if (isprint(*s) || *s == '\a' || *s == '\t' || *s == '\r') { |
| 57 | ++ ret = putc(*s, fp); |
| 58 | ++ ++col; |
| 59 | ++ } else if (!c_isascii(*s)) { |
| 60 | ++#ifdef HAVE_WIDECHAR |
| 61 | ++ wchar_t w; |
| 62 | ++ size_t clen = mbtowc(&w, s, slen); |
| 63 | ++ switch(clen) { |
| 64 | ++ case (size_t)-2: // incomplete |
| 65 | ++ case (size_t)-1: // EILSEQ |
| 66 | ++ mbtowc(NULL, NULL, 0); |
| 67 | ++ nonprint: |
| 68 | ++ col += ret = fprintf(fp, "\\%3hho", *s); |
| 69 | ++ break; |
| 70 | ++ default: |
| 71 | ++ if(!iswprint(w)) |
| 72 | ++ goto nonprint; |
| 73 | ++ ret = fwrite(s, 1, clen, fp); |
| 74 | ++ if (soft_width) |
| 75 | ++ col += wcwidth(w); |
| 76 | ++ s += clen - 1; |
| 77 | ++ slen -= clen - 1; |
| 78 | ++ break; |
| 79 | ++ } |
| 80 | ++#else |
| 81 | ++ col += ret = fprintf(fp, "\\%3hho", *s); |
| 82 | ++#endif |
| 83 | ++ } else { |
| 84 | ++ ret = fputs((char[]){ ctrl, *s ^ 0x40, '\0' }, fp); |
| 85 | ++ col += 2; |
| 86 | ++ } |
| 87 | ++ |
| 88 | ++ wrote: |
| 89 | ++ if (ret < 0) |
| 90 | ++ return EOF; |
| 91 | ++ } |
| 92 | ++ return 0; |
| 93 | ++} |
| 94 | ++ |
| 95 | + static inline int fputc_careful(int c, FILE *fp, const char fail) |
| 96 | + { |
| 97 | + int ret; |
| 98 | +diff --git a/term-utils/wall.c b/term-utils/wall.c |
| 99 | +index c601d3e..bc4a28c 100644 |
| 100 | +--- a/term-utils/wall.c |
| 101 | ++++ b/term-utils/wall.c |
| 102 | +@@ -339,16 +339,10 @@ static void buf_putc_careful(struct buffer *bs, int c) |
| 103 | + static char *makemsg(char *fname, char **mvec, int mvecsz, |
| 104 | + size_t *mbufsize, int print_banner) |
| 105 | + { |
| 106 | +- struct buffer _bs = {.used = 0}, *bs = &_bs; |
| 107 | +- register int ch, cnt; |
| 108 | +- char *p, *lbuf; |
| 109 | +- long line_max; |
| 110 | +- |
| 111 | +- line_max = sysconf(_SC_LINE_MAX); |
| 112 | +- if (line_max <= 0) |
| 113 | +- line_max = 512; |
| 114 | +- |
| 115 | +- lbuf = xmalloc(line_max); |
| 116 | ++ char *lbuf, *retbuf; |
| 117 | ++ FILE * fs = open_memstream(&retbuf, mbufsize); |
| 118 | ++ size_t lbuflen = 512; |
| 119 | ++ lbuf = xmalloc(lbuflen); |
| 120 | + |
| 121 | + if (print_banner == TRUE) { |
| 122 | + char *hostname = xgethostname(); |
| 123 | +@@ -379,15 +373,15 @@ static char *makemsg(char *fname, char **mvec, int mvecsz, |
| 124 | + */ |
| 125 | + /* snprintf is not always available, but the sprintf's here |
| 126 | + will not overflow as long as %d takes at most 100 chars */ |
| 127 | +- buf_printf(bs, "\r%*s\r\n", TERM_WIDTH, " "); |
| 128 | ++ fprintf(fs, "\r%*s\r\n", TERM_WIDTH, " "); |
| 129 | + |
| 130 | +- snprintf(lbuf, line_max, |
| 131 | ++ snprintf(lbuf, lbuflen, |
| 132 | + _("Broadcast message from %s@%s (%s) (%s):"), |
| 133 | + whom, hostname, where, date); |
| 134 | +- buf_printf(bs, "%-*.*s\007\007\r\n", TERM_WIDTH, TERM_WIDTH, lbuf); |
| 135 | ++ fprintf(fs, "%-*.*s\007\007\r\n", TERM_WIDTH, TERM_WIDTH, lbuf); |
| 136 | + free(hostname); |
| 137 | + } |
| 138 | +- buf_printf(bs, "%*s\r\n", TERM_WIDTH, " "); |
| 139 | ++ fprintf(fs, "%*s\r\n", TERM_WIDTH, " "); |
| 140 | + |
| 141 | + if (mvec) { |
| 142 | + /* |
| 143 | +@@ -396,11 +390,11 @@ static char *makemsg(char *fname, char **mvec, int mvecsz, |
| 144 | + int i; |
| 145 | + |
| 146 | + for (i = 0; i < mvecsz; i++) { |
| 147 | +- buf_puts(bs, mvec[i]); |
| 148 | ++ fputs_careful(mvec[i], fs, '^', true, TERM_WIDTH); |
| 149 | + if (i < mvecsz - 1) |
| 150 | +- buf_puts(bs, " "); |
| 151 | ++ fputc(' ', fs); |
| 152 | + } |
| 153 | +- buf_puts(bs, "\r\n"); |
| 154 | ++ fputs("\r\n", fs); |
| 155 | + } else { |
| 156 | + /* |
| 157 | + * read message from <file> |
| 158 | +@@ -425,26 +419,13 @@ static char *makemsg(char *fname, char **mvec, int mvecsz, |
| 159 | + /* |
| 160 | + * Read message from stdin. |
| 161 | + */ |
| 162 | +- while (fgets(lbuf, line_max, stdin)) { |
| 163 | +- for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) { |
| 164 | +- if (cnt == TERM_WIDTH || ch == '\n') { |
| 165 | +- for (; cnt < TERM_WIDTH; ++cnt) |
| 166 | +- buf_puts(bs, " "); |
| 167 | +- buf_puts(bs, "\r\n"); |
| 168 | +- cnt = 0; |
| 169 | +- } |
| 170 | +- if (ch == '\t') |
| 171 | +- cnt += (7 - (cnt % 8)); |
| 172 | +- if (ch != '\n') |
| 173 | +- buf_putc_careful(bs, ch); |
| 174 | +- } |
| 175 | +- } |
| 176 | ++ while (getline(&lbuf, &lbuflen, stdin) >= 0) |
| 177 | ++ fputs_careful(lbuf, fs, '^', true, TERM_WIDTH); |
| 178 | + } |
| 179 | +- buf_printf(bs, "%*s\r\n", TERM_WIDTH, " "); |
| 180 | ++ fprintf(fs, "%*s\r\n", TERM_WIDTH, " "); |
| 181 | + |
| 182 | + free(lbuf); |
| 183 | + |
| 184 | +- bs->data[bs->used] = '\0'; /* be paranoid */ |
| 185 | +- *mbufsize = bs->used; |
| 186 | +- return bs->data; |
| 187 | ++ fclose(fs); |
| 188 | ++ return retbuf; |
| 189 | + } |
| 190 | +-- |
| 191 | +2.33.8 |
| 192 | + |
0 commit comments