Compare commits
10 Commits
2f4d35adb1
...
b5579133e8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5579133e8 | ||
|
|
67a74408d0 | ||
|
|
0d0f8edec9 | ||
|
|
38e7f1e2fa | ||
|
|
6aff24a439 | ||
|
|
32e9f5e7c8 | ||
|
|
8b88b8a47f | ||
|
|
e0f7944170 | ||
|
|
2e0d9d82fd | ||
|
|
efb33c4dd8 |
225
backport-Avoid-using-ioctl-TIOCNOTTY-in-the-monitor.patch
Normal file
225
backport-Avoid-using-ioctl-TIOCNOTTY-in-the-monitor.patch
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
From a2d01a957d31e133c37d77ae149527f9483e4f19 Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Todd C. Miller" <Todd.Miller@sudo.ws>
|
||||||
|
Date: Sun, 28 Apr 2024 10:28:32 -0600
|
||||||
|
Subject: [PATCH] Avoid using ioctl(TIOCNOTTY) in the monitor.
|
||||||
|
|
||||||
|
We don't need to revoke the terminal in the monitor, just signal
|
||||||
|
the foreground process group. This is more portable and has the
|
||||||
|
same effect as ioctl(TIOCNOTTY) would on Linux. Since we now signal
|
||||||
|
the command from the monitor, there is no reason to forward SIGHUP
|
||||||
|
from the kernel. GitHub issue #367.
|
||||||
|
|
||||||
|
Reference:https://github.com/sudo-project/sudo/commit/a2d01a957d31e133c37d77ae149527f9483e4f19
|
||||||
|
Conflict:src/exec_monitor.c src/exec_pty.c
|
||||||
|
|
||||||
|
---
|
||||||
|
src/exec_monitor.c | 84 +++++++++++++++++++++++++---------------------
|
||||||
|
src/exec_pty.c | 31 ++++++++++-------
|
||||||
|
src/sudo.h | 2 +-
|
||||||
|
3 files changed, 64 insertions(+), 53 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/exec_monitor.c b/src/exec_monitor.c
|
||||||
|
index c570b5d86..524f5c8c9 100644
|
||||||
|
--- a/src/exec_monitor.c
|
||||||
|
+++ b/src/exec_monitor.c
|
||||||
|
@@ -1,7 +1,7 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: ISC
|
||||||
|
*
|
||||||
|
- * Copyright (c) 2009-2021 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||||
|
+ * Copyright (c) 2009-2024 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@@ -310,6 +310,48 @@ mon_errsock_cb(int fd, int what, void *v)
|
||||||
|
debug_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Called when the user's terminal has gone away but before our pty is
|
||||||
|
+ * actually revoked. We simulate the effect of ioctl(TIOCNOTTY) on Linux
|
||||||
|
+ * by sending SIGHUP and SIGCONT to the foreground process group.
|
||||||
|
+ */
|
||||||
|
+static void
|
||||||
|
+mon_handle_revoke(int fd, pid_t cmnd_pid, struct command_status *cstat)
|
||||||
|
+{
|
||||||
|
+ debug_decl(mon_handle_revoke, SUDO_DEBUG_EXEC);
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Signal the foreground process group and the command's process group
|
||||||
|
+ * (if different). We must do this before the pty is revoked be the
|
||||||
|
+ * main sudo process so we can determine the foreground process group.
|
||||||
|
+ * Otherwise, if the foreground process group is different from the
|
||||||
|
+ * command's process group it will not be signaled.
|
||||||
|
+ */
|
||||||
|
+ if (io_fds[SFD_FOLLOWER] != -1) {
|
||||||
|
+ const pid_t pgrp = tcgetpgrp(io_fds[SFD_FOLLOWER]);
|
||||||
|
+ if (pgrp != -1 && pgrp != cmnd_pid) {
|
||||||
|
+ sudo_debug_printf(SUDO_DEBUG_NOTICE, "%s: killpg(%d, SIGHUP)",
|
||||||
|
+ __func__, pgrp);
|
||||||
|
+ killpg(pgrp, SIGHUP);
|
||||||
|
+ sudo_debug_printf(SUDO_DEBUG_NOTICE, "%s: killpg(%d, SIGCONT)",
|
||||||
|
+ __func__, pgrp);
|
||||||
|
+ killpg(pgrp, SIGCONT);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ sudo_debug_printf(SUDO_DEBUG_NOTICE, "%s: killpg(%d, SIGHUP)",
|
||||||
|
+ __func__, cmnd_pid);
|
||||||
|
+ killpg(cmnd_pid, SIGHUP);
|
||||||
|
+ sudo_debug_printf(SUDO_DEBUG_NOTICE, "%s: killpg(%d, SIGCONT)",
|
||||||
|
+ __func__, cmnd_pid);
|
||||||
|
+ killpg(cmnd_pid, SIGCONT);
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Now that the running command as been signaled, tell the
|
||||||
|
+ * parent it is OK to close the pty leader, revoking the pty.
|
||||||
|
+ */
|
||||||
|
+ send_status(fd, cstat);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void
|
||||||
|
mon_backchannel_cb(int fd, int what, void *v)
|
||||||
|
{
|
||||||
|
@@ -337,44 +379,8 @@ mon_backchannel_cb(int fd, int what, void *v)
|
||||||
|
sudo_ev_loopbreak(mc->evbase);
|
||||||
|
} else {
|
||||||
|
switch (cstmp.type) {
|
||||||
|
- case CMD_IOCTL:
|
||||||
|
- if (cstmp.val != TIOCNOTTY) {
|
||||||
|
- sudo_warnx(U_("unexpected ioctl on backchannel: %d"),
|
||||||
|
- cstmp.val);
|
||||||
|
- } else if (io_fds[SFD_FOLLOWER] != -1) {
|
||||||
|
- int result, ttyfd;
|
||||||
|
-
|
||||||
|
- /*
|
||||||
|
- * Parent asks us to revoke the terminal when the
|
||||||
|
- * user's terminal goes away. Doing this in the
|
||||||
|
- * monitor allows the foreground command to receive
|
||||||
|
- * SIGHUP before the terminal is revoked.
|
||||||
|
- */
|
||||||
|
- result = ioctl(io_fds[SFD_FOLLOWER], TIOCNOTTY, NULL);
|
||||||
|
- if (result == -1) {
|
||||||
|
- sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||||
|
- "%s: unable to revoke follower pty", __func__);
|
||||||
|
- ttyfd = open(_PATH_TTY, O_RDWR);
|
||||||
|
- if (ttyfd != -1) {
|
||||||
|
- result = ioctl(ttyfd, TIOCNOTTY, NULL);
|
||||||
|
- if (result == -1) {
|
||||||
|
- sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||||
|
- "%s: unable to revoke controlling tty",
|
||||||
|
- __func__);
|
||||||
|
- }
|
||||||
|
- close(ttyfd);
|
||||||
|
- } else {
|
||||||
|
- sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||||
|
- "%s: unable to open %s", __func__, _PATH_TTY);
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- if (result == 0) {
|
||||||
|
- sudo_debug_printf(SUDO_DEBUG_INFO,
|
||||||
|
- "%s: revoked controlling tty for session", __func__);
|
||||||
|
- }
|
||||||
|
- /* Now tell the parent to close the pty leader. */
|
||||||
|
- send_status(fd, &cstmp);
|
||||||
|
- }
|
||||||
|
+ case CMD_REVOKE:
|
||||||
|
+ mon_handle_revoke(fd, mc->cmnd_pid, &cstmp);
|
||||||
|
break;
|
||||||
|
case CMD_SIGNO:
|
||||||
|
deliver_signal(mc, cstmp.val, true);
|
||||||
|
diff --git a/src/exec_pty.c b/src/exec_pty.c
|
||||||
|
index fff9b8f1e..4dd5915ed 100644
|
||||||
|
--- a/src/exec_pty.c
|
||||||
|
+++ b/src/exec_pty.c
|
||||||
|
@@ -1,7 +1,7 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: ISC
|
||||||
|
*
|
||||||
|
- * Copyright (c) 2009-2021 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||||
|
+ * Copyright (c) 2009-2024 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@@ -385,13 +385,13 @@ read_callback(int fd, int what, void *v)
|
||||||
|
/* If writer already consumed the buffer, close it too. */
|
||||||
|
if (iob->wevent != NULL && iob->off == iob->len) {
|
||||||
|
/*
|
||||||
|
- * Don't close the pty leader, it will invalidate the pty.
|
||||||
|
- * We ask the monitor to revoke the pty nicely using TIOCNOTTY.
|
||||||
|
+ * Don't close the pty leader yet, it will invalidate the pty.
|
||||||
|
+ * We ask the monitor to signal the running process first.
|
||||||
|
*/
|
||||||
|
const int wfd = sudo_ev_get_fd(iob->wevent);
|
||||||
|
if (wfd == io_fds[SFD_LEADER]) {
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_NOTICE, "user's tty revoked");
|
||||||
|
- send_command_status(iob->ec, CMD_IOCTL, TIOCNOTTY);
|
||||||
|
+ send_command_status(iob->ec, CMD_REVOKE, 0);
|
||||||
|
} else {
|
||||||
|
safe_close(wfd);
|
||||||
|
}
|
||||||
|
@@ -474,12 +474,12 @@ write_callback(int fd, int what, void *v)
|
||||||
|
if (iob->revent != NULL) {
|
||||||
|
/*
|
||||||
|
* Don't close the pty leader, it will invalidate the pty.
|
||||||
|
- * We ask the monitor to revoke the pty nicely using TIOCNOTTY.
|
||||||
|
+ * We ask the monitor to signal the running process first.
|
||||||
|
*/
|
||||||
|
const int rfd = sudo_ev_get_fd(iob->revent);
|
||||||
|
if (rfd == io_fds[SFD_LEADER]) {
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_NOTICE, "user's tty revoked");
|
||||||
|
- send_command_status(iob->ec, CMD_IOCTL, TIOCNOTTY);
|
||||||
|
+ send_command_status(iob->ec, CMD_REVOKE, 0);
|
||||||
|
} else {
|
||||||
|
safe_close(rfd);
|
||||||
|
}
|
||||||
|
@@ -684,15 +684,11 @@ backchannel_cb(int fd, int what, void *v)
|
||||||
|
sudo_ev_loopbreak(ec->evbase);
|
||||||
|
*ec->cstat = cstat;
|
||||||
|
break;
|
||||||
|
- case CMD_IOCTL:
|
||||||
|
- if (cstat.val != TIOCNOTTY) {
|
||||||
|
- sudo_warnx(U_("unexpected ioctl on backchannel: %d"),
|
||||||
|
- cstat.val);
|
||||||
|
- } else if (io_fds[SFD_LEADER] != -1) {
|
||||||
|
+ case CMD_REVOKE:
|
||||||
|
+ if (io_fds[SFD_LEADER] != -1) {
|
||||||
|
/*
|
||||||
|
* Monitor requests that we revoke the user's terminal.
|
||||||
|
- * This must happen after the monitor has used TIOCNOTTY
|
||||||
|
- * to invalidate the session and gracefully kill the
|
||||||
|
+ * This must happen after the monitor has signaled the
|
||||||
|
* controlling terminal's process group.
|
||||||
|
*/
|
||||||
|
close(io_fds[SFD_LEADER]);
|
||||||
|
@@ -855,6 +851,15 @@ signal_cb_pty(int signo, int what, void *v)
|
||||||
|
case SIGWINCH:
|
||||||
|
sync_ttysize(ec);
|
||||||
|
break;
|
||||||
|
+ case SIGHUP:
|
||||||
|
+ /*
|
||||||
|
+ * Avoid forwarding SIGHUP sent by the kernel, it probably means
|
||||||
|
+ * that the user's terminal was revoked. When we detect that the
|
||||||
|
+ * terminal has been revoked, the monitor will send SIGHUP itself.
|
||||||
|
+ */
|
||||||
|
+ if (!USER_SIGNALED(sc->siginfo))
|
||||||
|
+ break;
|
||||||
|
+ FALLTHROUGH;
|
||||||
|
default:
|
||||||
|
/*
|
||||||
|
* Do not forward signals sent by a process in the command's process
|
||||||
|
diff --git a/src/sudo.h b/src/sudo.h
|
||||||
|
index ca245ca68..d3122ef4e 100644
|
||||||
|
--- a/src/sudo.h
|
||||||
|
+++ b/src/sudo.h
|
||||||
|
@@ -225,7 +225,7 @@ struct command_status {
|
||||||
|
#define CMD_WSTATUS 2
|
||||||
|
#define CMD_SIGNO 3
|
||||||
|
#define CMD_PID 4
|
||||||
|
-#define CMD_IOCTL 5
|
||||||
|
+#define CMD_REVOKE 5
|
||||||
|
int type;
|
||||||
|
int val;
|
||||||
|
};
|
||||||
|
--
|
||||||
|
2.33.0
|
||||||
|
|
||||||
442
backport-CVE-2023-42465.patch
Normal file
442
backport-CVE-2023-42465.patch
Normal file
@ -0,0 +1,442 @@
|
|||||||
|
From 7873f8334c8d31031f8cfa83bd97ac6029309e4f Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Todd C. Miller" <Todd.Miller@sudo.ws>
|
||||||
|
Date: Sat, 9 Sep 2023 14:07:04 -0600
|
||||||
|
Subject: [PATCH] Try to make sudo less vulnerable to ROWHAMMER attacks.
|
||||||
|
|
||||||
|
We now use ROWHAMMER-resistent values for ALLOW, DENY, AUTH_SUCCESS,
|
||||||
|
AUTH_FAILURE, AUTH_ERROR and AUTH_NONINTERACTIVE. In addition, we
|
||||||
|
explicitly test for expected values instead of using a negated test
|
||||||
|
against an error value. In the parser match functions this means
|
||||||
|
explicitly checking for ALLOW or DENY instead of accepting anything
|
||||||
|
that is not set to UNSPEC.
|
||||||
|
|
||||||
|
Thanks to Andrew J. Adiletta, M. Caner Tol, Yarkin Doroz, and Berk
|
||||||
|
Sunar, all affiliated with the Vernam Applied Cryptography and
|
||||||
|
Cybersecurity Lab at Worcester Polytechnic Institute, for the report.
|
||||||
|
Paper preprint: https://arxiv.org/abs/2309.02545
|
||||||
|
|
||||||
|
Reference: https://github.com/sudo-project/sudo/commit/7873f8334c8d31031f8cfa83bd97ac6029309e4f
|
||||||
|
Conflict: passwd.c sudo_auth.h match.c parse.c
|
||||||
|
---
|
||||||
|
plugins/sudoers/auth/passwd.c | 27 ++++++++++-------
|
||||||
|
plugins/sudoers/auth/sudo_auth.c | 51 ++++++++++++++++++++++----------
|
||||||
|
plugins/sudoers/auth/sudo_auth.h | 10 +++----
|
||||||
|
plugins/sudoers/match.c | 25 ++++++++--------
|
||||||
|
plugins/sudoers/parse.c | 6 ++--
|
||||||
|
plugins/sudoers/parse.h | 23 ++++++++++----
|
||||||
|
6 files changed, 92 insertions(+), 50 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/plugins/sudoers/auth/passwd.c b/plugins/sudoers/auth/passwd.c
|
||||||
|
index bb9f2d6..8f163cb 100644
|
||||||
|
--- a/plugins/sudoers/auth/passwd.c
|
||||||
|
+++ b/plugins/sudoers/auth/passwd.c
|
||||||
|
@@ -62,7 +62,7 @@ sudo_passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_c
|
||||||
|
char des_pass[9], *epass;
|
||||||
|
char *pw_epasswd = auth->data;
|
||||||
|
size_t pw_len;
|
||||||
|
- int matched = 0;
|
||||||
|
+ int ret;
|
||||||
|
debug_decl(sudo_passwd_verify, SUDOERS_DEBUG_AUTH);
|
||||||
|
|
||||||
|
/* An empty plain-text password must match an empty encrypted password. */
|
||||||
|
@@ -74,7 +74,7 @@ sudo_passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_c
|
||||||
|
*/
|
||||||
|
pw_len = strlen(pw_epasswd);
|
||||||
|
if (pw_len == DESLEN || HAS_AGEINFO(pw_epasswd, pw_len)) {
|
||||||
|
- strlcpy(des_pass, pass, sizeof(des_pass));
|
||||||
|
+ (void)strlcpy(des_pass, pass, sizeof(des_pass));
|
||||||
|
pass = des_pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -84,29 +84,36 @@ sudo_passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_c
|
||||||
|
* only compare the first DESLEN characters in that case.
|
||||||
|
*/
|
||||||
|
epass = (char *) crypt(pass, pw_epasswd);
|
||||||
|
+ ret = AUTH_FAILURE;
|
||||||
|
if (epass != NULL) {
|
||||||
|
- if (HAS_AGEINFO(pw_epasswd, pw_len) && strlen(epass) == DESLEN)
|
||||||
|
- matched = !strncmp(pw_epasswd, epass, DESLEN);
|
||||||
|
- else
|
||||||
|
- matched = !strcmp(pw_epasswd, epass);
|
||||||
|
+ if (HAS_AGEINFO(pw_epasswd, pw_len) && strlen(epass) == DESLEN) {
|
||||||
|
+ if (strncmp(pw_epasswd, epass, DESLEN) == 0)
|
||||||
|
+ ret = AUTH_SUCCESS;
|
||||||
|
+ } else {
|
||||||
|
+ if (strcmp(pw_epasswd, epass) == 0)
|
||||||
|
+ ret = AUTH_SUCCESS;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit_bzero(des_pass, sizeof(des_pass));
|
||||||
|
|
||||||
|
- debug_return_int(matched ? AUTH_SUCCESS : AUTH_FAILURE);
|
||||||
|
+ debug_return_int(ret);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int
|
||||||
|
sudo_passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback)
|
||||||
|
{
|
||||||
|
char *pw_passwd = auth->data;
|
||||||
|
- int matched;
|
||||||
|
+ int ret;
|
||||||
|
debug_decl(sudo_passwd_verify, SUDOERS_DEBUG_AUTH);
|
||||||
|
|
||||||
|
/* Simple string compare for systems without crypt(). */
|
||||||
|
- matched = !strcmp(pass, pw_passwd);
|
||||||
|
+ if (strcmp(pass, pw_passwd) == 0)
|
||||||
|
+ ret = AUTH_SUCCESS;
|
||||||
|
+ else
|
||||||
|
+ ret = AUTH_FAILURE;
|
||||||
|
|
||||||
|
- debug_return_int(matched ? AUTH_SUCCESS : AUTH_FAILURE);
|
||||||
|
+ debug_return_int(ret);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
diff --git a/plugins/sudoers/auth/sudo_auth.c b/plugins/sudoers/auth/sudo_auth.c
|
||||||
|
index 188b65f..467233a 100644
|
||||||
|
--- a/plugins/sudoers/auth/sudo_auth.c
|
||||||
|
+++ b/plugins/sudoers/auth/sudo_auth.c
|
||||||
|
@@ -112,10 +112,16 @@ sudo_auth_init(struct passwd *pw)
|
||||||
|
if (auth->init && !IS_DISABLED(auth)) {
|
||||||
|
/* Disable if it failed to init unless there was a fatal error. */
|
||||||
|
status = (auth->init)(pw, auth);
|
||||||
|
- if (status == AUTH_FAILURE)
|
||||||
|
+ switch (status) {
|
||||||
|
+ case AUTH_SUCCESS:
|
||||||
|
+ break;
|
||||||
|
+ case AUTH_FAILURE:
|
||||||
|
SET(auth->flags, FLAG_DISABLED);
|
||||||
|
- else if (status == AUTH_FATAL)
|
||||||
|
- break; /* assume error msg already printed */
|
||||||
|
+ break;
|
||||||
|
+ default:
|
||||||
|
+ /* Assume error msg already printed. */
|
||||||
|
+ debug_return_int(-1);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -161,7 +167,7 @@ sudo_auth_init(struct passwd *pw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- debug_return_int(status == AUTH_FATAL ? -1 : 0);
|
||||||
|
+ debug_return_int(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -202,7 +208,7 @@ sudo_auth_cleanup(struct passwd *pw, bool force)
|
||||||
|
for (auth = auth_switch; auth->name; auth++) {
|
||||||
|
if (auth->cleanup && !IS_DISABLED(auth)) {
|
||||||
|
int status = (auth->cleanup)(pw, auth, force);
|
||||||
|
- if (status == AUTH_FATAL) {
|
||||||
|
+ if (status != AUTH_SUCCESS) {
|
||||||
|
/* Assume error msg already printed. */
|
||||||
|
debug_return_int(-1);
|
||||||
|
}
|
||||||
|
@@ -297,7 +303,7 @@ verify_user(struct passwd *pw, char *prompt, int validated,
|
||||||
|
status = (auth->setup)(pw, &prompt, auth);
|
||||||
|
if (status == AUTH_FAILURE)
|
||||||
|
SET(auth->flags, FLAG_DISABLED);
|
||||||
|
- else if (status == AUTH_FATAL || user_interrupted())
|
||||||
|
+ else if (status != AUTH_SUCCESS || user_interrupted())
|
||||||
|
goto done; /* assume error msg already printed */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -348,7 +354,6 @@ done:
|
||||||
|
log_auth_failure(validated, ntries);
|
||||||
|
ret = false;
|
||||||
|
break;
|
||||||
|
- case AUTH_FATAL:
|
||||||
|
default:
|
||||||
|
log_auth_failure(validated, 0);
|
||||||
|
ret = -1;
|
||||||
|
@@ -360,24 +365,32 @@ done:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call authentication method begin session hooks.
|
||||||
|
- * Returns 1 on success and -1 on error.
|
||||||
|
+ * Returns true on success, false on failure and -1 on error.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
sudo_auth_begin_session(struct passwd *pw, char **user_env[])
|
||||||
|
{
|
||||||
|
sudo_auth *auth;
|
||||||
|
+ int ret = true;
|
||||||
|
debug_decl(sudo_auth_begin_session, SUDOERS_DEBUG_AUTH);
|
||||||
|
|
||||||
|
for (auth = auth_switch; auth->name; auth++) {
|
||||||
|
if (auth->begin_session && !IS_DISABLED(auth)) {
|
||||||
|
int status = (auth->begin_session)(pw, user_env, auth);
|
||||||
|
- if (status != AUTH_SUCCESS) {
|
||||||
|
+ switch (status) {
|
||||||
|
+ case AUTH_SUCCESS:
|
||||||
|
+ break;
|
||||||
|
+ case AUTH_FAILURE:
|
||||||
|
+ ret = false;
|
||||||
|
+ break;
|
||||||
|
+ default:
|
||||||
|
/* Assume error msg already printed. */
|
||||||
|
- debug_return_int(-1);
|
||||||
|
+ ret = -1;
|
||||||
|
+ break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- debug_return_int(1);
|
||||||
|
+ debug_return_int(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
@@ -398,25 +411,33 @@ sudo_auth_needs_end_session(void)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call authentication method end session hooks.
|
||||||
|
- * Returns 1 on success and -1 on error.
|
||||||
|
+ * Returns true on success, false on failure and -1 on error.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
sudo_auth_end_session(struct passwd *pw)
|
||||||
|
{
|
||||||
|
sudo_auth *auth;
|
||||||
|
+ int ret = true;
|
||||||
|
int status;
|
||||||
|
debug_decl(sudo_auth_end_session, SUDOERS_DEBUG_AUTH);
|
||||||
|
|
||||||
|
for (auth = auth_switch; auth->name; auth++) {
|
||||||
|
if (auth->end_session && !IS_DISABLED(auth)) {
|
||||||
|
status = (auth->end_session)(pw, auth);
|
||||||
|
- if (status == AUTH_FATAL) {
|
||||||
|
+ switch (status) {
|
||||||
|
+ case AUTH_SUCCESS:
|
||||||
|
+ break;
|
||||||
|
+ case AUTH_FAILURE:
|
||||||
|
+ ret = false;
|
||||||
|
+ break;
|
||||||
|
+ default:
|
||||||
|
/* Assume error msg already printed. */
|
||||||
|
- debug_return_int(-1);
|
||||||
|
+ ret = -1;
|
||||||
|
+ break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- debug_return_int(1);
|
||||||
|
+ debug_return_int(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
diff --git a/plugins/sudoers/auth/sudo_auth.h b/plugins/sudoers/auth/sudo_auth.h
|
||||||
|
index 9ee408d..0b30d0c 100644
|
||||||
|
--- a/plugins/sudoers/auth/sudo_auth.h
|
||||||
|
+++ b/plugins/sudoers/auth/sudo_auth.h
|
||||||
|
@@ -19,11 +19,11 @@
|
||||||
|
#ifndef SUDO_AUTH_H
|
||||||
|
#define SUDO_AUTH_H
|
||||||
|
|
||||||
|
-/* Auth function return values. */
|
||||||
|
-#define AUTH_SUCCESS 0
|
||||||
|
-#define AUTH_FAILURE 1
|
||||||
|
-#define AUTH_INTR 2
|
||||||
|
-#define AUTH_FATAL 3
|
||||||
|
+/* Auth function return values (rowhammer resistent). */
|
||||||
|
+#define AUTH_SUCCESS 0x52a2925 /* 0101001010100010100100100101 */
|
||||||
|
+#define AUTH_FAILURE 0xad5d6da /* 1010110101011101011011011010 */
|
||||||
|
+#define AUTH_INTR 0x69d61fc8 /* 1101001110101100001111111001000 */
|
||||||
|
+#define AUTH_FATAL 0x1629e037 /* 0010110001010011110000000110111 */
|
||||||
|
|
||||||
|
typedef struct sudo_auth {
|
||||||
|
int flags; /* various flags, see below */
|
||||||
|
diff --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c
|
||||||
|
index 9324159..0891d63 100644
|
||||||
|
--- a/plugins/sudoers/match.c
|
||||||
|
+++ b/plugins/sudoers/match.c
|
||||||
|
@@ -92,7 +92,7 @@ user_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw,
|
||||||
|
if ((a = alias_get(parse_tree, m->name, USERALIAS)) != NULL) {
|
||||||
|
/* XXX */
|
||||||
|
const int rc = userlist_matches(parse_tree, pw, &a->members);
|
||||||
|
- if (rc != UNSPEC) {
|
||||||
|
+ if (SPECIFIED(rc)) {
|
||||||
|
if (m->negated) {
|
||||||
|
matched = rc == ALLOW ? DENY : ALLOW;
|
||||||
|
} else {
|
||||||
|
@@ -124,7 +124,8 @@ userlist_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw,
|
||||||
|
debug_decl(userlist_matches, SUDOERS_DEBUG_MATCH);
|
||||||
|
|
||||||
|
TAILQ_FOREACH_REVERSE(m, list, member_list, entries) {
|
||||||
|
- if ((matched = user_matches(parse_tree, pw, m)) != UNSPEC)
|
||||||
|
+ matched = user_matches(parse_tree, pw, m);
|
||||||
|
+ if (SPECIFIED(matched))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
debug_return_int(matched);
|
||||||
|
@@ -194,7 +195,7 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree,
|
||||||
|
if (a != NULL) {
|
||||||
|
rc = runaslist_matches(parse_tree, &a->members,
|
||||||
|
&empty, matching_user, NULL);
|
||||||
|
- if (rc != UNSPEC) {
|
||||||
|
+ if (SPECIFIED(rc)) {
|
||||||
|
if (m->negated) {
|
||||||
|
user_matched = rc == ALLOW ? DENY : ALLOW;
|
||||||
|
} else {
|
||||||
|
@@ -215,7 +216,7 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree,
|
||||||
|
user_matched = m->negated ? DENY : ALLOW;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
- if (user_matched != UNSPEC) {
|
||||||
|
+ if (SPECIFIED(user_matched)) {
|
||||||
|
if (matching_user != NULL && m->type != ALIAS)
|
||||||
|
*matching_user = m;
|
||||||
|
break;
|
||||||
|
@@ -228,7 +229,7 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree,
|
||||||
|
* Skip checking runas group if none was specified.
|
||||||
|
*/
|
||||||
|
if (ISSET(sudo_user.flags, RUNAS_GROUP_SPECIFIED)) {
|
||||||
|
- if (user_matched == UNSPEC) {
|
||||||
|
+ if (!SPECIFIED(user_matched)) {
|
||||||
|
if (strcmp(user_name, runas_pw->pw_name) == 0)
|
||||||
|
user_matched = ALLOW; /* only changing group */
|
||||||
|
}
|
||||||
|
@@ -243,7 +244,7 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree,
|
||||||
|
if (a != NULL) {
|
||||||
|
rc = runaslist_matches(parse_tree, &empty,
|
||||||
|
&a->members, NULL, matching_group);
|
||||||
|
- if (rc != UNSPEC) {
|
||||||
|
+ if (SPECIFIED(rc)) {
|
||||||
|
if (m->negated) {
|
||||||
|
group_matched = rc == ALLOW ? DENY : ALLOW;
|
||||||
|
} else {
|
||||||
|
@@ -259,14 +260,14 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree,
|
||||||
|
group_matched = m->negated ? DENY : ALLOW;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
- if (group_matched != UNSPEC) {
|
||||||
|
+ if (SPECIFIED(group_matched)) {
|
||||||
|
if (matching_group != NULL && m->type != ALIAS)
|
||||||
|
*matching_group = m;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- if (group_matched == UNSPEC) {
|
||||||
|
+ if (!SPECIFIED(group_matched)) {
|
||||||
|
struct gid_list *runas_groups;
|
||||||
|
/*
|
||||||
|
* The runas group was not explicitly allowed by sudoers.
|
||||||
|
@@ -310,7 +311,7 @@ hostlist_matches_int(struct sudoers_parse_tree *parse_tree,
|
||||||
|
|
||||||
|
TAILQ_FOREACH_REVERSE(m, list, member_list, entries) {
|
||||||
|
matched = host_matches(parse_tree, pw, lhost, shost, m);
|
||||||
|
- if (matched != UNSPEC)
|
||||||
|
+ if (SPECIFIED(matched))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
debug_return_int(matched);
|
||||||
|
@@ -361,7 +362,7 @@ host_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw,
|
||||||
|
/* XXX */
|
||||||
|
const int rc = hostlist_matches_int(parse_tree, pw, lhost,
|
||||||
|
shost, &a->members);
|
||||||
|
- if (rc != UNSPEC) {
|
||||||
|
+ if (SPECIFIED(rc)) {
|
||||||
|
if (m->negated) {
|
||||||
|
matched = rc == ALLOW ? DENY : ALLOW;
|
||||||
|
} else {
|
||||||
|
@@ -395,7 +396,7 @@ cmndlist_matches(struct sudoers_parse_tree *parse_tree,
|
||||||
|
|
||||||
|
TAILQ_FOREACH_REVERSE(m, list, member_list, entries) {
|
||||||
|
matched = cmnd_matches(parse_tree, m, runchroot, info);
|
||||||
|
- if (matched != UNSPEC)
|
||||||
|
+ if (SPECIFIED(matched))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
debug_return_int(matched);
|
||||||
|
@@ -425,7 +426,7 @@ cmnd_matches(struct sudoers_parse_tree *parse_tree, const struct member *m,
|
||||||
|
a = alias_get(parse_tree, m->name, CMNDALIAS);
|
||||||
|
if (a != NULL) {
|
||||||
|
rc = cmndlist_matches(parse_tree, &a->members, runchroot, info);
|
||||||
|
- if (rc != UNSPEC) {
|
||||||
|
+ if (SPECIFIED(rc)) {
|
||||||
|
if (m->negated) {
|
||||||
|
matched = rc == ALLOW ? DENY : ALLOW;
|
||||||
|
} else {
|
||||||
|
diff --git a/plugins/sudoers/parse.c b/plugins/sudoers/parse.c
|
||||||
|
index d3bf8a5..e38e7e9 100644
|
||||||
|
--- a/plugins/sudoers/parse.c
|
||||||
|
+++ b/plugins/sudoers/parse.c
|
||||||
|
@@ -153,7 +153,7 @@ sudoers_lookup_check(struct sudo_nss *nss, struct passwd *pw,
|
||||||
|
if (runas_match == ALLOW) {
|
||||||
|
cmnd_match = cmnd_matches(nss->parse_tree, cs->cmnd,
|
||||||
|
cs->runchroot, info);
|
||||||
|
- if (cmnd_match != UNSPEC) {
|
||||||
|
+ if (SPECIFIED(cmnd_match)) {
|
||||||
|
/*
|
||||||
|
* If user is running command as himself,
|
||||||
|
* set runas_pw = sudo_user.pw.
|
||||||
|
@@ -396,7 +396,7 @@ sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, int *cmnd_status,
|
||||||
|
}
|
||||||
|
|
||||||
|
m = sudoers_lookup_check(nss, pw, &validated, &info, &cs, &defs, now);
|
||||||
|
- if (m != UNSPEC) {
|
||||||
|
+ if (SPECIFIED(m)) {
|
||||||
|
match = m;
|
||||||
|
parse_tree = nss->parse_tree;
|
||||||
|
}
|
||||||
|
@@ -404,7 +404,7 @@ sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, int *cmnd_status,
|
||||||
|
if (!sudo_nss_can_continue(nss, m))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
- if (match != UNSPEC) {
|
||||||
|
+ if (SPECIFIED(match)) {
|
||||||
|
if (info.cmnd_path != NULL) {
|
||||||
|
/* Update user_cmnd, user_stat, cmnd_status from matching entry. */
|
||||||
|
free(user_cmnd);
|
||||||
|
diff --git a/plugins/sudoers/parse.h b/plugins/sudoers/parse.h
|
||||||
|
index ea2a179..8559849 100644
|
||||||
|
--- a/plugins/sudoers/parse.h
|
||||||
|
+++ b/plugins/sudoers/parse.h
|
||||||
|
@@ -34,15 +34,28 @@
|
||||||
|
# define SUDOERS_NAME_MATCH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+/* Allowed by policy (rowhammer resistent). */
|
||||||
|
+#undef ALLOW
|
||||||
|
+#define ALLOW 0x52a2925 /* 0101001010100010100100100101 */
|
||||||
|
+
|
||||||
|
+/* Denied by policy (rowhammer resistent). */
|
||||||
|
+#undef DENY
|
||||||
|
+#define DENY 0xad5d6da /* 1010110101011101011011011010 */
|
||||||
|
+
|
||||||
|
+/* Neither allowed, nor denied. */
|
||||||
|
#undef UNSPEC
|
||||||
|
#define UNSPEC -1
|
||||||
|
-#undef DENY
|
||||||
|
-#define DENY 0
|
||||||
|
-#undef ALLOW
|
||||||
|
-#define ALLOW 1
|
||||||
|
+
|
||||||
|
+/* Tag implied by root access (SETENV only). */
|
||||||
|
#undef IMPLIED
|
||||||
|
#define IMPLIED 2
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * We must explicitly check against ALLOW and DENY instead testing
|
||||||
|
+ * that the value is not UNSPEC to avoid potential ROWHAMMER issues.
|
||||||
|
+ */
|
||||||
|
+#define SPECIFIED(_v) ((_v) == ALLOW || (_v) == DENY)
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Initialize all tags to UNSPEC.
|
||||||
|
*/
|
||||||
|
@@ -92,7 +105,7 @@
|
||||||
|
* Returns true if the specified tag is not UNSPEC or IMPLIED, else false.
|
||||||
|
*/
|
||||||
|
#define TAG_SET(tt) \
|
||||||
|
- ((tt) != UNSPEC && (tt) != IMPLIED)
|
||||||
|
+ ((tt) == true || (tt) == false)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns true if any tags set in nt differ between ot and nt, else false.
|
||||||
|
--
|
||||||
|
2.42.0.windows.2
|
||||||
|
|
||||||
@ -0,0 +1,249 @@
|
|||||||
|
From cf00568d888c90a8c5d06a06283bc87a45992933 Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Todd C. Miller" <Todd.Miller@sudo.ws>
|
||||||
|
Date: Sat, 26 Aug 2023 10:32:37 -0600
|
||||||
|
Subject: [PATCH] Do not rely on the definition of ALLOW/DENY being true/false.
|
||||||
|
|
||||||
|
We now explicitly check for ALLOW and DENY when checking return
|
||||||
|
values and negating values.
|
||||||
|
|
||||||
|
Reference: https://github.com/sudo-project/sudo/commit/cf00568d888c90a8c5d06a06283bc87a45992933
|
||||||
|
Conflict: cvtsudoers.c match.c
|
||||||
|
---
|
||||||
|
plugins/sudoers/cvtsudoers.c | 6 +--
|
||||||
|
plugins/sudoers/match.c | 83 +++++++++++++++++++++++-------------
|
||||||
|
2 files changed, 57 insertions(+), 32 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/plugins/sudoers/cvtsudoers.c b/plugins/sudoers/cvtsudoers.c
|
||||||
|
index 79558c3..8cedcc6 100644
|
||||||
|
--- a/plugins/sudoers/cvtsudoers.c
|
||||||
|
+++ b/plugins/sudoers/cvtsudoers.c
|
||||||
|
@@ -690,7 +690,7 @@ userlist_matches_filter(struct sudoers_parse_tree *parse_tree,
|
||||||
|
pw.pw_uid = (uid_t)-1;
|
||||||
|
pw.pw_gid = (gid_t)-1;
|
||||||
|
|
||||||
|
- if (user_matches(parse_tree, &pw, m) == true)
|
||||||
|
+ if (user_matches(parse_tree, &pw, m) == ALLOW)
|
||||||
|
matched = true;
|
||||||
|
} else {
|
||||||
|
STAILQ_FOREACH(s, &filters->users, entries) {
|
||||||
|
@@ -716,7 +716,7 @@ userlist_matches_filter(struct sudoers_parse_tree *parse_tree,
|
||||||
|
if (pw == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
- if (user_matches(parse_tree, pw, m) == true)
|
||||||
|
+ if (user_matches(parse_tree, pw, m) == ALLOW)
|
||||||
|
matched = true;
|
||||||
|
sudo_pw_delref(pw);
|
||||||
|
|
||||||
|
@@ -792,7 +792,7 @@ hostlist_matches_filter(struct sudoers_parse_tree *parse_tree,
|
||||||
|
|
||||||
|
/* Only need one host in the filter to match. */
|
||||||
|
/* XXX - can't use netgroup_tuple with NULL pw */
|
||||||
|
- if (host_matches(parse_tree, NULL, lhost, shost, m) == true) {
|
||||||
|
+ if (host_matches(parse_tree, NULL, lhost, shost, m) == ALLOW) {
|
||||||
|
matched = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
diff --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c
|
||||||
|
index 9801f38..9324159 100644
|
||||||
|
--- a/plugins/sudoers/match.c
|
||||||
|
+++ b/plugins/sudoers/match.c
|
||||||
|
@@ -76,31 +76,36 @@ user_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw,
|
||||||
|
|
||||||
|
switch (m->type) {
|
||||||
|
case ALL:
|
||||||
|
- matched = !m->negated;
|
||||||
|
+ matched = m->negated ? DENY : ALLOW;
|
||||||
|
break;
|
||||||
|
case NETGROUP:
|
||||||
|
if (netgr_matches(m->name,
|
||||||
|
def_netgroup_tuple ? lhost : NULL,
|
||||||
|
def_netgroup_tuple ? shost : NULL, pw->pw_name))
|
||||||
|
- matched = !m->negated;
|
||||||
|
+ matched = m->negated ? DENY : ALLOW;
|
||||||
|
break;
|
||||||
|
case USERGROUP:
|
||||||
|
if (usergr_matches(m->name, pw->pw_name, pw))
|
||||||
|
- matched = !m->negated;
|
||||||
|
+ matched = m->negated ? DENY : ALLOW;
|
||||||
|
break;
|
||||||
|
case ALIAS:
|
||||||
|
if ((a = alias_get(parse_tree, m->name, USERALIAS)) != NULL) {
|
||||||
|
/* XXX */
|
||||||
|
- int rc = userlist_matches(parse_tree, pw, &a->members);
|
||||||
|
- if (rc != UNSPEC)
|
||||||
|
- matched = m->negated ? !rc : rc;
|
||||||
|
+ const int rc = userlist_matches(parse_tree, pw, &a->members);
|
||||||
|
+ if (rc != UNSPEC) {
|
||||||
|
+ if (m->negated) {
|
||||||
|
+ matched = rc == ALLOW ? DENY : ALLOW;
|
||||||
|
+ } else {
|
||||||
|
+ matched = rc;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
alias_put(a);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
FALLTHROUGH;
|
||||||
|
case WORD:
|
||||||
|
if (userpw_matches(m->name, pw->pw_name, pw))
|
||||||
|
- matched = !m->negated;
|
||||||
|
+ matched = m->negated ? DENY : ALLOW;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
debug_return_int(matched);
|
||||||
|
@@ -171,38 +176,43 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree,
|
||||||
|
TAILQ_FOREACH_REVERSE(m, user_list, member_list, entries) {
|
||||||
|
switch (m->type) {
|
||||||
|
case ALL:
|
||||||
|
- user_matched = !m->negated;
|
||||||
|
+ user_matched = m->negated ? DENY : ALLOW;
|
||||||
|
break;
|
||||||
|
case NETGROUP:
|
||||||
|
if (netgr_matches(m->name,
|
||||||
|
def_netgroup_tuple ? lhost : NULL,
|
||||||
|
def_netgroup_tuple ? shost : NULL,
|
||||||
|
runas_pw->pw_name))
|
||||||
|
- user_matched = !m->negated;
|
||||||
|
+ user_matched = m->negated ? DENY : ALLOW;
|
||||||
|
break;
|
||||||
|
case USERGROUP:
|
||||||
|
if (usergr_matches(m->name, runas_pw->pw_name, runas_pw))
|
||||||
|
- user_matched = !m->negated;
|
||||||
|
+ user_matched = m->negated ? DENY : ALLOW;
|
||||||
|
break;
|
||||||
|
case ALIAS:
|
||||||
|
a = alias_get(parse_tree, m->name, RUNASALIAS);
|
||||||
|
if (a != NULL) {
|
||||||
|
rc = runaslist_matches(parse_tree, &a->members,
|
||||||
|
&empty, matching_user, NULL);
|
||||||
|
- if (rc != UNSPEC)
|
||||||
|
- user_matched = m->negated ? !rc : rc;
|
||||||
|
+ if (rc != UNSPEC) {
|
||||||
|
+ if (m->negated) {
|
||||||
|
+ user_matched = rc == ALLOW ? DENY : ALLOW;
|
||||||
|
+ } else {
|
||||||
|
+ user_matched = rc;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
alias_put(a);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
FALLTHROUGH;
|
||||||
|
case WORD:
|
||||||
|
if (userpw_matches(m->name, runas_pw->pw_name, runas_pw))
|
||||||
|
- user_matched = !m->negated;
|
||||||
|
+ user_matched = m->negated ? DENY : ALLOW;
|
||||||
|
break;
|
||||||
|
case MYSELF:
|
||||||
|
if (!ISSET(sudo_user.flags, RUNAS_USER_SPECIFIED) ||
|
||||||
|
strcmp(user_name, runas_pw->pw_name) == 0)
|
||||||
|
- user_matched = !m->negated;
|
||||||
|
+ user_matched = m->negated ? DENY : ALLOW;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (user_matched != UNSPEC) {
|
||||||
|
@@ -226,22 +236,27 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree,
|
||||||
|
TAILQ_FOREACH_REVERSE(m, group_list, member_list, entries) {
|
||||||
|
switch (m->type) {
|
||||||
|
case ALL:
|
||||||
|
- group_matched = !m->negated;
|
||||||
|
+ group_matched = m->negated ? DENY : ALLOW;
|
||||||
|
break;
|
||||||
|
case ALIAS:
|
||||||
|
a = alias_get(parse_tree, m->name, RUNASALIAS);
|
||||||
|
if (a != NULL) {
|
||||||
|
rc = runaslist_matches(parse_tree, &empty,
|
||||||
|
&a->members, NULL, matching_group);
|
||||||
|
- if (rc != UNSPEC)
|
||||||
|
- group_matched = m->negated ? !rc : rc;
|
||||||
|
+ if (rc != UNSPEC) {
|
||||||
|
+ if (m->negated) {
|
||||||
|
+ group_matched = rc == ALLOW ? DENY : ALLOW;
|
||||||
|
+ } else {
|
||||||
|
+ group_matched = rc;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
alias_put(a);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
FALLTHROUGH;
|
||||||
|
case WORD:
|
||||||
|
if (group_matches(m->name, runas_gr))
|
||||||
|
- group_matched = !m->negated;
|
||||||
|
+ group_matched = m->negated ? DENY : ALLOW;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (group_matched != UNSPEC) {
|
||||||
|
@@ -329,32 +344,37 @@ host_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw,
|
||||||
|
|
||||||
|
switch (m->type) {
|
||||||
|
case ALL:
|
||||||
|
- matched = !m->negated;
|
||||||
|
+ matched = m->negated ? DENY : ALLOW;
|
||||||
|
break;
|
||||||
|
case NETGROUP:
|
||||||
|
if (netgr_matches(m->name, lhost, shost,
|
||||||
|
def_netgroup_tuple ? pw->pw_name : NULL))
|
||||||
|
- matched = !m->negated;
|
||||||
|
+ matched = m->negated ? DENY : ALLOW;
|
||||||
|
break;
|
||||||
|
case NTWKADDR:
|
||||||
|
if (addr_matches(m->name))
|
||||||
|
- matched = !m->negated;
|
||||||
|
+ matched = m->negated ? DENY : ALLOW;
|
||||||
|
break;
|
||||||
|
case ALIAS:
|
||||||
|
a = alias_get(parse_tree, m->name, HOSTALIAS);
|
||||||
|
if (a != NULL) {
|
||||||
|
/* XXX */
|
||||||
|
- int rc = hostlist_matches_int(parse_tree, pw, lhost, shost,
|
||||||
|
- &a->members);
|
||||||
|
- if (rc != UNSPEC)
|
||||||
|
- matched = m->negated ? !rc : rc;
|
||||||
|
+ const int rc = hostlist_matches_int(parse_tree, pw, lhost,
|
||||||
|
+ shost, &a->members);
|
||||||
|
+ if (rc != UNSPEC) {
|
||||||
|
+ if (m->negated) {
|
||||||
|
+ matched = rc == ALLOW ? DENY : ALLOW;
|
||||||
|
+ } else {
|
||||||
|
+ matched = rc;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
alias_put(a);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
FALLTHROUGH;
|
||||||
|
case WORD:
|
||||||
|
if (hostname_matches(shost, lhost, m->name))
|
||||||
|
- matched = !m->negated;
|
||||||
|
+ matched = m->negated ? DENY : ALLOW;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
debug_return_int(matched);
|
||||||
|
@@ -399,14 +419,19 @@ cmnd_matches(struct sudoers_parse_tree *parse_tree, const struct member *m,
|
||||||
|
case COMMAND:
|
||||||
|
c = (struct sudo_command *)m->name;
|
||||||
|
if (command_matches(c->cmnd, c->args, runchroot, info, &c->digests))
|
||||||
|
- matched = !m->negated;
|
||||||
|
+ matched = m->negated ? DENY : ALLOW;
|
||||||
|
break;
|
||||||
|
case ALIAS:
|
||||||
|
a = alias_get(parse_tree, m->name, CMNDALIAS);
|
||||||
|
if (a != NULL) {
|
||||||
|
rc = cmndlist_matches(parse_tree, &a->members, runchroot, info);
|
||||||
|
- if (rc != UNSPEC)
|
||||||
|
- matched = m->negated ? !rc : rc;
|
||||||
|
+ if (rc != UNSPEC) {
|
||||||
|
+ if (m->negated) {
|
||||||
|
+ matched = rc == ALLOW ? DENY : ALLOW;
|
||||||
|
+ } else {
|
||||||
|
+ matched = rc;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
alias_put(a);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
--
|
||||||
|
2.42.0.windows.2
|
||||||
|
|
||||||
@ -0,0 +1,212 @@
|
|||||||
|
From 41978a56e042977923c1a55191b887218c536145 Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Todd C. Miller" <Todd.Miller@sudo.ws>
|
||||||
|
Date: Sat, 27 Apr 2024 18:53:50 -0600
|
||||||
|
Subject: [PATCH] If user's tty goes away, tell monitor to revoke the tty in
|
||||||
|
its session.
|
||||||
|
|
||||||
|
Previously, we would simply close the pty leader in the main sudo
|
||||||
|
process. This had the effect of revoking the pty, but the foreground
|
||||||
|
process would not necessarily receive SIGHUP. By using TIOCNOTTY
|
||||||
|
in the monitor, the running command has a better chance of getting
|
||||||
|
SIGHUP. Once the monitor has revoked the pty, the main sudo process
|
||||||
|
will close the pty leader, invalidating the pty. GitHub issue #367.
|
||||||
|
|
||||||
|
Reference:https://github.com/sudo-project/sudo/commit/41978a56e042977923c1a55191b887218c536145
|
||||||
|
Conflict:src/exec_monitor.c src/exec_pty.c
|
||||||
|
|
||||||
|
---
|
||||||
|
src/exec_monitor.c | 48 +++++++++++++++++++++++++++++++++++--
|
||||||
|
src/exec_pty.c | 60 ++++++++++++++++++++++++++++++++++++----------
|
||||||
|
src/sudo.h | 1 +
|
||||||
|
3 files changed, 95 insertions(+), 14 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/exec_monitor.c b/src/exec_monitor.c
|
||||||
|
index 05f5f8cd1..c570b5d86 100644
|
||||||
|
--- a/src/exec_monitor.c
|
||||||
|
+++ b/src/exec_monitor.c
|
||||||
|
@@ -118,6 +118,8 @@ deliver_signal(struct monitor_closure *mc, int signo, bool from_parent)
|
||||||
|
/* NOTREACHED */
|
||||||
|
default:
|
||||||
|
/* Relay signal to command. */
|
||||||
|
+ sudo_debug_printf(SUDO_DEBUG_NOTICE, "%s: killpg(%d, %d)",
|
||||||
|
+ __func__, (int)mc->cmnd_pid, signo);
|
||||||
|
killpg(mc->cmnd_pid, signo);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
@@ -334,11 +336,53 @@ mon_backchannel_cb(int fd, int what, void *v)
|
||||||
|
mc->cstat->val = n ? EIO : ECONNRESET;
|
||||||
|
sudo_ev_loopbreak(mc->evbase);
|
||||||
|
} else {
|
||||||
|
- if (cstmp.type == CMD_SIGNO) {
|
||||||
|
+ switch (cstmp.type) {
|
||||||
|
+ case CMD_IOCTL:
|
||||||
|
+ if (cstmp.val != TIOCNOTTY) {
|
||||||
|
+ sudo_warnx(U_("unexpected ioctl on backchannel: %d"),
|
||||||
|
+ cstmp.val);
|
||||||
|
+ } else if (io_fds[SFD_FOLLOWER] != -1) {
|
||||||
|
+ int result, ttyfd;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Parent asks us to revoke the terminal when the
|
||||||
|
+ * user's terminal goes away. Doing this in the
|
||||||
|
+ * monitor allows the foreground command to receive
|
||||||
|
+ * SIGHUP before the terminal is revoked.
|
||||||
|
+ */
|
||||||
|
+ result = ioctl(io_fds[SFD_FOLLOWER], TIOCNOTTY, NULL);
|
||||||
|
+ if (result == -1) {
|
||||||
|
+ sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||||
|
+ "%s: unable to revoke follower pty", __func__);
|
||||||
|
+ ttyfd = open(_PATH_TTY, O_RDWR);
|
||||||
|
+ if (ttyfd != -1) {
|
||||||
|
+ result = ioctl(ttyfd, TIOCNOTTY, NULL);
|
||||||
|
+ if (result == -1) {
|
||||||
|
+ sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||||
|
+ "%s: unable to revoke controlling tty",
|
||||||
|
+ __func__);
|
||||||
|
+ }
|
||||||
|
+ close(ttyfd);
|
||||||
|
+ } else {
|
||||||
|
+ sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||||
|
+ "%s: unable to open %s", __func__, _PATH_TTY);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if (result == 0) {
|
||||||
|
+ sudo_debug_printf(SUDO_DEBUG_INFO,
|
||||||
|
+ "%s: revoked controlling tty for session", __func__);
|
||||||
|
+ }
|
||||||
|
+ /* Now tell the parent to close the pty leader. */
|
||||||
|
+ send_status(fd, &cstmp);
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
+ case CMD_SIGNO:
|
||||||
|
deliver_signal(mc, cstmp.val, true);
|
||||||
|
- } else {
|
||||||
|
+ break;
|
||||||
|
+ default:
|
||||||
|
sudo_warnx(U_("unexpected reply type on backchannel: %d"),
|
||||||
|
cstmp.type);
|
||||||
|
+ break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug_return;
|
||||||
|
diff --git a/src/exec_pty.c b/src/exec_pty.c
|
||||||
|
index 6c0f7583e..fff9b8f1e 100644
|
||||||
|
--- a/src/exec_pty.c
|
||||||
|
+++ b/src/exec_pty.c
|
||||||
|
@@ -61,6 +61,7 @@ static struct exec_closure pty_ec;
|
||||||
|
static pid_t check_foreground(struct exec_closure_pty *ec);
|
||||||
|
static void add_io_events(struct sudo_event_base *evbase);
|
||||||
|
static void schedule_signal(struct exec_closure_pty *ec, int signo);
|
||||||
|
+static void send_command_status(struct exec_closure_pty *ec, int type, int val);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cleanup hook for sudo_fatal()/sudo_fatalx()
|
||||||
|
@@ -383,8 +384,18 @@ read_callback(int fd, int what, void *v)
|
||||||
|
ev_free_by_fd(evbase, fd);
|
||||||
|
/* If writer already consumed the buffer, close it too. */
|
||||||
|
if (iob->wevent != NULL && iob->off == iob->len) {
|
||||||
|
- safe_close(sudo_ev_get_fd(iob->wevent));
|
||||||
|
- ev_free_by_fd(evbase, sudo_ev_get_fd(iob->wevent));
|
||||||
|
+ /*
|
||||||
|
+ * Don't close the pty leader, it will invalidate the pty.
|
||||||
|
+ * We ask the monitor to revoke the pty nicely using TIOCNOTTY.
|
||||||
|
+ */
|
||||||
|
+ const int wfd = sudo_ev_get_fd(iob->wevent);
|
||||||
|
+ if (wfd == io_fds[SFD_LEADER]) {
|
||||||
|
+ sudo_debug_printf(SUDO_DEBUG_NOTICE, "user's tty revoked");
|
||||||
|
+ send_command_status(iob->ec, CMD_IOCTL, TIOCNOTTY);
|
||||||
|
+ } else {
|
||||||
|
+ safe_close(wfd);
|
||||||
|
+ }
|
||||||
|
+ ev_free_by_fd(evbase, wfd);
|
||||||
|
iob->off = iob->len = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
@@ -461,8 +472,18 @@ write_callback(int fd, int what, void *v)
|
||||||
|
iob->len - iob->off, fd);
|
||||||
|
/* Close reader if there is one. */
|
||||||
|
if (iob->revent != NULL) {
|
||||||
|
- safe_close(sudo_ev_get_fd(iob->revent));
|
||||||
|
- ev_free_by_fd(evbase, sudo_ev_get_fd(iob->revent));
|
||||||
|
+ /*
|
||||||
|
+ * Don't close the pty leader, it will invalidate the pty.
|
||||||
|
+ * We ask the monitor to revoke the pty nicely using TIOCNOTTY.
|
||||||
|
+ */
|
||||||
|
+ const int rfd = sudo_ev_get_fd(iob->revent);
|
||||||
|
+ if (rfd == io_fds[SFD_LEADER]) {
|
||||||
|
+ sudo_debug_printf(SUDO_DEBUG_NOTICE, "user's tty revoked");
|
||||||
|
+ send_command_status(iob->ec, CMD_IOCTL, TIOCNOTTY);
|
||||||
|
+ } else {
|
||||||
|
+ safe_close(rfd);
|
||||||
|
+ }
|
||||||
|
+ ev_free_by_fd(evbase, rfd);
|
||||||
|
}
|
||||||
|
safe_close(fd);
|
||||||
|
ev_free_by_fd(evbase, fd);
|
||||||
|
@@ -656,6 +677,28 @@ backchannel_cb(int fd, int what, void *v)
|
||||||
|
case sizeof(cstat):
|
||||||
|
/* Check command status. */
|
||||||
|
switch (cstat.type) {
|
||||||
|
+ case CMD_ERRNO:
|
||||||
|
+ /* Monitor was unable to execute command or broken pipe. */
|
||||||
|
+ sudo_debug_printf(SUDO_DEBUG_INFO, "errno from monitor: %s",
|
||||||
|
+ strerror(cstat.val));
|
||||||
|
+ sudo_ev_loopbreak(ec->evbase);
|
||||||
|
+ *ec->cstat = cstat;
|
||||||
|
+ break;
|
||||||
|
+ case CMD_IOCTL:
|
||||||
|
+ if (cstat.val != TIOCNOTTY) {
|
||||||
|
+ sudo_warnx(U_("unexpected ioctl on backchannel: %d"),
|
||||||
|
+ cstat.val);
|
||||||
|
+ } else if (io_fds[SFD_LEADER] != -1) {
|
||||||
|
+ /*
|
||||||
|
+ * Monitor requests that we revoke the user's terminal.
|
||||||
|
+ * This must happen after the monitor has used TIOCNOTTY
|
||||||
|
+ * to invalidate the session and gracefully kill the
|
||||||
|
+ * controlling terminal's process group.
|
||||||
|
+ */
|
||||||
|
+ close(io_fds[SFD_LEADER]);
|
||||||
|
+ io_fds[SFD_LEADER] = -1;
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
case CMD_PID:
|
||||||
|
ec->cmnd_pid = cstat.val;
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_INFO, "executed %s, pid %d",
|
||||||
|
@@ -693,13 +736,6 @@ backchannel_cb(int fd, int what, void *v)
|
||||||
|
*ec->cstat = cstat;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
- case CMD_ERRNO:
|
||||||
|
- /* Monitor was unable to execute command or broken pipe. */
|
||||||
|
- sudo_debug_printf(SUDO_DEBUG_INFO, "errno from monitor: %s",
|
||||||
|
- strerror(cstat.val));
|
||||||
|
- sudo_ev_loopbreak(ec->evbase);
|
||||||
|
- *ec->cstat = cstat;
|
||||||
|
- break;
|
||||||
|
}
|
||||||
|
/* Keep reading command status messages until EAGAIN or EOF. */
|
||||||
|
break;
|
||||||
|
@@ -1382,7 +1418,7 @@ exec_pty(struct command_details *details,
|
||||||
|
if (sudo_ev_dispatch(ec.evbase) == -1)
|
||||||
|
sudo_warn("%s", U_("error in event loop"));
|
||||||
|
if (sudo_ev_got_break(ec.evbase)) {
|
||||||
|
- /* error from callback or monitor died */
|
||||||
|
+ /* error from callback */
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR, "event loop exited prematurely");
|
||||||
|
/* XXX: no good way to know if we should terminate the command. */
|
||||||
|
if (cstat->val == CMD_INVALID && ec.cmnd_pid != -1) {
|
||||||
|
diff --git a/src/sudo.h b/src/sudo.h
|
||||||
|
index a7450dca9..ca245ca68 100644
|
||||||
|
--- a/src/sudo.h
|
||||||
|
+++ b/src/sudo.h
|
||||||
|
@@ -225,6 +225,7 @@ struct command_status {
|
||||||
|
#define CMD_WSTATUS 2
|
||||||
|
#define CMD_SIGNO 3
|
||||||
|
#define CMD_PID 4
|
||||||
|
+#define CMD_IOCTL 5
|
||||||
|
int type;
|
||||||
|
int val;
|
||||||
|
};
|
||||||
|
--
|
||||||
|
2.33.0
|
||||||
|
|
||||||
1117
backport-Make-all-match-functions-return-ALLOW-DENY-.patch
Normal file
1117
backport-Make-all-match-functions-return-ALLOW-DENY-.patch
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,234 @@
|
|||||||
|
From adb84293abfc1c3349ab34c03b036f1756e89aca Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Todd C. Miller" <Todd.Miller@sudo.ws>
|
||||||
|
Date: Tue, 21 Mar 2023 15:30:54 -0600
|
||||||
|
Subject: [PATCH] Move updating of the window size back to the main sudo
|
||||||
|
process. We can use the leader file descriptor with TIOCGWINSZ to set the
|
||||||
|
window size of the pty. Thanks to Duncan Overbruck for the hint.
|
||||||
|
|
||||||
|
|
||||||
|
Reference:https://github.com/sudo-project/sudo/commit/adb84293abfc1c3349ab34c03b036f1756e89aca
|
||||||
|
Conflict:src/exec_monitor.c src/exec_pty.c
|
||||||
|
|
||||||
|
---
|
||||||
|
src/exec_monitor.c | 60 ++++++----------------------------------------
|
||||||
|
src/exec_pty.c | 23 +++++++++---------
|
||||||
|
src/sudo.h | 1 -
|
||||||
|
3 files changed, 18 insertions(+), 66 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/exec_monitor.c b/src/exec_monitor.c
|
||||||
|
index a92ed4099..2f2e0bd83 100644
|
||||||
|
--- a/src/exec_monitor.c
|
||||||
|
+++ b/src/exec_monitor.c
|
||||||
|
@@ -24,7 +24,6 @@
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
-#include <sys/ioctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
@@ -35,7 +34,6 @@
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
-#include <termios.h>
|
||||||
|
|
||||||
|
#include "sudo.h"
|
||||||
|
#include "sudo_exec.h"
|
||||||
|
@@ -62,8 +60,6 @@ struct monitor_closure {
|
||||||
|
struct sudo_event *sigchld_event;
|
||||||
|
};
|
||||||
|
|
||||||
|
-static bool tty_initialized;
|
||||||
|
-
|
||||||
|
/*
|
||||||
|
* Deliver a signal to the running command.
|
||||||
|
* The signal was either forwarded to us by the parent sudo process
|
||||||
|
@@ -103,11 +99,6 @@ deliver_signal(struct monitor_closure *mc, int signo, bool from_parent)
|
||||||
|
"%s: unable to set foreground pgrp to %d (command)",
|
||||||
|
__func__, (int)mc->cmnd_pgrp);
|
||||||
|
}
|
||||||
|
- /* Lazily initialize the pty if needed. */
|
||||||
|
- if (!tty_initialized) {
|
||||||
|
- if (sudo_term_copy(io_fds[SFD_USERTTY], io_fds[SFD_FOLLOWER]))
|
||||||
|
- tty_initialized = true;
|
||||||
|
- }
|
||||||
|
killpg(mc->cmnd_pid, SIGCONT);
|
||||||
|
break;
|
||||||
|
case SIGCONT_BG:
|
||||||
|
@@ -130,34 +121,6 @@ deliver_signal(struct monitor_closure *mc, int signo, bool from_parent)
|
||||||
|
debug_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
-/*
|
||||||
|
- * Unpack rows and cols from a CMD_TTYWINCH value, set the new window
|
||||||
|
- * size on the pty follower and inform the command of the change.
|
||||||
|
- */
|
||||||
|
-static void
|
||||||
|
-handle_winch(struct monitor_closure *mc, unsigned int wsize_packed)
|
||||||
|
-{
|
||||||
|
- struct winsize wsize, owsize;
|
||||||
|
- debug_decl(handle_winch, SUDO_DEBUG_EXEC);
|
||||||
|
-
|
||||||
|
- /* Rows and columns are stored as two shorts packed into a single int. */
|
||||||
|
- wsize.ws_row = wsize_packed & 0xffff;
|
||||||
|
- wsize.ws_col = (wsize_packed >> 16) & 0xffff;
|
||||||
|
-
|
||||||
|
- if (ioctl(io_fds[SFD_FOLLOWER], TIOCGWINSZ, &owsize) == 0 &&
|
||||||
|
- (wsize.ws_row != owsize.ws_row || wsize.ws_col != owsize.ws_col)) {
|
||||||
|
-
|
||||||
|
- sudo_debug_printf(SUDO_DEBUG_INFO,
|
||||||
|
- "window size change %dx%d -> %dx%d",
|
||||||
|
- owsize.ws_col, owsize.ws_row, wsize.ws_col, wsize.ws_row);
|
||||||
|
-
|
||||||
|
- (void)ioctl(io_fds[SFD_FOLLOWER], TIOCSWINSZ, &wsize);
|
||||||
|
- deliver_signal(mc, SIGWINCH, true);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- debug_return;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
/*
|
||||||
|
* Send status to parent over socketpair.
|
||||||
|
* Return value is the same as send(2).
|
||||||
|
@@ -368,16 +331,11 @@ mon_backchannel_cb(int fd, int what, void *v)
|
||||||
|
mc->cstat->val = n ? EIO : ECONNRESET;
|
||||||
|
sudo_ev_loopbreak(mc->evbase);
|
||||||
|
} else {
|
||||||
|
- switch (cstmp.type) {
|
||||||
|
- case CMD_TTYWINCH:
|
||||||
|
- handle_winch(mc, cstmp.val);
|
||||||
|
- break;
|
||||||
|
- case CMD_SIGNO:
|
||||||
|
+ if (cstmp.type == CMD_SIGNO) {
|
||||||
|
deliver_signal(mc, cstmp.val, true);
|
||||||
|
- break;
|
||||||
|
- default:
|
||||||
|
- sudo_warnx(U_("unexpected reply type on backchannel: %d"), cstmp.type);
|
||||||
|
- break;
|
||||||
|
+ } else {
|
||||||
|
+ sudo_warnx(U_("unexpected reply type on backchannel: %d"),
|
||||||
|
+ cstmp.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug_return;
|
||||||
|
@@ -556,9 +514,11 @@ exec_monitor(struct command_details *details, sigset_t *oset,
|
||||||
|
int errpipe[2];
|
||||||
|
debug_decl(exec_monitor, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
|
- /* The pty leader is not used by the monitor. */
|
||||||
|
+ /* Close fds the monitor doesn't use. */
|
||||||
|
if (io_fds[SFD_LEADER] != -1)
|
||||||
|
close(io_fds[SFD_LEADER]);
|
||||||
|
+ if (io_fds[SFD_USERTTY] != -1)
|
||||||
|
+ close(io_fds[SFD_USERTTY]);
|
||||||
|
|
||||||
|
/* Ignore any SIGTTIN or SIGTTOU we receive (shouldn't be possible). */
|
||||||
|
memset(&sa, 0, sizeof(sa));
|
||||||
|
@@ -570,10 +530,6 @@ exec_monitor(struct command_details *details, sigset_t *oset,
|
||||||
|
if (sudo_sigaction(SIGTTOU, &sa, NULL) != 0)
|
||||||
|
sudo_warn(U_("unable to set handler for signal %d"), SIGTTOU);
|
||||||
|
|
||||||
|
- /* If we are starting in the foreground, the pty was already initialized. */
|
||||||
|
- if (foreground)
|
||||||
|
- tty_initialized = true;
|
||||||
|
-
|
||||||
|
/*
|
||||||
|
* Start a new session with the parent as the session leader
|
||||||
|
* and the follower device as the controlling terminal.
|
||||||
|
@@ -630,8 +586,6 @@ exec_monitor(struct command_details *details, sigset_t *oset,
|
||||||
|
sigprocmask(SIG_SETMASK, oset, NULL);
|
||||||
|
close(backchannel);
|
||||||
|
close(errpipe[0]);
|
||||||
|
- if (io_fds[SFD_USERTTY] != -1)
|
||||||
|
- close(io_fds[SFD_USERTTY]);
|
||||||
|
restore_signals();
|
||||||
|
|
||||||
|
/* setup tty and exec command */
|
||||||
|
diff --git a/src/exec_pty.c b/src/exec_pty.c
|
||||||
|
index 9a8ddfab1..e764564aa 100644
|
||||||
|
--- a/src/exec_pty.c
|
||||||
|
+++ b/src/exec_pty.c
|
||||||
|
@@ -59,6 +59,7 @@ static struct monitor_message_list monitor_messages =
|
||||||
|
static char ptyname[PATH_MAX];
|
||||||
|
int io_fds[6] = { -1, -1, -1, -1, -1, -1};
|
||||||
|
static bool foreground, pipeline;
|
||||||
|
+static bool tty_initialized;
|
||||||
|
static int ttymode = TERM_COOKED;
|
||||||
|
static sigset_t ttyblock;
|
||||||
|
static struct io_buffer_list iobufs;
|
||||||
|
@@ -159,6 +160,10 @@ check_foreground(struct exec_closure *ec)
|
||||||
|
if (io_fds[SFD_USERTTY] != -1) {
|
||||||
|
if ((ret = tcgetpgrp(io_fds[SFD_USERTTY])) != -1) {
|
||||||
|
foreground = ret == ec->ppgrp;
|
||||||
|
+ if (foreground && !tty_initialized) {
|
||||||
|
+ if (sudo_term_copy(io_fds[SFD_USERTTY], io_fds[SFD_FOLLOWER]))
|
||||||
|
+ tty_initialized = true;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
/* Also check for window size changes. */
|
||||||
|
sync_ttysize(ec);
|
||||||
|
@@ -840,11 +845,6 @@ fwdchannel_cb(int sock, int what, void *v)
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_INFO,
|
||||||
|
"sending SIG%s to monitor over backchannel", signame);
|
||||||
|
break;
|
||||||
|
- case CMD_TTYWINCH:
|
||||||
|
- sudo_debug_printf(SUDO_DEBUG_INFO, "sending window size change "
|
||||||
|
- "to monitor over backchannelL %d x %d",
|
||||||
|
- msg->cstat.val & 0xffff, (msg->cstat.val >> 16) & 0xffff);
|
||||||
|
- break;
|
||||||
|
default:
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_INFO,
|
||||||
|
"sending cstat type %d, value %d to monitor over backchannel",
|
||||||
|
@@ -1192,6 +1192,7 @@ exec_pty(struct command_details *details, struct command_status *cstat)
|
||||||
|
if (sudo_term_raw(io_fds[SFD_USERTTY], 0))
|
||||||
|
ttymode = TERM_RAW;
|
||||||
|
}
|
||||||
|
+ tty_initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1347,8 +1348,8 @@ exec_pty(struct command_details *details, struct command_status *cstat)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
- * Check for tty size changes.
|
||||||
|
- * Passes the new window size to the I/O plugin and to the monitor.
|
||||||
|
+ * Propagate tty size change to pty being used by the command, pass
|
||||||
|
+ * new window size to I/O plugins and deliver SIGWINCH to the command.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
sync_ttysize(struct exec_closure_pty *ec)
|
||||||
|
@@ -1358,14 +1359,12 @@ sync_ttysize(struct exec_closure_pty *ec)
|
||||||
|
|
||||||
|
if (ioctl(io_fds[SFD_USERTTY], TIOCGWINSZ, &wsize) == 0) {
|
||||||
|
if (wsize.ws_row != ec->rows || wsize.ws_col != ec->cols) {
|
||||||
|
- const unsigned int wsize_packed = (wsize.ws_row & 0xffff) |
|
||||||
|
- ((wsize.ws_col & 0xffff) << 16);
|
||||||
|
-
|
||||||
|
/* Log window change event. */
|
||||||
|
log_winchange(ec, wsize.ws_row, wsize.ws_col);
|
||||||
|
|
||||||
|
- /* Send window change event to monitor process. */
|
||||||
|
- send_command_status(ec, CMD_TTYWINCH, wsize_packed);
|
||||||
|
+ /* Update pty window size and send command SIGWINCH. */
|
||||||
|
+ (void)ioctl(io_fds[SFD_LEADER], TIOCSWINSZ, &wsize);
|
||||||
|
+ killpg(ec->cmnd_pid, SIGWINCH);
|
||||||
|
|
||||||
|
/* Update rows/cols. */
|
||||||
|
ec->rows = wsize.ws_row;
|
||||||
|
diff --git a/src/sudo.h b/src/sudo.h
|
||||||
|
index acb89b751..204c3e76e 100644
|
||||||
|
--- a/src/sudo.h
|
||||||
|
+++ b/src/sudo.h
|
||||||
|
@@ -225,7 +225,6 @@ struct command_status {
|
||||||
|
#define CMD_WSTATUS 2
|
||||||
|
#define CMD_SIGNO 3
|
||||||
|
#define CMD_PID 4
|
||||||
|
-#define CMD_TTYWINCH 5
|
||||||
|
int type;
|
||||||
|
int val;
|
||||||
|
};
|
||||||
|
--
|
||||||
|
2.33.0
|
||||||
|
|
||||||
25
backport-Set-command_info-to-NULL-once-it-is-freed.patch
Normal file
25
backport-Set-command_info-to-NULL-once-it-is-freed.patch
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
From 0bb41ed82a5849b0c64d7046662825d84e983e4d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Rose <83477269+AtariDreams@users.noreply.github.com>
|
||||||
|
Date: Mon, 26 Jun 2023 15:08:51 -0400
|
||||||
|
Subject: [PATCH] Set command_info to NULL once it is freed
|
||||||
|
|
||||||
|
The lack of setting to NULL is a holdover from when command_info was a local variable and not a global one. However, we given how other global variables are set to NULL, it is best that we do the same here to avoid potential issues should sudoers_policy_store_result be called again after the first time failed, otherwise we could get a double-free.
|
||||||
|
|
||||||
|
---
|
||||||
|
plugins/sudoers/policy.c | 1 +
|
||||||
|
1 file changed, 1 insertion(+)
|
||||||
|
|
||||||
|
diff --git a/plugins/sudoers/policy.c b/plugins/sudoers/policy.c
|
||||||
|
index 7157fab2b..f018caca2 100644
|
||||||
|
--- a/plugins/sudoers/policy.c
|
||||||
|
+++ b/plugins/sudoers/policy.c
|
||||||
|
@@ -1054,6 +1054,7 @@ bad:
|
||||||
|
while (info_len--)
|
||||||
|
free(command_info[info_len]);
|
||||||
|
free(command_info);
|
||||||
|
+ command_info = NULL;
|
||||||
|
debug_return_bool(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
--
|
||||||
|
2.23.0
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
From 2ffcda8e15afe312550be4017d8c40dbb438b786 Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Todd C. Miller" <Todd.Miller@sudo.ws>
|
||||||
|
Date: Thu, 2 Nov 2023 14:42:42 -0600
|
||||||
|
Subject: [PATCH] role_to_sudoers: only try to reuse a privilege if one is
|
||||||
|
present
|
||||||
|
|
||||||
|
Reference:https://github.com/sudo-project/sudo/commit/2ffcda8e15afe312550be4017d8c40dbb438b786
|
||||||
|
Conflict:NA
|
||||||
|
|
||||||
|
---
|
||||||
|
plugins/sudoers/parse_ldif.c | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/plugins/sudoers/parse_ldif.c b/plugins/sudoers/parse_ldif.c
|
||||||
|
index 87c94125c..180e7da6c 100644
|
||||||
|
--- a/plugins/sudoers/parse_ldif.c
|
||||||
|
+++ b/plugins/sudoers/parse_ldif.c
|
||||||
|
@@ -427,7 +427,7 @@ role_to_sudoers(struct sudoers_parse_tree *parse_tree, struct sudo_role *role,
|
||||||
|
U_("unable to allocate memory"));
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (reuse_privilege) {
|
||||||
|
+ if (reuse_privilege && !TAILQ_EMPTY(&us->privileges)) {
|
||||||
|
/* Hostspec unchanged, append cmndlist to previous privilege. */
|
||||||
|
struct privilege *prev_priv = TAILQ_LAST(&us->privileges, privilege_list);
|
||||||
|
if (reuse_runas) {
|
||||||
|
--
|
||||||
|
2.33.0
|
||||||
|
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
From a712af5a26d886d1db88d77575b7998a1944d3a9 Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Todd C. Miller" <Todd.Miller@sudo.ws>
|
||||||
|
Date: Fri, 18 Aug 2023 12:22:43 -0600
|
||||||
|
Subject: [PATCH] sudoers_parse_ldif: do not free parse_tree before using
|
||||||
|
|
||||||
|
The user is expected to pass in an initialized and empty parse_tree
|
||||||
|
so there is no need to free it first.
|
||||||
|
---
|
||||||
|
plugins/sudoers/parse_ldif.c | 3 ---
|
||||||
|
1 file changed, 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/plugins/sudoers/parse_ldif.c b/plugins/sudoers/parse_ldif.c
|
||||||
|
index a9944171b..98d84488a 100644
|
||||||
|
--- a/plugins/sudoers/parse_ldif.c
|
||||||
|
+++ b/plugins/sudoers/parse_ldif.c
|
||||||
|
@@ -582,9 +582,6 @@ sudoers_parse_ldif(struct sudoers_parse_tree *parse_tree,
|
||||||
|
int errors = 0;
|
||||||
|
debug_decl(sudoers_parse_ldif, SUDOERS_DEBUG_UTIL);
|
||||||
|
|
||||||
|
- /* Free old contents of the parse tree (if any). */
|
||||||
|
- free_parse_tree(parse_tree);
|
||||||
|
-
|
||||||
|
/*
|
||||||
|
* We cache user, group and host lists to make it eay to detect when there
|
||||||
|
* are identical lists (simple pointer compare). This makes it possible
|
||||||
|
--
|
||||||
|
2.33.0
|
||||||
|
|
||||||
26
sudo.spec
26
sudo.spec
@ -1,6 +1,6 @@
|
|||||||
Name: sudo
|
Name: sudo
|
||||||
Version: 1.9.8p2
|
Version: 1.9.8p2
|
||||||
Release: 13
|
Release: 18
|
||||||
Summary: Allows restricted root access for specified users
|
Summary: Allows restricted root access for specified users
|
||||||
License: ISC
|
License: ISC
|
||||||
URL: http://www.courtesan.com/sudo/
|
URL: http://www.courtesan.com/sudo/
|
||||||
@ -37,6 +37,15 @@ Patch23: backport-sudoers_main-defer-setting-return-value-until-the-en.patch
|
|||||||
Patch24: backport-sudo_putenv_nodebug-require-that-the-environment-str.patch
|
Patch24: backport-sudo_putenv_nodebug-require-that-the-environment-str.patch
|
||||||
Patch25: backport-Linux-execve-2-allows-argv-or-envp-to-be-NULL.patch
|
Patch25: backport-Linux-execve-2-allows-argv-or-envp-to-be-NULL.patch
|
||||||
Patch26: backport-Fix-potential-NULL-pointer-deference-found-by-clang-.patch
|
Patch26: backport-Fix-potential-NULL-pointer-deference-found-by-clang-.patch
|
||||||
|
Patch27: backport-Set-command_info-to-NULL-once-it-is-freed.patch
|
||||||
|
Patch28: backport-sudoers_parse_ldif-do-not-free-parse_tree-before-usi.patch
|
||||||
|
Patch29: backport-Do-not-rely-on-the-definition-of-ALLOW-DENY-being-tr.patch
|
||||||
|
Patch30: backport-CVE-2023-42465.patch
|
||||||
|
Patch31: backport-Make-all-match-functions-return-ALLOW-DENY-.patch
|
||||||
|
Patch32: backport-role_to_sudoers-only-try-to-reuse-a-privilege-if-one.patch
|
||||||
|
Patch33: backport-Move-updating-of-the-window-size-back-to-the-main-su.patch
|
||||||
|
Patch34: backport-If-user-s-tty-goes-away-tell-monitor-to-revoke-the-t.patch
|
||||||
|
Patch35: backport-Avoid-using-ioctl-TIOCNOTTY-in-the-monitor.patch
|
||||||
|
|
||||||
Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||||
Requires: pam
|
Requires: pam
|
||||||
@ -187,6 +196,21 @@ install -p -c -m 0644 %{SOURCE3} $RPM_BUILD_ROOT/etc/pam.d/sudo-i
|
|||||||
%exclude %{_pkgdocdir}/ChangeLog
|
%exclude %{_pkgdocdir}/ChangeLog
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Fri Apr 18 2025 fuanan <fuanan3@h-partners.com> - 1.9.8p2-18
|
||||||
|
- Backport patch from upstream community
|
||||||
|
|
||||||
|
* Wed Jan 31 2024 fuanan <fuanan3@h-partners.com> - 1.9.8p2-17
|
||||||
|
- Backport patch from upstream community
|
||||||
|
|
||||||
|
* Wed Jan 10 2024 wangqingsan <wangqingsan@huawei.com> - 1.9.8p2-16
|
||||||
|
- fix CVE-2023-42465
|
||||||
|
|
||||||
|
* Tue Nov 28 2023 zhangruifang <zhangruifang1@h-partners.com> - 1.9.8p2-15
|
||||||
|
- Backport patches from upstream community
|
||||||
|
|
||||||
|
* Mon Aug 07 2023 zhoushuiqing <zhoushuiqing2@huawei.com> - 1.9.8p2-14
|
||||||
|
- Backport patche from upstream community
|
||||||
|
|
||||||
* Tue Jun 13 2023 zhoushuiqing <zhoushuiqing2@huawei.com> - 1.9.8p2-13
|
* Tue Jun 13 2023 zhoushuiqing <zhoushuiqing2@huawei.com> - 1.9.8p2-13
|
||||||
- Backport patches from upstream community
|
- Backport patches from upstream community
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user