bump(main/screen): 5.0.1

This commit is contained in:
termux-pacman-bot
2025-05-15 13:44:37 +00:00
parent 30455c5a00
commit 0850bb2db2
7 changed files with 2 additions and 607 deletions

View File

@@ -1,137 +0,0 @@
From a23f2fa9fbb3cb214ed6a8ab71c99bba94f79e92 Mon Sep 17 00:00:00 2001
From: Alex Naumov <alexander_naumov@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@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

View File

@@ -1,49 +0,0 @@
From 4f1c9e41bae1547077a524241952c244b969645f Mon Sep 17 00:00:00 2001
From: Alex Naumov <alexander_naumov@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@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

View File

@@ -1,60 +0,0 @@
From e61649242afc42213e7fd3bb8b3dbea33be96761 Mon Sep 17 00:00:00 2001
From: Alex Naumov <alexander_naumov@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@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

View File

@@ -1,113 +0,0 @@
From 5a5383b312b2422689ca0220ac1557885b6ce67d Mon Sep 17 00:00:00 2001
From: Matthias Gerstner <matthias.gerstner@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

View File

@@ -1,130 +0,0 @@
From 49473441c17006856268f37249e62a99a7901741 Mon Sep 17 00:00:00 2001
From: Matthias Gerstner <matthias.gerstner@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

View File

@@ -1,115 +0,0 @@
From d993aacb892ee7aa83c0e21174c8b65b191802d5 Mon Sep 17 00:00:00 2001
From: Matthias Gerstner <matthias.gerstner@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

View File

@@ -2,10 +2,9 @@ TERMUX_PKG_HOMEPAGE=https://www.gnu.org/software/screen/
TERMUX_PKG_DESCRIPTION="Terminal multiplexer with VT100/ANSI terminal emulation"
TERMUX_PKG_LICENSE="GPL-3.0"
TERMUX_PKG_MAINTAINER="@termux"
TERMUX_PKG_VERSION="5.0.0"
TERMUX_PKG_REVISION=3
TERMUX_PKG_VERSION="5.0.1"
TERMUX_PKG_SRCURL=https://mirrors.kernel.org/gnu/screen/screen-${TERMUX_PKG_VERSION}.tar.gz
TERMUX_PKG_SHA256=f04a39d00a0e5c7c86a55338808903082ad5df4d73df1a2fd3425976aed94971
TERMUX_PKG_SHA256=bca9b5b9022ca7b8c1a61b503e53ace7dd7cb61eac14e39e7ccbc0b139495d49
# libandroid-support is necessary as screen uses `wcwidth`, see #22688
TERMUX_PKG_DEPENDS="libandroid-support, ncurses, termux-auth"
TERMUX_PKG_BUILD_DEPENDS="libcrypt"