Files
poky/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0001.patch
Soumya Sambu ec87d3ca28 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>
2024-06-01 19:07:52 -07:00

203 lines
5.9 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 8a7b8456d1dc0e7ca557d1ac31f638986704757f Mon Sep 17 00:00:00 2001
From: наб <nabijaczleweli@nabijaczleweli.xyz>
Date: Wed Mar 15 16:16:31 2023 +0100
Subject: [PATCH] write: correctly handle wide characters
Do this by replacing fputc_careful() (notice that the description said
it's locale-aware it very much is /not/), with a fputs_careful() which
does the same thing, but if it were to output a byte in the \123 format,
first it checks whether this byte starts a valid multibyte character.
If it does, and that character is printable, write it verbatim.
This means that
echo 'foo åäö ąęćźżń bar' | write nabijaczleweli pts/4
instead of
foo \303\245\303\244\303\266
\304\205\304\231\304\207\305\272\305\274\305\204 bar
yields
foo åäö ąęćźżń bar
or, more realistically, from a message I got earlier today,
Filip powiedzia\305\202 \305\274e zap\305\202aci jutro
becomes
Filip powiedział że zapłaci jutro
Invalid/non-printable sequences get processed as before.
Line reading in write must become getline() to avoid dealing with
partial characters: for example on input consisting solely of
ąęćźżń, where every {1} is an instance, the output would be
{42}ąęć\305\272żń{84}ąęćź\305\274ń{84}ąęćźż\305\204{39}
with just fixed-512 fgets()
Bug-Debian: https://bugs.debian.org/826596
CVE: CVE-2024-28085
Upstream-Status: Backport [https://github.com/util-linux/util-linux/commit/8a7b8456d1dc0e7ca557d1ac31f638986704757f]
Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
---
include/carefulputc.h | 62 +++++++++++++++++++++++++++++++------------
login-utils/last.c | 4 +--
term-utils/write.c | 25 +++++------------
3 files changed, 53 insertions(+), 38 deletions(-)
diff --git a/include/carefulputc.h b/include/carefulputc.h
index 66a0f15..2506614 100644
--- a/include/carefulputc.h
+++ b/include/carefulputc.h
@@ -1,31 +1,59 @@
#ifndef UTIL_LINUX_CAREFULPUTC_H
#define UTIL_LINUX_CAREFULPUTC_H
-/*
- * A putc() for use in write and wall (that sometimes are sgid tty).
- * It avoids control characters in our locale, and also ASCII control
- * characters. Note that the locale of the recipient is unknown.
-*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
+#ifdef HAVE_WIDECHAR
+#include <wctype.h>
+#endif
+#include <stdbool.h>
#include "cctype.h"
-static inline int fputc_careful(int c, FILE *fp, const char fail)
+/*
+ * A puts() for use in write and wall (that sometimes are sgid tty).
+ * It avoids control and invalid characters.
+ * The locale of the recipient is nominally unknown,
+ * but it's a solid bet that the encoding is compatible with the author's.
+ */
+static inline int fputs_careful(const char * s, FILE *fp, const char ctrl, bool cr_lf)
{
- int ret;
-
- if (isprint(c) || c == '\a' || c == '\t' || c == '\r' || c == '\n')
- ret = putc(c, fp);
- else if (!c_isascii(c))
- ret = fprintf(fp, "\\%3o", (unsigned char)c);
- else {
- ret = putc(fail, fp);
- if (ret != EOF)
- ret = putc(c ^ 0x40, fp);
+ int ret = 0;
+
+ for (size_t slen = strlen(s); *s; ++s, --slen) {
+ if (*s == '\n')
+ ret = fputs(cr_lf ? "\r\n" : "\n", fp);
+ else if (isprint(*s) || *s == '\a' || *s == '\t' || *s == '\r')
+ ret = putc(*s, fp);
+ else if (!c_isascii(*s)) {
+#ifdef HAVE_WIDECHAR
+ wchar_t w;
+ size_t clen = mbtowc(&w, s, slen);
+ switch(clen) {
+ case (size_t)-2: // incomplete
+ case (size_t)-1: // EILSEQ
+ mbtowc(NULL, NULL, 0);
+ nonprint:
+ ret = fprintf(fp, "\\%3hho", *s);
+ break;
+ default:
+ if(!iswprint(w))
+ goto nonprint;
+ ret = fwrite(s, 1, clen, fp);
+ s += clen - 1;
+ slen -= clen - 1;
+ break;
+ }
+#else
+ ret = fprintf(fp, "\\%3hho", *s);
+#endif
+ } else
+ ret = fputs((char[]){ ctrl, *s ^ 0x40, '\0' }, fp);
+ if (ret < 0)
+ return EOF;
}
- return (ret < 0) ? EOF : 0;
+ return 0;
}
static inline void fputs_quoted_case(const char *data, FILE *out, int dir)
diff --git a/login-utils/last.c b/login-utils/last.c
index f3272ca..aacd1f6 100644
--- a/login-utils/last.c
+++ b/login-utils/last.c
@@ -403,7 +403,6 @@ static int list(const struct last_control *ctl, struct utmpx *p, time_t logout_t
char final[512];
char utline[sizeof(p->ut_line) + 1];
char domain[256];
- char *s;
int mins, hours, days;
int r, len;
struct last_timefmt *fmt;
@@ -559,8 +558,7 @@ static int list(const struct last_control *ctl, struct utmpx *p, time_t logout_t
/*
* Print out "final" string safely.
*/
- for (s = final; *s; s++)
- fputc_careful(*s, stdout, '*');
+ fputs_careful(final, stdout, '*', false);
if (len < 0 || (size_t)len >= sizeof(final))
putchar('\n');
diff --git a/term-utils/write.c b/term-utils/write.c
index 50f18dc..710a58c 100644
--- a/term-utils/write.c
+++ b/term-utils/write.c
@@ -223,21 +223,6 @@ static void signal_handler(int signo)
signal_received = signo;
}
-/*
- * write_line - like fputs(), but makes control characters visible and
- * turns \n into \r\n.
- */
-static void write_line(char *s)
-{
- while (*s) {
- const int c = *s++;
-
- if ((c == '\n' && fputc_careful('\r', stdout, '^') == EOF)
- || fputc_careful(c, stdout, '^') == EOF)
- err(EXIT_FAILURE, _("carefulputc failed"));
- }
-}
-
/*
* do_write - actually make the connection
*/
@@ -247,7 +232,8 @@ static void do_write(const struct write_control *ctl)
struct passwd *pwd;
time_t now;
struct tm *tm;
- char *host, line[512];
+ char *host, *line = NULL;
+ size_t linelen = 0;
struct sigaction sigact;
/* Determine our login name(s) before the we reopen() stdout */
@@ -286,11 +272,14 @@ static void do_write(const struct write_control *ctl)
free(host);
printf("\r\n");
- while (fgets(line, sizeof(line), stdin) != NULL) {
+ while (getline(&line, &linelen, stdin) >= 0) {
if (signal_received)
break;
- write_line(line);
+
+ if (fputs_careful(line, stdout, '^', true) == EOF)
+ err(EXIT_FAILURE, _("carefulputc failed"));
}
+ free(line);
printf("EOF\r\n");
}
--
2.40.0