mirror of
https://git.yoctoproject.org/poky
synced 2026-03-14 11:19:42 +01:00
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>
203 lines
5.9 KiB
Diff
203 lines
5.9 KiB
Diff
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
|