[packages/screen] Rel 2; security fixes for few issues https://security.opensuse.org/2025/05/12/screen-security-issues
arekm
arekm at pld-linux.org
Mon May 12 23:37:42 CEST 2025
commit 06b56d959517296e2d87a47310d0cf8318096d5e
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date: Mon May 12 23:37:30 2025 +0200
Rel 2; security fixes for few issues https://security.opensuse.org/2025/05/12/screen-security-issues.html
...ntroduce-lf_secreopen-to-fix-CVE-2025-233.patch | 137 +++++++++++++++++++++
...-mode-apply-safe-default-mode-of-0620-to-.patch | 49 ++++++++
...fix-bad-strncpy-which-can-lead-to-a-buffe.patch | 60 +++++++++
...prevent-temporary-0666-mode-on-PTYs-to-fi.patch | 113 +++++++++++++++++
...existence-test-information-leaks-to-fix-C.patch | 130 +++++++++++++++++++
...n-t-send-signals-with-root-privileges-to-.patch | 115 +++++++++++++++++
screen.spec | 29 +++--
7 files changed, 625 insertions(+), 8 deletions(-)
---
diff --git a/screen.spec b/screen.spec
index 9d8aacb..2a2cfc1 100644
--- a/screen.spec
+++ b/screen.spec
@@ -11,7 +11,7 @@ Summary(tr.UTF-8): Bir uçbirimde birden fazla oturumu düzenler
Summary(uk.UTF-8): Менеджер екрану, що підтримує кілька логінів з одного терміналу
Name: screen
Version: 5.0.0
-Release: 1
+Release: 2
License: GPL v3+
Group: Applications/Terminal
Source0: https://ftp.gnu.org/gnu/screen/%{name}-%{version}.tar.gz
@@ -20,6 +20,12 @@ Source1: http://www.mif.pg.gda.pl/homepages/ankry/man-PLD/%{name}-non-english-ma
# Source1-md5: 236166e774cee788cf594b05dd1dd70d
Source2: %{name}.pamd
Source3: %{name}rc
+Patch100: 0001-logfile-reintroduce-lf_secreopen-to-fix-CVE-2025-233.patch
+Patch101: 0002-default-PTY-mode-apply-safe-default-mode-of-0620-to-.patch
+Patch102: 0003-attacher.c-fix-bad-strncpy-which-can-lead-to-a-buffe.patch
+Patch103: 0004-attacher.c-prevent-temporary-0666-mode-on-PTYs-to-fi.patch
+Patch104: 0005-Avoid-file-existence-test-information-leaks-to-fix-C.patch
+Patch105: 0006-socket.c-don-t-send-signals-with-root-privileges-to-.patch
Patch2: %{name}-manual.patch
Patch4: %{name}-info.patch
Patch7: %{name}-no_hardcoded_term_sequences.patch
@@ -92,16 +98,23 @@ Screen корисний користувачам, які заходять на
%prep
%setup -q
-%patch2 -p1
-%patch4 -p1
+%patch -P2 -p1
+%patch -P4 -p1
# DON'T ENABLE IT UNLESS YOU REALLY FIX IT
# (it's heavily broken - note that some sequences should be get for
# $TERM before running screen instance, and others for TERM=screen!)
-###%patch7 -p1
-#%patch8 -p1
-%patch12 -p1
-#%patch13 -p1 # my brain farted here, see if you have better luck
-%patch18 -p1
+###%%patch -P7 -p1
+#%%patch -P8 -p1
+%patch -P12 -p1
+#%%patch -P13 -p1 # my brain farted here, see if you have better luck
+%patch -P18 -p1
+
+%patch -P100 -p1
+%patch -P101 -p1
+%patch -P102 -p1
+%patch -P103 -p1
+%patch -P104 -p1
+%patch -P105 -p1
%build
%{__aclocal}
diff --git a/0001-logfile-reintroduce-lf_secreopen-to-fix-CVE-2025-233.patch b/0001-logfile-reintroduce-lf_secreopen-to-fix-CVE-2025-233.patch
new file mode 100644
index 0000000..37c7043
--- /dev/null
+++ b/0001-logfile-reintroduce-lf_secreopen-to-fix-CVE-2025-233.patch
@@ -0,0 +1,137 @@
+From a23f2fa9fbb3cb214ed6a8ab71c99bba94f79e92 Mon Sep 17 00:00:00 2001
+From: Alex Naumov <alexander_naumov at opensuse.org>
+Date: Wed, 7 May 2025 10:42:55 +0200
+Subject: [PATCH 1/6] logfile: reintroduce lf_secreopen() to fix CVE-2025-23395
+
+In commit 441bca708bd this function was mistakenly removed, which
+introduces a local root exploit vulnerability when running screen in
+setuid-root context.
+
+Committed-By: Matthias Gerstner <matthias.gerstner at suse.de>
+---
+ logfile.c | 27 +++++++++++++++++++++++----
+ logfile.h | 10 ++++++++++
+ screen.c | 19 +++++++++++++++++++
+ 3 files changed, 52 insertions(+), 4 deletions(-)
+
+diff --git a/logfile.c b/logfile.c
+index 65e7205..91dc224 100644
+--- a/logfile.c
++++ b/logfile.c
+@@ -88,10 +88,29 @@ static int logfile_reopen(char *name, int wantfd, Log *l)
+ return -1;
+ }
+ changed_logfile(l);
+- l->st->st_ino = l->st->st_dev = 0;
+ return 0;
+ }
+
++static int (*lf_reopen_fn) (char *, int, struct Log *) = logfile_reopen;
++
++/*
++ * Whenever logfwrite discoveres that it is required to close and
++ * reopen the logfile, the function registered here is called.
++ * If you do not register anything here, the above logfile_reopen()
++ * will be used instead.
++ * Your function should perform the same steps as logfile_reopen():
++ * a) close the original filedescriptor without flushing any output
++ * b) open a new logfile for future output on the same filedescriptor number.
++ * c) zero out st_dev, st_ino to tell the stolen_logfile() indcator to
++ * reinitialise itself.
++ * d) return 0 on success.
++ */
++void logreopen_register(int (*fn) (char *, int, struct Log *))
++{
++ lf_reopen_fn = fn ? fn : logfile_reopen;
++}
++
++
+ /*
+ * If the logfile has been removed, truncated, unlinked or the like,
+ * return nonzero.
+@@ -204,7 +223,7 @@ int logfwrite(Log *l, char *buf, size_t n)
+ {
+ int r;
+
+- if (stolen_logfile(l) && logfile_reopen(l->name, fileno(l->fp), l))
++ if (stolen_logfile(l) && lf_reopen_fn(l->name, fileno(l->fp), l))
+ return -1;
+ r = fwrite(buf, n, 1, l->fp);
+ l->writecount += l->flushcount + 1;
+@@ -219,13 +238,13 @@ int logfflush(Log *l)
+
+ if (!l)
+ for (l = logroot; l; l = l->next) {
+- if (stolen_logfile(l) && logfile_reopen(l->name, fileno(l->fp), l))
++ if (stolen_logfile(l) && lf_reopen_fn(l->name, fileno(l->fp), l))
+ return -1;
+ r |= fflush(l->fp);
+ l->flushcount++;
+ changed_logfile(l);
+ } else {
+- if (stolen_logfile(l) && logfile_reopen(l->name, fileno(l->fp), l))
++ if (stolen_logfile(l) && lf_reopen_fn(l->name, fileno(l->fp), l))
+ return -1;
+ r = fflush(l->fp);
+ l->flushcount++;
+diff --git a/logfile.h b/logfile.h
+index dbc9c2c..569a90e 100644
+--- a/logfile.h
++++ b/logfile.h
+@@ -71,6 +71,16 @@ int logfwrite (Log *, char *, size_t);
+ */
+ int logfflush (Log *ifany);
+
++/*
++ * a reopen function may be registered here, in case you want to bring your
++ * own (more secure open), it may come along with a private data pointer.
++ * this function is called, whenever logfwrite/logfflush detect that the
++ * file has been (re)moved, truncated or changed by someone else.
++ * if you provide NULL as parameter to logreopen_register, the builtin
++ * reopen function will be reactivated.
++ */
++void logreopen_register (int (*fn) (char *, int, struct Log *) );
++
+ /*
+ * Your custom reopen function is required to reuse the exact
+ * filedescriptor.
+diff --git a/screen.c b/screen.c
+index a79c3b1..728e717 100644
+--- a/screen.c
++++ b/screen.c
+@@ -199,6 +199,21 @@ static int GotSigChld;
+ /********************************************************************/
+ /********************************************************************/
+
++static int lf_secreopen(char *name, int wantfd, struct Log *l)
++{
++ int got_fd;
++
++ close(wantfd);
++ if (((got_fd = secopen(name, O_WRONLY | O_CREAT | O_APPEND, 0666)) < 0) || lf_move_fd(got_fd, wantfd) < 0) {
++ logfclose(l);
++ return -1;
++ }
++ l->st->st_ino = l->st->st_dev = 0;
++ return 0;
++}
++
++
++
+ static struct passwd *getpwbyname(char *name, struct passwd *ppp)
+ {
+ int n;
+@@ -349,6 +364,10 @@ int main(int argc, char **argv)
+ #ifdef ENABLE_TELNET
+ af = AF_UNSPEC;
+ #endif
++ /* lf_secreopen() is vital for the secure operation in setuid-root context.
++ * Do not remove it
++ */
++ logreopen_register(lf_secreopen);
+
+ real_uid = getuid();
+ real_gid = getgid();
+--
+2.49.0
+
diff --git a/0002-default-PTY-mode-apply-safe-default-mode-of-0620-to-.patch b/0002-default-PTY-mode-apply-safe-default-mode-of-0620-to-.patch
new file mode 100644
index 0000000..d9f8dab
--- /dev/null
+++ b/0002-default-PTY-mode-apply-safe-default-mode-of-0620-to-.patch
@@ -0,0 +1,49 @@
+From 4f1c9e41bae1547077a524241952c244b969645f Mon Sep 17 00:00:00 2001
+From: Alex Naumov <alexander_naumov at opensuse.org>
+Date: Wed, 7 May 2025 10:45:30 +0200
+Subject: [PATCH 2/6] default PTY mode: apply safe default mode of 0620 to fix
+ CVE-2025-46803
+
+During refactoring of configure.ac the default PTY mode was changed from
+0620 to 0622 without documenting this change. Packagers that don't pass
+an explicit `--with-pty-mode=0620` will end up with world-writable PTYs.
+Revert the default back of 0620 to provide a safe default again.
+
+Committed-By: Matthias Gerstner <matthias.gerstner at suse.de>
+---
+ configure.ac | 4 ++--
+ process.c | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 976b1e0..34caf99 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -117,9 +117,9 @@ AC_ARG_WITH(system_screenrc, AS_HELP_STRING([--with-system_screenrc],
+ [with_system_screenrc=$withval],
+ [with_system_screenrc=/etc/screenrc])
+ AC_ARG_WITH(pty-mode, AS_HELP_STRING([--with-pty-mode],
+- [set pty mode (default: 0622)]),
++ [set pty mode (default: 0620)]),
+ [with_pty_mode=$withval],
+- [with_pty_mode=0622])
++ [with_pty_mode=0620])
+ AC_ARG_WITH(pty-group, AS_HELP_STRING([--with-pty-group],
+ [set pty group (default: 5)]),
+ [with_pty_group=$withval],
+diff --git a/process.c b/process.c
+index 470e70a..3912803 100644
+--- a/process.c
++++ b/process.c
+@@ -117,7 +117,7 @@ char NullStr[] = "";
+ struct plop plop_tab[MAX_PLOP_DEFS];
+
+ #ifndef PTY_MODE
+-#define PTY_MODE 0622
++#define PTY_MODE 0620
+ #endif
+
+ int TtyMode = PTY_MODE;
+--
+2.49.0
+
diff --git a/0003-attacher.c-fix-bad-strncpy-which-can-lead-to-a-buffe.patch b/0003-attacher.c-fix-bad-strncpy-which-can-lead-to-a-buffe.patch
new file mode 100644
index 0000000..3ad0a01
--- /dev/null
+++ b/0003-attacher.c-fix-bad-strncpy-which-can-lead-to-a-buffe.patch
@@ -0,0 +1,60 @@
+From e61649242afc42213e7fd3bb8b3dbea33be96761 Mon Sep 17 00:00:00 2001
+From: Alex Naumov <alexander_naumov at opensuse.org>
+Date: Wed, 7 May 2025 10:49:24 +0200
+Subject: [PATCH 3/6] attacher.c: fix bad strncpy() which can lead to a buffer
+ overflow
+
+`strncpy()` always pads the destination buffer with zeroes, regardless
+of the length of the input string. Passing `MAXPATHLEN` in every `for`
+loop iteration will cause a buffer write overflow past the end of the
+`m.m.command.cmd` buffer.
+
+This becomes visible on systems that compile Screen with the
+`_FORTIFY_SOURCE` macro enabled when passing more than one parameter,
+for example like this:
+
+```
+screen -S myinstance -X blankerprg /path/to/blanker
+*** buffer overflow detected ***: terminated
+Aborted (core dumped)
+```
+
+This is not security relevant, since only zeroes are written past the
+end of the buffer and only other message buffer fields can be reached,
+no internal state of Screen can be changed.
+
+Committed-By: Matthias Gerstner <matthias.gerstner at suse.de>
+---
+ attacher.c | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+diff --git a/attacher.c b/attacher.c
+index d8de9d4..4e1a77e 100644
+--- a/attacher.c
++++ b/attacher.c
+@@ -457,13 +457,16 @@ void SendCmdMessage(char *sty, char *match, char **av, int query)
+ }
+ p = m.m.command.cmd;
+ n = 0;
++ size_t space_left = ARRAY_SIZE(m.m.command.cmd);
++
+ for (; *av && n < MAXARGS - 1; ++av, ++n) {
+- size_t len;
+- len = strlen(*av) + 1;
+- if (p + len >= m.m.command.cmd + ARRAY_SIZE(m.m.command.cmd) - 1)
+- break;
+- strncpy(p, *av, MAXPATHLEN);
+- p += len;
++ int printed = snprintf(p, space_left, "%s", *av);
++ if (printed < 0 || (size_t)printed >= space_left)
++ Panic(0, "Total length of the command to send too large.\n");
++
++ printed += 1; // add null terminator
++ p += printed;
++ space_left -= printed;
+ }
+ *p = 0;
+ m.m.command.nargs = n;
+--
+2.49.0
+
diff --git a/0004-attacher.c-prevent-temporary-0666-mode-on-PTYs-to-fi.patch b/0004-attacher.c-prevent-temporary-0666-mode-on-PTYs-to-fi.patch
new file mode 100644
index 0000000..b2ae38d
--- /dev/null
+++ b/0004-attacher.c-prevent-temporary-0666-mode-on-PTYs-to-fi.patch
@@ -0,0 +1,113 @@
+From 5a5383b312b2422689ca0220ac1557885b6ce67d Mon Sep 17 00:00:00 2001
+From: Matthias Gerstner <matthias.gerstner at suse.de>
+Date: Wed, 7 May 2025 10:56:17 +0200
+Subject: [PATCH 4/6] attacher.c: prevent temporary 0666 mode on PTYs to fix
+ CVE-2025-46802
+
+This temporary chmod of the PTY to mode 0666 is most likely a remnant of
+past times, before the PTY file descriptor was passed to the target
+session via the UNIX domain socket.
+
+This chmod() causes a race condition during which any other user in the
+system can open the PTY for reading and writing, and thus allows PTY
+hijacking.
+
+Simply remove this logic completely.
+---
+ attacher.c | 14 --------------
+ screen.c | 12 ------------
+ screen.h | 2 --
+ 3 files changed, 28 deletions(-)
+
+diff --git a/attacher.c b/attacher.c
+index 4e1a77e..e5a48b0 100644
+--- a/attacher.c
++++ b/attacher.c
+@@ -127,9 +127,6 @@ int Attach(int how)
+ xseteuid(multi_uid);
+ xseteuid(own_uid);
+ #endif
+- if (chmod(attach_tty, 0666))
+- Panic(errno, "chmod %s", attach_tty);
+- tty_oldmode = tty_mode;
+ }
+
+ memset((char *)&m, 0, sizeof(Message));
+@@ -279,12 +276,6 @@ int Attach(int how)
+ pause(); /* wait for SIGCONT */
+ xsignal(SIGCONT, SIG_DFL);
+ ContinuePlease = false;
+- xseteuid(own_uid);
+- if (tty_oldmode >= 0)
+- if (chmod(attach_tty, tty_oldmode))
+- Panic(errno, "chmod %s", attach_tty);
+- tty_oldmode = -1;
+- xseteuid(real_uid);
+ }
+ rflag = 0;
+ return 1;
+@@ -334,11 +325,6 @@ void AttacherFinit(int sigsig)
+ close(s);
+ }
+ }
+- if (tty_oldmode >= 0) {
+- if (setuid(own_uid))
+- Panic(errno, "setuid");
+- chmod(attach_tty, tty_oldmode);
+- }
+ exit(0);
+ }
+
+diff --git a/screen.c b/screen.c
+index 728e717..fb61c7f 100644
+--- a/screen.c
++++ b/screen.c
+@@ -145,8 +145,6 @@ bool hastruecolor = false;
+
+ char *multi;
+ int multiattach;
+-int tty_mode;
+-int tty_oldmode = -1;
+
+ char HostName[MAXSTR];
+ pid_t MasterPid;
+@@ -766,7 +764,6 @@ int main(int argc, char **argv)
+
+ /* ttyname implies isatty */
+ SetTtyname(true, &st);
+- tty_mode = (int)st.st_mode & 0777;
+
+ fl = fcntl(0, F_GETFL, 0);
+ if (fl != -1 && (fl & (O_RDWR | O_RDONLY | O_WRONLY)) == O_RDWR)
+@@ -1570,15 +1567,6 @@ void Panic(int err, const char *fmt, ...)
+ if (D_userpid)
+ Kill(D_userpid, SIG_BYE);
+ }
+- if (tty_oldmode >= 0) {
+-#if defined(HAVE_SETEUID)
+- if (setuid(own_uid))
+- xseteuid(own_uid); /* may be a loop. sigh. */
+-#else
+- setuid(own_uid);
+-#endif
+- chmod(attach_tty, tty_oldmode);
+- }
+ eexit(1);
+ }
+
+diff --git a/screen.h b/screen.h
+index 308c365..410b4f4 100644
+--- a/screen.h
++++ b/screen.h
+@@ -291,8 +291,6 @@ extern int nversion;
+ extern uid_t own_uid;
+ extern int queryflag;
+ extern int rflag;
+-extern int tty_mode;
+-extern int tty_oldmode;
+ extern pid_t MasterPid;
+ extern int MsgMinWait;
+ extern int MsgWait;
+--
+2.49.0
+
diff --git a/0005-Avoid-file-existence-test-information-leaks-to-fix-C.patch b/0005-Avoid-file-existence-test-information-leaks-to-fix-C.patch
new file mode 100644
index 0000000..2aeab06
--- /dev/null
+++ b/0005-Avoid-file-existence-test-information-leaks-to-fix-C.patch
@@ -0,0 +1,130 @@
+From 49473441c17006856268f37249e62a99a7901741 Mon Sep 17 00:00:00 2001
+From: Matthias Gerstner <matthias.gerstner at suse.de>
+Date: Wed, 7 May 2025 11:25:25 +0200
+Subject: [PATCH 5/6] Avoid file existence test information leaks to fix
+ CVE-2025-46804
+
+In setuid-root context the current error messages give away whether
+certain paths not accessible by the real user exist and what type they
+have. To prevent this only output generic error messages in setuid-root
+context.
+
+In some situations, when an error is pertaining a directory and the
+directory is owner by the real user then we can still output more
+detailed diagnostics.
+
+This change can lead to less helpful error messages when Screen is
+install setuid-root. More complex changes would be needed to avoid this
+(e.g. only open the `SocketPath` with raised privileges when
+multi-attach is requested).
+
+There might still be lingering some code paths that allow such
+information leaks, since `SocketPath` is a global variable that is used
+across the code base. The majority of issues should be caught with this
+fix, however.
+---
+ screen.c | 54 ++++++++++++++++++++++++++++++++++++++++++------------
+ socket.c | 9 +++++++--
+ 2 files changed, 49 insertions(+), 14 deletions(-)
+
+diff --git a/screen.c b/screen.c
+index fb61c7f..eabbdc2 100644
+--- a/screen.c
++++ b/screen.c
+@@ -862,22 +862,47 @@ int main(int argc, char **argv)
+ #endif
+ }
+
+- if (stat(SocketPath, &st) == -1)
+- Panic(errno, "Cannot access %s", SocketPath);
+- else if (!S_ISDIR(st.st_mode))
+- Panic(0, "%s is not a directory.", SocketPath);
++ if (stat(SocketPath, &st) == -1) {
++ if (eff_uid == real_uid) {
++ Panic(errno, "Cannot access %s", SocketPath);
++ } else {
++ Panic(0, "Error accessing %s", SocketPath);
++ }
++ }
++ else if (!S_ISDIR(st.st_mode)) {
++ if (eff_uid == real_uid || st.st_uid == real_uid) {
++ Panic(0, "%s is not a directory.", SocketPath);
++ } else {
++ Panic(0, "Error accessing %s", SocketPath);
++ }
++ }
+ if (multi) {
+- if (st.st_uid != multi_uid)
+- Panic(0, "%s is not the owner of %s.", multi, SocketPath);
++ if (st.st_uid != multi_uid) {
++ if (eff_uid == real_uid || st.st_uid == real_uid) {
++ Panic(0, "%s is not the owner of %s.", multi, SocketPath);
++ } else {
++ Panic(0, "Error accessing %s", SocketPath);
++ }
++ }
+ } else {
+ #ifdef SOCKET_DIR /* if SOCKETDIR is not defined, the socket is in $HOME.
+ in that case it does not make sense to compare uids. */
+- if (st.st_uid != real_uid)
+- Panic(0, "You are not the owner of %s.", SocketPath);
++ if (st.st_uid != real_uid) {
++ if (eff_uid == real_uid) {
++ Panic(0, "You are not the owner of %s.", SocketPath);
++ } else {
++ Panic(0, "Error accessing %s", SocketPath);
++ }
++ }
+ #endif
+ }
+- if ((st.st_mode & 0777) != 0700)
+- Panic(0, "Directory %s must have mode 700.", SocketPath);
++ if ((st.st_mode & 0777) != 0700) {
++ if (eff_uid == real_uid || st.st_uid == real_uid) {
++ Panic(0, "Directory %s must have mode 700.", SocketPath);
++ } else {
++ Panic(0, "Error accessing %s", SocketPath);
++ }
++ }
+ if (SocketMatch && strchr(SocketMatch, '/'))
+ Panic(0, "Bad session name '%s'", SocketMatch);
+ SocketName = SocketPath + strlen(SocketPath) + 1;
+@@ -902,8 +927,13 @@ int main(int argc, char **argv)
+ else
+ exit(9 + (fo || oth ? 1 : 0) + fo);
+ }
+- if (fo == 0)
+- Panic(0, "No Sockets found in %s.\n", SocketPath);
++ if (fo == 0) {
++ if (eff_uid == real_uid || st.st_uid == real_uid) {
++ Panic(0, "No Sockets found in %s.\n", SocketPath);
++ } else {
++ Panic(0, "Error accessing %s", SocketPath);
++ }
++ }
+ Msg(0, "%d Socket%s in %s.", fo, fo > 1 ? "s" : "", SocketPath);
+ eexit(0);
+ }
+diff --git a/socket.c b/socket.c
+index 5709a24..d0b361a 100644
+--- a/socket.c
++++ b/socket.c
+@@ -148,8 +148,13 @@ int FindSocket(int *fdp, int *nfoundp, int *notherp, char *match)
+ xseteuid(real_uid);
+ xsetegid(real_gid);
+
+- if ((dirp = opendir(SocketPath)) == NULL)
+- Panic(errno, "Cannot opendir %s", SocketPath);
++ if ((dirp = opendir(SocketPath)) == NULL) {
++ if (eff_uid == real_uid) {
++ Panic(errno, "Cannot opendir %s", SocketPath);
++ } else {
++ Panic(0, "Error accessing %s", SocketPath);
++ }
++ }
+
+ slist = NULL;
+ slisttail = &slist;
+--
+2.49.0
+
diff --git a/0006-socket.c-don-t-send-signals-with-root-privileges-to-.patch b/0006-socket.c-don-t-send-signals-with-root-privileges-to-.patch
new file mode 100644
index 0000000..b24b2c0
--- /dev/null
+++ b/0006-socket.c-don-t-send-signals-with-root-privileges-to-.patch
@@ -0,0 +1,115 @@
+From d993aacb892ee7aa83c0e21174c8b65b191802d5 Mon Sep 17 00:00:00 2001
+From: Matthias Gerstner <matthias.gerstner at suse.de>
+Date: Wed, 7 May 2025 12:30:39 +0200
+Subject: [PATCH 6/6] socket.c: don't send signals with root privileges to fix
+ CVE-2025-46805
+
+The CheckPid() function was introduced to address CVE-2023-24626, to
+prevent sending SIGCONT and SIGHUP to arbitrary PIDs in the system. This
+fix still suffers from a TOCTOU race condition. The client can replace
+itself by a privileged process, or try to cycle PIDs until a privileged
+process receives the original PID.
+
+To prevent this, always send signals using the real privileges. Keep
+CheckPid() for error diagnostics. If sending the actual signal fails
+later on then there will be no more error reporting.
+
+It seems the original bugfix already introduced a regression when
+attaching to another's user session that is not owned by root. In this
+case the target sessions runs with real uid X, while for sending a
+signal to the `pid` provided by the client real uid Y (or root
+privileges) are required.
+
+This is hard to properly fix without this regression. On Linux pidfds
+could be used to allow safely sending signals to other PIDs as root
+without involving race conditions. In this case the client PID should
+also be obtained via the UNIX domain socket's SO_PEERCRED option,
+though.
+---
+ socket.c | 21 +++++++++++++--------
+ 1 file changed, 13 insertions(+), 8 deletions(-)
+
+diff --git a/socket.c b/socket.c
+index d0b361a..c715519 100644
+--- a/socket.c
++++ b/socket.c
+@@ -91,6 +91,11 @@ static void AskPassword(Message *);
+ static bool CheckPassword(const char *password);
+ static void PasswordProcessInput(char *, size_t);
+
++static void KillUnpriv(pid_t pid, int sig) {
++ UserContext();
++ UserReturn(kill(pid, sig));
++}
++
+ #define SOCKMODE (S_IWRITE | S_IREAD | (displays ? S_IEXEC : 0) | (multi ? 1 : 0))
+
+ /*
+@@ -611,7 +616,7 @@ static int CreateTempDisplay(Message *m, int recvfd, Window *win)
+ Msg(errno, "Could not perform necessary sanity "
+ "checks on pts device.");
+ close(i);
+- Kill(pid, SIG_BYE);
++ KillUnpriv(pid, SIG_BYE);
+ return -1;
+ }
+ if (strcmp(ttyname_in_ns, m->m_tty)) {
+@@ -620,7 +625,7 @@ static int CreateTempDisplay(Message *m, int recvfd, Window *win)
+ ttyname_in_ns,
+ m->m_tty[0] != '\0' ? m->m_tty : "(null)");
+ close(i);
+- Kill(pid, SIG_BYE);
++ KillUnpriv(pid, SIG_BYE);
+ return -1;
+ }
+ /* m->m_tty so far contains the actual name of the pts
+@@ -638,24 +643,24 @@ static int CreateTempDisplay(Message *m, int recvfd, Window *win)
+ "Attach: passed fd does not match tty: %s - %s!",
+ m->m_tty, myttyname ? myttyname : "NULL");
+ close(i);
+- Kill(pid, SIG_BYE);
++ KillUnpriv(pid, SIG_BYE);
+ return -1;
+ }
+ } else if ((i = secopen(m->m_tty, O_RDWR | O_NONBLOCK, 0)) < 0) {
+ Msg(errno, "Attach: Could not open %s!", m->m_tty);
+- Kill(pid, SIG_BYE);
++ KillUnpriv(pid, SIG_BYE);
+ return -1;
+ }
+
+ if (attach)
+- Kill(pid, SIGCONT);
++ KillUnpriv(pid, SIGCONT);
+
+ if (attach) {
+ if (display || win) {
+ int unused_result = write(i, "Attaching from inside of screen?\n", 33);
+ (void)unused_result; /* unused */
+ close(i);
+- Kill(pid, SIG_BYE);
++ KillUnpriv(pid, SIG_BYE);
+ Msg(0, "Attach msg ignored: coming from inside.");
+ return -1;
+ }
+@@ -678,7 +683,7 @@ static int CreateTempDisplay(Message *m, int recvfd, Window *win)
+ (void)unused_result; /* unused */
+ close(i);
+ Msg(0, "Attach: could not make display for user %s", user);
+- Kill(pid, SIG_BYE);
++ KillUnpriv(pid, SIG_BYE);
+ return -1;
+ }
+ if (attach) {
+@@ -884,7 +889,7 @@ void ReceiveMsg(void)
+ Msg(0, "Query attempt with bad pid(%d)!", m.m.command.apid);
+ }
+ else {
+- Kill(m.m.command.apid, (queryflag >= 0) ? SIGCONT : SIG_BYE); /* Send SIG_BYE if an error happened */
++ KillUnpriv(m.m.command.apid, (queryflag >= 0) ? SIGCONT : SIG_BYE); /* Send SIG_BYE if an error happened */
+ queryflag = -1;
+ }
+ }
+--
+2.49.0
+
================================================================
---- gitweb:
http://git.pld-linux.org/gitweb.cgi/packages/screen.git/commitdiff/06b56d959517296e2d87a47310d0cf8318096d5e
More information about the pld-cvs-commit
mailing list