diff options
author | Soumya Sambu <soumya.sambu@windriver.com> | 2024-05-29 06:13:28 +0000 |
---|---|---|
committer | Steve Sakoman <steve@sakoman.com> | 2024-06-01 19:07:52 -0700 |
commit | ec87d3ca28273d5bb0d38d82566e4d1bca93e31a (patch) | |
tree | 00e54ca636126465d1ebe9408d78cf4237227808 | |
parent | b0b5da10e13fe264e34a60e82ab06139f7ba7fd5 (diff) | |
download | poky-ec87d3ca28273d5bb0d38d82566e4d1bca93e31a.tar.gz |
util-linux: Fix CVE-2024-28085
wall in util-linux through 2.40, often installed with setgid
tty permissions, allows escape sequences to be sent to other
users' terminals through argv. (Specifically, escape sequences
received from stdin are blocked, but escape sequences received
from argv are not blocked.) There may be plausible scenarios
where this leads to account takeover.
CVE-2024-28085-0005 is the CVE fix and CVE-2024-28085-0001,
CVE-2024-28085-0002, CVE-2024-28085-0003, CVE-2024-28085-0004
are dependent commits to fix the CVE.
References:
https://nvd.nist.gov/vuln/detail/CVE-2024-28085
(From OE-Core rev: 28d9f948536dfee2330e4cfd225c932d20d688f1)
Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
6 files changed, 672 insertions, 0 deletions
diff --git a/meta/recipes-core/util-linux/util-linux.inc b/meta/recipes-core/util-linux/util-linux.inc index 982ec669a2..f8841e6be0 100644 --- a/meta/recipes-core/util-linux/util-linux.inc +++ b/meta/recipes-core/util-linux/util-linux.inc | |||
@@ -35,6 +35,11 @@ SRC_URI = "${KERNELORG_MIRROR}/linux/utils/util-linux/v${MAJOR_VERSION}/util-lin | |||
35 | file://run-ptest \ | 35 | file://run-ptest \ |
36 | file://display_testname_for_subtest.patch \ | 36 | file://display_testname_for_subtest.patch \ |
37 | file://avoid_parallel_tests.patch \ | 37 | file://avoid_parallel_tests.patch \ |
38 | file://CVE-2024-28085-0001.patch \ | ||
39 | file://CVE-2024-28085-0002.patch \ | ||
40 | file://CVE-2024-28085-0003.patch \ | ||
41 | file://CVE-2024-28085-0004.patch \ | ||
42 | file://CVE-2024-28085-0005.patch \ | ||
38 | " | 43 | " |
39 | 44 | ||
40 | SRC_URI[sha256sum] = "634e6916ad913366c3536b6468e7844769549b99a7b2bf80314de78ab5655b83" | 45 | SRC_URI[sha256sum] = "634e6916ad913366c3536b6468e7844769549b99a7b2bf80314de78ab5655b83" |
diff --git a/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0001.patch b/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0001.patch new file mode 100644 index 0000000000..7ce2d6c567 --- /dev/null +++ b/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0001.patch | |||
@@ -0,0 +1,202 @@ | |||
1 | From 8a7b8456d1dc0e7ca557d1ac31f638986704757f Mon Sep 17 00:00:00 2001 | ||
2 | From: наб <nabijaczleweli@nabijaczleweli.xyz> | ||
3 | Date: Wed Mar 15 16:16:31 2023 +0100 | ||
4 | Subject: [PATCH] write: correctly handle wide characters | ||
5 | |||
6 | Do this by replacing fputc_careful() (notice that the description said | ||
7 | it's locale-aware ‒ it very much is /not/), with a fputs_careful() which | ||
8 | does the same thing, but if it were to output a byte in the \123 format, | ||
9 | first it checks whether this byte starts a valid multibyte character. | ||
10 | |||
11 | If it does, and that character is printable, write it verbatim. | ||
12 | This means that | ||
13 | echo 'foo åäö ąęćźżń bar' | write nabijaczleweli pts/4 | ||
14 | instead of | ||
15 | foo \303\245\303\244\303\266 | ||
16 | \304\205\304\231\304\207\305\272\305\274\305\204 bar | ||
17 | yields | ||
18 | foo åäö ąęćźżń bar | ||
19 | or, more realistically, from a message I got earlier today, | ||
20 | Filip powiedzia\305\202 \305\274e zap\305\202aci jutro | ||
21 | becomes | ||
22 | Filip powiedział że zapłaci jutro | ||
23 | |||
24 | Invalid/non-printable sequences get processed as before. | ||
25 | |||
26 | Line reading in write must become getline() to avoid dealing with | ||
27 | partial characters: for example on input consisting solely of | ||
28 | ąęćźżń, where every {1} is an instance, the output would be | ||
29 | {42}ąęć\305\272żń{84}ąęćź\305\274ń{84}ąęćźż\305\204{39} | ||
30 | with just fixed-512 fgets() | ||
31 | |||
32 | Bug-Debian: https://bugs.debian.org/826596 | ||
33 | |||
34 | CVE: CVE-2024-28085 | ||
35 | |||
36 | Upstream-Status: Backport [https://github.com/util-linux/util-linux/commit/8a7b8456d1dc0e7ca557d1ac31f638986704757f] | ||
37 | |||
38 | Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> | ||
39 | --- | ||
40 | include/carefulputc.h | 62 +++++++++++++++++++++++++++++++------------ | ||
41 | login-utils/last.c | 4 +-- | ||
42 | term-utils/write.c | 25 +++++------------ | ||
43 | 3 files changed, 53 insertions(+), 38 deletions(-) | ||
44 | |||
45 | diff --git a/include/carefulputc.h b/include/carefulputc.h | ||
46 | index 66a0f15..2506614 100644 | ||
47 | --- a/include/carefulputc.h | ||
48 | +++ b/include/carefulputc.h | ||
49 | @@ -1,31 +1,59 @@ | ||
50 | #ifndef UTIL_LINUX_CAREFULPUTC_H | ||
51 | #define UTIL_LINUX_CAREFULPUTC_H | ||
52 | |||
53 | -/* | ||
54 | - * A putc() for use in write and wall (that sometimes are sgid tty). | ||
55 | - * It avoids control characters in our locale, and also ASCII control | ||
56 | - * characters. Note that the locale of the recipient is unknown. | ||
57 | -*/ | ||
58 | #include <stdio.h> | ||
59 | #include <string.h> | ||
60 | #include <ctype.h> | ||
61 | +#ifdef HAVE_WIDECHAR | ||
62 | +#include <wctype.h> | ||
63 | +#endif | ||
64 | +#include <stdbool.h> | ||
65 | |||
66 | #include "cctype.h" | ||
67 | |||
68 | -static inline int fputc_careful(int c, FILE *fp, const char fail) | ||
69 | +/* | ||
70 | + * A puts() for use in write and wall (that sometimes are sgid tty). | ||
71 | + * It avoids control and invalid characters. | ||
72 | + * The locale of the recipient is nominally unknown, | ||
73 | + * but it's a solid bet that the encoding is compatible with the author's. | ||
74 | + */ | ||
75 | +static inline int fputs_careful(const char * s, FILE *fp, const char ctrl, bool cr_lf) | ||
76 | { | ||
77 | - int ret; | ||
78 | - | ||
79 | - if (isprint(c) || c == '\a' || c == '\t' || c == '\r' || c == '\n') | ||
80 | - ret = putc(c, fp); | ||
81 | - else if (!c_isascii(c)) | ||
82 | - ret = fprintf(fp, "\\%3o", (unsigned char)c); | ||
83 | - else { | ||
84 | - ret = putc(fail, fp); | ||
85 | - if (ret != EOF) | ||
86 | - ret = putc(c ^ 0x40, fp); | ||
87 | + int ret = 0; | ||
88 | + | ||
89 | + for (size_t slen = strlen(s); *s; ++s, --slen) { | ||
90 | + if (*s == '\n') | ||
91 | + ret = fputs(cr_lf ? "\r\n" : "\n", fp); | ||
92 | + else if (isprint(*s) || *s == '\a' || *s == '\t' || *s == '\r') | ||
93 | + ret = putc(*s, fp); | ||
94 | + else if (!c_isascii(*s)) { | ||
95 | +#ifdef HAVE_WIDECHAR | ||
96 | + wchar_t w; | ||
97 | + size_t clen = mbtowc(&w, s, slen); | ||
98 | + switch(clen) { | ||
99 | + case (size_t)-2: // incomplete | ||
100 | + case (size_t)-1: // EILSEQ | ||
101 | + mbtowc(NULL, NULL, 0); | ||
102 | + nonprint: | ||
103 | + ret = fprintf(fp, "\\%3hho", *s); | ||
104 | + break; | ||
105 | + default: | ||
106 | + if(!iswprint(w)) | ||
107 | + goto nonprint; | ||
108 | + ret = fwrite(s, 1, clen, fp); | ||
109 | + s += clen - 1; | ||
110 | + slen -= clen - 1; | ||
111 | + break; | ||
112 | + } | ||
113 | +#else | ||
114 | + ret = fprintf(fp, "\\%3hho", *s); | ||
115 | +#endif | ||
116 | + } else | ||
117 | + ret = fputs((char[]){ ctrl, *s ^ 0x40, '\0' }, fp); | ||
118 | + if (ret < 0) | ||
119 | + return EOF; | ||
120 | } | ||
121 | - return (ret < 0) ? EOF : 0; | ||
122 | + return 0; | ||
123 | } | ||
124 | |||
125 | static inline void fputs_quoted_case(const char *data, FILE *out, int dir) | ||
126 | diff --git a/login-utils/last.c b/login-utils/last.c | ||
127 | index f3272ca..aacd1f6 100644 | ||
128 | --- a/login-utils/last.c | ||
129 | +++ b/login-utils/last.c | ||
130 | @@ -403,7 +403,6 @@ static int list(const struct last_control *ctl, struct utmpx *p, time_t logout_t | ||
131 | char final[512]; | ||
132 | char utline[sizeof(p->ut_line) + 1]; | ||
133 | char domain[256]; | ||
134 | - char *s; | ||
135 | int mins, hours, days; | ||
136 | int r, len; | ||
137 | struct last_timefmt *fmt; | ||
138 | @@ -559,8 +558,7 @@ static int list(const struct last_control *ctl, struct utmpx *p, time_t logout_t | ||
139 | /* | ||
140 | * Print out "final" string safely. | ||
141 | */ | ||
142 | - for (s = final; *s; s++) | ||
143 | - fputc_careful(*s, stdout, '*'); | ||
144 | + fputs_careful(final, stdout, '*', false); | ||
145 | |||
146 | if (len < 0 || (size_t)len >= sizeof(final)) | ||
147 | putchar('\n'); | ||
148 | diff --git a/term-utils/write.c b/term-utils/write.c | ||
149 | index 50f18dc..710a58c 100644 | ||
150 | --- a/term-utils/write.c | ||
151 | +++ b/term-utils/write.c | ||
152 | @@ -223,21 +223,6 @@ static void signal_handler(int signo) | ||
153 | signal_received = signo; | ||
154 | } | ||
155 | |||
156 | -/* | ||
157 | - * write_line - like fputs(), but makes control characters visible and | ||
158 | - * turns \n into \r\n. | ||
159 | - */ | ||
160 | -static void write_line(char *s) | ||
161 | -{ | ||
162 | - while (*s) { | ||
163 | - const int c = *s++; | ||
164 | - | ||
165 | - if ((c == '\n' && fputc_careful('\r', stdout, '^') == EOF) | ||
166 | - || fputc_careful(c, stdout, '^') == EOF) | ||
167 | - err(EXIT_FAILURE, _("carefulputc failed")); | ||
168 | - } | ||
169 | -} | ||
170 | - | ||
171 | /* | ||
172 | * do_write - actually make the connection | ||
173 | */ | ||
174 | @@ -247,7 +232,8 @@ static void do_write(const struct write_control *ctl) | ||
175 | struct passwd *pwd; | ||
176 | time_t now; | ||
177 | struct tm *tm; | ||
178 | - char *host, line[512]; | ||
179 | + char *host, *line = NULL; | ||
180 | + size_t linelen = 0; | ||
181 | struct sigaction sigact; | ||
182 | |||
183 | /* Determine our login name(s) before the we reopen() stdout */ | ||
184 | @@ -286,11 +272,14 @@ static void do_write(const struct write_control *ctl) | ||
185 | free(host); | ||
186 | printf("\r\n"); | ||
187 | |||
188 | - while (fgets(line, sizeof(line), stdin) != NULL) { | ||
189 | + while (getline(&line, &linelen, stdin) >= 0) { | ||
190 | if (signal_received) | ||
191 | break; | ||
192 | - write_line(line); | ||
193 | + | ||
194 | + if (fputs_careful(line, stdout, '^', true) == EOF) | ||
195 | + err(EXIT_FAILURE, _("carefulputc failed")); | ||
196 | } | ||
197 | + free(line); | ||
198 | printf("EOF\r\n"); | ||
199 | } | ||
200 | |||
201 | -- | ||
202 | 2.40.0 | ||
diff --git a/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0002.patch b/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0002.patch new file mode 100644 index 0000000000..1fceebbdb4 --- /dev/null +++ b/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0002.patch | |||
@@ -0,0 +1,172 @@ | |||
1 | From 27ee6446503af7ec0c2647704ca47ac4de3852ef Mon Sep 17 00:00:00 2001 | ||
2 | From: наб <nabijaczleweli@nabijaczleweli.xyz> | ||
3 | Date: Wed, 15 Mar 2023 16:16:43 +0100 | ||
4 | Subject: [PATCH] wall: convert homebrew buffering to open_memstream() | ||
5 | |||
6 | The struct buffer system duplicates a plethora of standard I/O | ||
7 | functions (including a fork of fputc_careful()) | ||
8 | and adds a lot of complexity ‒ open_memstream() is standard, | ||
9 | and fits perfectly into this niche | ||
10 | |||
11 | CVE: CVE-2024-28085 | ||
12 | |||
13 | Upstream-Status: Backport [https://github.com/util-linux/util-linux/commit/27ee6446503af7ec0c2647704ca47ac4de3852ef] | ||
14 | |||
15 | Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> | ||
16 | --- | ||
17 | term-utils/wall.c | 95 ++++++++++------------------------------------- | ||
18 | 1 file changed, 20 insertions(+), 75 deletions(-) | ||
19 | |||
20 | diff --git a/term-utils/wall.c b/term-utils/wall.c | ||
21 | index c601d3e..a51a928 100644 | ||
22 | --- a/term-utils/wall.c | ||
23 | +++ b/term-utils/wall.c | ||
24 | @@ -274,74 +274,22 @@ int main(int argc, char **argv) | ||
25 | exit(EXIT_SUCCESS); | ||
26 | } | ||
27 | |||
28 | -struct buffer { | ||
29 | - size_t sz; | ||
30 | - size_t used; | ||
31 | - char *data; | ||
32 | -}; | ||
33 | - | ||
34 | -static void buf_enlarge(struct buffer *bs, size_t len) | ||
35 | +static void buf_putc_careful(FILE *fs, int c) | ||
36 | { | ||
37 | - if (bs->sz == 0 || len > bs->sz - bs->used) { | ||
38 | - bs->sz += len < 128 ? 128 : len; | ||
39 | - bs->data = xrealloc(bs->data, bs->sz); | ||
40 | - } | ||
41 | -} | ||
42 | - | ||
43 | -static void buf_puts(struct buffer *bs, const char *s) | ||
44 | -{ | ||
45 | - size_t len = strlen(s); | ||
46 | - | ||
47 | - buf_enlarge(bs, len + 1); | ||
48 | - memcpy(bs->data + bs->used, s, len + 1); | ||
49 | - bs->used += len; | ||
50 | -} | ||
51 | - | ||
52 | -static void __attribute__((__format__ (__printf__, 2, 3))) | ||
53 | - buf_printf(struct buffer *bs, const char *fmt, ...) | ||
54 | -{ | ||
55 | - int rc; | ||
56 | - va_list ap; | ||
57 | - size_t limit; | ||
58 | - | ||
59 | - buf_enlarge(bs, 0); /* default size */ | ||
60 | - limit = bs->sz - bs->used; | ||
61 | - | ||
62 | - va_start(ap, fmt); | ||
63 | - rc = vsnprintf(bs->data + bs->used, limit, fmt, ap); | ||
64 | - va_end(ap); | ||
65 | - | ||
66 | - if (rc >= 0 && (size_t) rc >= limit) { /* not enough, enlarge */ | ||
67 | - buf_enlarge(bs, (size_t)rc + 1); | ||
68 | - limit = bs->sz - bs->used; | ||
69 | - va_start(ap, fmt); | ||
70 | - rc = vsnprintf(bs->data + bs->used, limit, fmt, ap); | ||
71 | - va_end(ap); | ||
72 | - } | ||
73 | - | ||
74 | - if (rc > 0) | ||
75 | - bs->used += rc; | ||
76 | -} | ||
77 | - | ||
78 | -static void buf_putc_careful(struct buffer *bs, int c) | ||
79 | -{ | ||
80 | - if (isprint(c) || c == '\a' || c == '\t' || c == '\r' || c == '\n') { | ||
81 | - buf_enlarge(bs, 1); | ||
82 | - bs->data[bs->used++] = c; | ||
83 | - } else if (!c_isascii(c)) | ||
84 | - buf_printf(bs, "\\%3o", (unsigned char)c); | ||
85 | - else { | ||
86 | - char tmp[] = { '^', c ^ 0x40, '\0' }; | ||
87 | - buf_puts(bs, tmp); | ||
88 | - } | ||
89 | + if (isprint(c) || c == '\a' || c == '\t' || c == '\r' || c == '\n') | ||
90 | + fputc(c, fs); | ||
91 | + else if (!c_isascii(c)) | ||
92 | + fprintf(fs, "\\%3o", (unsigned char)c); | ||
93 | + else | ||
94 | + fputs((char[]){ '^', c ^ 0x40, '\0' }, fs); | ||
95 | } | ||
96 | |||
97 | static char *makemsg(char *fname, char **mvec, int mvecsz, | ||
98 | size_t *mbufsize, int print_banner) | ||
99 | { | ||
100 | - struct buffer _bs = {.used = 0}, *bs = &_bs; | ||
101 | register int ch, cnt; | ||
102 | - char *p, *lbuf; | ||
103 | + char *p, *lbuf, *retbuf; | ||
104 | + FILE * fs = open_memstream(&retbuf, mbufsize); | ||
105 | long line_max; | ||
106 | |||
107 | line_max = sysconf(_SC_LINE_MAX); | ||
108 | @@ -379,15 +327,15 @@ static char *makemsg(char *fname, char **mvec, int mvecsz, | ||
109 | */ | ||
110 | /* snprintf is not always available, but the sprintf's here | ||
111 | will not overflow as long as %d takes at most 100 chars */ | ||
112 | - buf_printf(bs, "\r%*s\r\n", TERM_WIDTH, " "); | ||
113 | + fprintf(fs, "\r%*s\r\n", TERM_WIDTH, " "); | ||
114 | |||
115 | snprintf(lbuf, line_max, | ||
116 | _("Broadcast message from %s@%s (%s) (%s):"), | ||
117 | whom, hostname, where, date); | ||
118 | - buf_printf(bs, "%-*.*s\007\007\r\n", TERM_WIDTH, TERM_WIDTH, lbuf); | ||
119 | + fprintf(fs, "%-*.*s\007\007\r\n", TERM_WIDTH, TERM_WIDTH, lbuf); | ||
120 | free(hostname); | ||
121 | } | ||
122 | - buf_printf(bs, "%*s\r\n", TERM_WIDTH, " "); | ||
123 | + fprintf(fs, "%*s\r\n", TERM_WIDTH, " "); | ||
124 | |||
125 | if (mvec) { | ||
126 | /* | ||
127 | @@ -396,11 +344,11 @@ static char *makemsg(char *fname, char **mvec, int mvecsz, | ||
128 | int i; | ||
129 | |||
130 | for (i = 0; i < mvecsz; i++) { | ||
131 | - buf_puts(bs, mvec[i]); | ||
132 | + fputs(mvec[i], fs); | ||
133 | if (i < mvecsz - 1) | ||
134 | - buf_puts(bs, " "); | ||
135 | + fputc(' ', fs); | ||
136 | } | ||
137 | - buf_puts(bs, "\r\n"); | ||
138 | + fputs("\r\n", fs); | ||
139 | } else { | ||
140 | /* | ||
141 | * read message from <file> | ||
142 | @@ -428,23 +376,20 @@ static char *makemsg(char *fname, char **mvec, int mvecsz, | ||
143 | while (fgets(lbuf, line_max, stdin)) { | ||
144 | for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) { | ||
145 | if (cnt == TERM_WIDTH || ch == '\n') { | ||
146 | - for (; cnt < TERM_WIDTH; ++cnt) | ||
147 | - buf_puts(bs, " "); | ||
148 | - buf_puts(bs, "\r\n"); | ||
149 | + fprintf(fs, "%*s\r\n", TERM_WIDTH - cnt, ""); | ||
150 | cnt = 0; | ||
151 | } | ||
152 | if (ch == '\t') | ||
153 | cnt += (7 - (cnt % 8)); | ||
154 | if (ch != '\n') | ||
155 | - buf_putc_careful(bs, ch); | ||
156 | + buf_putc_careful(fs, ch); | ||
157 | } | ||
158 | } | ||
159 | } | ||
160 | - buf_printf(bs, "%*s\r\n", TERM_WIDTH, " "); | ||
161 | + fprintf(fs, "%*s\r\n", TERM_WIDTH, " "); | ||
162 | |||
163 | free(lbuf); | ||
164 | |||
165 | - bs->data[bs->used] = '\0'; /* be paranoid */ | ||
166 | - *mbufsize = bs->used; | ||
167 | - return bs->data; | ||
168 | + fclose(fs); | ||
169 | + return retbuf; | ||
170 | } | ||
171 | -- | ||
172 | 2.40.0 | ||
diff --git a/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0003.patch b/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0003.patch new file mode 100644 index 0000000000..55eba9cc49 --- /dev/null +++ b/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0003.patch | |||
@@ -0,0 +1,223 @@ | |||
1 | From aa13246a1bf1be9e4f6eb331f4d4d2dbc875e22f Mon Sep 17 00:00:00 2001 | ||
2 | From: наб <nabijaczleweli@nabijaczleweli.xyz> | ||
3 | Date: Wed, 15 Mar 2023 16:16:48 +0100 | ||
4 | Subject: [PATCH] wall: use fputs_careful() | ||
5 | |||
6 | LINE_MAX only applies to teletypes in canonical mode: when stdin is a | ||
7 | file, it could still very much tear; start off at 512 for the sprintf(), | ||
8 | then use getline() like in write. | ||
9 | |||
10 | The line wrapping has one suboptimal edge-case: | ||
11 | $ wall < all | ||
12 | |||
13 | Broadcast message from nabijaczleweli@tarta (pts/4) (Tue Mar 14 22:31:25 | ||
14 | 2023): | ||
15 | |||
16 | ^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\^]^^^_ | ||
17 | !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJ | ||
18 | KLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~^?\200\201\202\203\204\205\206 | ||
19 | \207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232 | ||
20 | \233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256 | ||
21 | \257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302 | ||
22 | \303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326 | ||
23 | \327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352 | ||
24 | \353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376 | ||
25 | \377 | ||
26 | but that's a pathological input, and the result is still infinitely | ||
27 | better than it was before, so fixing that is more trouble than it's | ||
28 | worth. | ||
29 | |||
30 | Bug-Debian: https://bugs.debian.org/826596 | ||
31 | |||
32 | CVE: CVE-2024-28085 | ||
33 | |||
34 | Upstream-Status: Backport [https://github.com/util-linux/util-linux/commit/aa13246a1bf1be9e4f6eb331f4d4d2dbc875e22f] | ||
35 | |||
36 | Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> | ||
37 | --- | ||
38 | include/carefulputc.h | 42 +++++++++++++++++++++++++++++++++--------- | ||
39 | login-utils/last.c | 2 +- | ||
40 | term-utils/wall.c | 38 ++++++-------------------------------- | ||
41 | term-utils/write.c | 2 +- | ||
42 | 4 files changed, 41 insertions(+), 43 deletions(-) | ||
43 | |||
44 | diff --git a/include/carefulputc.h b/include/carefulputc.h | ||
45 | index 2506614..89f8a99 100644 | ||
46 | --- a/include/carefulputc.h | ||
47 | +++ b/include/carefulputc.h | ||
48 | @@ -6,6 +6,7 @@ | ||
49 | #include <ctype.h> | ||
50 | #ifdef HAVE_WIDECHAR | ||
51 | #include <wctype.h> | ||
52 | +#include <wchar.h> | ||
53 | #endif | ||
54 | #include <stdbool.h> | ||
55 | |||
56 | @@ -15,18 +16,35 @@ | ||
57 | * A puts() for use in write and wall (that sometimes are sgid tty). | ||
58 | * It avoids control and invalid characters. | ||
59 | * The locale of the recipient is nominally unknown, | ||
60 | - * but it's a solid bet that the encoding is compatible with the author's. | ||
61 | + * but it's a solid bet that it's compatible with the author's. | ||
62 | + * Use soft_width=0 to disable wrapping. | ||
63 | */ | ||
64 | -static inline int fputs_careful(const char * s, FILE *fp, const char ctrl, bool cr_lf) | ||
65 | +static inline int fputs_careful(const char * s, FILE *fp, const char ctrl, bool cr_lf, int soft_width) | ||
66 | { | ||
67 | - int ret = 0; | ||
68 | + int ret = 0, col = 0; | ||
69 | |||
70 | for (size_t slen = strlen(s); *s; ++s, --slen) { | ||
71 | - if (*s == '\n') | ||
72 | + if (*s == '\t') | ||
73 | + col += (7 - (col % 8)) - 1; | ||
74 | + else if (*s == '\r') | ||
75 | + col = -1; | ||
76 | + else if (*s == '\a') | ||
77 | + --col; | ||
78 | + | ||
79 | + if ((soft_width && col >= soft_width) || *s == '\n') { | ||
80 | + if (soft_width) { | ||
81 | + fprintf(fp, "%*s", soft_width - col, ""); | ||
82 | + col = 0; | ||
83 | + } | ||
84 | ret = fputs(cr_lf ? "\r\n" : "\n", fp); | ||
85 | - else if (isprint(*s) || *s == '\a' || *s == '\t' || *s == '\r') | ||
86 | + if (*s == '\n' || ret < 0) | ||
87 | + goto wrote; | ||
88 | + } | ||
89 | + | ||
90 | + if (isprint(*s) || *s == '\a' || *s == '\t' || *s == '\r') { | ||
91 | ret = putc(*s, fp); | ||
92 | - else if (!c_isascii(*s)) { | ||
93 | + ++col; | ||
94 | + } else if (!c_isascii(*s)) { | ||
95 | #ifdef HAVE_WIDECHAR | ||
96 | wchar_t w; | ||
97 | size_t clen = mbtowc(&w, s, slen); | ||
98 | @@ -35,21 +53,27 @@ static inline int fputs_careful(const char * s, FILE *fp, const char ctrl, bool | ||
99 | case (size_t)-1: // EILSEQ | ||
100 | mbtowc(NULL, NULL, 0); | ||
101 | nonprint: | ||
102 | - ret = fprintf(fp, "\\%3hho", *s); | ||
103 | + col += ret = fprintf(fp, "\\%3hho", *s); | ||
104 | break; | ||
105 | default: | ||
106 | if(!iswprint(w)) | ||
107 | goto nonprint; | ||
108 | ret = fwrite(s, 1, clen, fp); | ||
109 | + if (soft_width) | ||
110 | + col += wcwidth(w); | ||
111 | s += clen - 1; | ||
112 | slen -= clen - 1; | ||
113 | break; | ||
114 | } | ||
115 | #else | ||
116 | - ret = fprintf(fp, "\\%3hho", *s); | ||
117 | + col += ret = fprintf(fp, "\\%3hho", *s); | ||
118 | #endif | ||
119 | - } else | ||
120 | + } else { | ||
121 | ret = fputs((char[]){ ctrl, *s ^ 0x40, '\0' }, fp); | ||
122 | + col += 2; | ||
123 | + } | ||
124 | + | ||
125 | + wrote: | ||
126 | if (ret < 0) | ||
127 | return EOF; | ||
128 | } | ||
129 | diff --git a/login-utils/last.c b/login-utils/last.c | ||
130 | index aacd1f6..43c5429 100644 | ||
131 | --- a/login-utils/last.c | ||
132 | +++ b/login-utils/last.c | ||
133 | @@ -558,7 +558,7 @@ static int list(const struct last_control *ctl, struct utmpx *p, time_t logout_t | ||
134 | /* | ||
135 | * Print out "final" string safely. | ||
136 | */ | ||
137 | - fputs_careful(final, stdout, '*', false); | ||
138 | + fputs_careful(final, stdout, '*', false, 0); | ||
139 | |||
140 | if (len < 0 || (size_t)len >= sizeof(final)) | ||
141 | putchar('\n'); | ||
142 | diff --git a/term-utils/wall.c b/term-utils/wall.c | ||
143 | index a51a928..377db45 100644 | ||
144 | --- a/term-utils/wall.c | ||
145 | +++ b/term-utils/wall.c | ||
146 | @@ -274,29 +274,13 @@ int main(int argc, char **argv) | ||
147 | exit(EXIT_SUCCESS); | ||
148 | } | ||
149 | |||
150 | -static void buf_putc_careful(FILE *fs, int c) | ||
151 | -{ | ||
152 | - if (isprint(c) || c == '\a' || c == '\t' || c == '\r' || c == '\n') | ||
153 | - fputc(c, fs); | ||
154 | - else if (!c_isascii(c)) | ||
155 | - fprintf(fs, "\\%3o", (unsigned char)c); | ||
156 | - else | ||
157 | - fputs((char[]){ '^', c ^ 0x40, '\0' }, fs); | ||
158 | -} | ||
159 | - | ||
160 | static char *makemsg(char *fname, char **mvec, int mvecsz, | ||
161 | size_t *mbufsize, int print_banner) | ||
162 | { | ||
163 | - register int ch, cnt; | ||
164 | - char *p, *lbuf, *retbuf; | ||
165 | + char *lbuf, *retbuf; | ||
166 | FILE * fs = open_memstream(&retbuf, mbufsize); | ||
167 | - long line_max; | ||
168 | - | ||
169 | - line_max = sysconf(_SC_LINE_MAX); | ||
170 | - if (line_max <= 0) | ||
171 | - line_max = 512; | ||
172 | - | ||
173 | - lbuf = xmalloc(line_max); | ||
174 | + size_t lbuflen = 512; | ||
175 | + lbuf = xmalloc(lbuflen); | ||
176 | |||
177 | if (print_banner == TRUE) { | ||
178 | char *hostname = xgethostname(); | ||
179 | @@ -329,7 +313,7 @@ static char *makemsg(char *fname, char **mvec, int mvecsz, | ||
180 | will not overflow as long as %d takes at most 100 chars */ | ||
181 | fprintf(fs, "\r%*s\r\n", TERM_WIDTH, " "); | ||
182 | |||
183 | - snprintf(lbuf, line_max, | ||
184 | + snprintf(lbuf, lbuflen, | ||
185 | _("Broadcast message from %s@%s (%s) (%s):"), | ||
186 | whom, hostname, where, date); | ||
187 | fprintf(fs, "%-*.*s\007\007\r\n", TERM_WIDTH, TERM_WIDTH, lbuf); | ||
188 | @@ -373,18 +357,8 @@ static char *makemsg(char *fname, char **mvec, int mvecsz, | ||
189 | /* | ||
190 | * Read message from stdin. | ||
191 | */ | ||
192 | - while (fgets(lbuf, line_max, stdin)) { | ||
193 | - for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) { | ||
194 | - if (cnt == TERM_WIDTH || ch == '\n') { | ||
195 | - fprintf(fs, "%*s\r\n", TERM_WIDTH - cnt, ""); | ||
196 | - cnt = 0; | ||
197 | - } | ||
198 | - if (ch == '\t') | ||
199 | - cnt += (7 - (cnt % 8)); | ||
200 | - if (ch != '\n') | ||
201 | - buf_putc_careful(fs, ch); | ||
202 | - } | ||
203 | - } | ||
204 | + while (getline(&lbuf, &lbuflen, stdin) >= 0) | ||
205 | + fputs_careful(lbuf, fs, '^', true, TERM_WIDTH); | ||
206 | } | ||
207 | fprintf(fs, "%*s\r\n", TERM_WIDTH, " "); | ||
208 | |||
209 | diff --git a/term-utils/write.c b/term-utils/write.c | ||
210 | index 710a58c..1d57fce 100644 | ||
211 | --- a/term-utils/write.c | ||
212 | +++ b/term-utils/write.c | ||
213 | @@ -276,7 +276,7 @@ static void do_write(const struct write_control *ctl) | ||
214 | if (signal_received) | ||
215 | break; | ||
216 | |||
217 | - if (fputs_careful(line, stdout, '^', true) == EOF) | ||
218 | + if (fputs_careful(line, stdout, '^', true, 0) == EOF) | ||
219 | err(EXIT_FAILURE, _("carefulputc failed")); | ||
220 | } | ||
221 | free(line); | ||
222 | -- | ||
223 | 2.40.0 | ||
diff --git a/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0004.patch b/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0004.patch new file mode 100644 index 0000000000..af39931b3f --- /dev/null +++ b/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0004.patch | |||
@@ -0,0 +1,36 @@ | |||
1 | From 07f0f0f5bd1e5e2268257ae1ff6d76a9b6c6ea8b Mon Sep 17 00:00:00 2001 | ||
2 | From: Karel Zak <kzak@redhat.com> | ||
3 | Date: Wed, 17 Jan 2024 12:37:08 +0100 | ||
4 | Subject: [PATCH] wall: fix calloc cal [-Werror=calloc-transposed-args] | ||
5 | |||
6 | term-utils/wall.c:143:37: error: xcalloc sizes specified with sizeof in the earlier argument and not in the later argument [-Werror=calloc-transposed-args] | ||
7 | 143 | buf->groups = xcalloc(sizeof(*buf->groups), buf->ngroups); | ||
8 | | ^ | ||
9 | term-utils/wall.c:143:37: note: earlier argument should specify number of elements, later size of each element | ||
10 | |||
11 | Signed-off-by: Karel Zak <kzak@redhat.com> | ||
12 | |||
13 | CVE: CVE-2024-28085 | ||
14 | |||
15 | Upstream-Status: Backport [https://github.com/util-linux/util-linux/commit/07f0f0f5bd1e5e2268257ae1ff6d76a9b6c6ea8b] | ||
16 | |||
17 | Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> | ||
18 | --- | ||
19 | term-utils/wall.c | 2 +- | ||
20 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
21 | |||
22 | diff --git a/term-utils/wall.c b/term-utils/wall.c | ||
23 | index 377db45..85c006a 100644 | ||
24 | --- a/term-utils/wall.c | ||
25 | +++ b/term-utils/wall.c | ||
26 | @@ -135,7 +135,7 @@ static struct group_workspace *init_group_workspace(const char *group) | ||
27 | |||
28 | buf->requested_group = get_group_gid(group); | ||
29 | buf->ngroups = sysconf(_SC_NGROUPS_MAX) + 1; /* room for the primary gid */ | ||
30 | - buf->groups = xcalloc(sizeof(*buf->groups), buf->ngroups); | ||
31 | + buf->groups = xcalloc(buf->ngroups, sizeof(*buf->groups)); | ||
32 | |||
33 | return buf; | ||
34 | } | ||
35 | -- | ||
36 | 2.40.0 | ||
diff --git a/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0005.patch b/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0005.patch new file mode 100644 index 0000000000..a2b914d580 --- /dev/null +++ b/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0005.patch | |||
@@ -0,0 +1,34 @@ | |||
1 | From 404b0781f52f7c045ca811b2dceec526408ac253 Mon Sep 17 00:00:00 2001 | ||
2 | From: Karel Zak <kzak@redhat.com> | ||
3 | Date: Thu, 21 Mar 2024 11:16:20 +0100 | ||
4 | Subject: [PATCH] wall: fix escape sequence Injection [CVE-2024-28085] | ||
5 | |||
6 | Let's use for all cases the same output function. | ||
7 | |||
8 | Reported-by: Skyler Ferrante <sjf5462@rit.edu> | ||
9 | Signed-off-by: Karel Zak <kzak@redhat.com> | ||
10 | |||
11 | CVE: CVE-2024-28085 | ||
12 | |||
13 | Upstream-Status: Backport [https://github.com/util-linux/util-linux/commit/404b0781f52f7c045ca811b2dceec526408ac253] | ||
14 | |||
15 | Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> | ||
16 | --- | ||
17 | term-utils/wall.c | 2 +- | ||
18 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
19 | |||
20 | diff --git a/term-utils/wall.c b/term-utils/wall.c | ||
21 | index 85c006a..0212c03 100644 | ||
22 | --- a/term-utils/wall.c | ||
23 | +++ b/term-utils/wall.c | ||
24 | @@ -328,7 +328,7 @@ static char *makemsg(char *fname, char **mvec, int mvecsz, | ||
25 | int i; | ||
26 | |||
27 | for (i = 0; i < mvecsz; i++) { | ||
28 | - fputs(mvec[i], fs); | ||
29 | + fputs_careful(mvec[i], fs, '^', true, TERM_WIDTH); | ||
30 | if (i < mvecsz - 1) | ||
31 | fputc(' ', fs); | ||
32 | } | ||
33 | -- | ||
34 | 2.40.0 | ||