Compare commits

..

No commits in common. "b5579133e80c653fe1dad41650208dba8bc5ffa9" and "2f4d35adb1bdf030ce50a40bac344719aa324c3d" have entirely different histories.

10 changed files with 1 additions and 2586 deletions

View File

@ -1,225 +0,0 @@
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

View File

@ -1,442 +0,0 @@
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

View File

@ -1,249 +0,0 @@
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

View File

@ -1,212 +0,0 @@
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

File diff suppressed because it is too large Load Diff

View File

@ -1,234 +0,0 @@
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

View File

@ -1,25 +0,0 @@
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

View File

@ -1,29 +0,0 @@
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

View File

@ -1,28 +0,0 @@
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

View File

@ -1,6 +1,6 @@
Name: sudo
Version: 1.9.8p2
Release: 18
Release: 13
Summary: Allows restricted root access for specified users
License: ISC
URL: http://www.courtesan.com/sudo/
@ -37,15 +37,6 @@ Patch23: backport-sudoers_main-defer-setting-return-value-until-the-en.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
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)
Requires: pam
@ -196,21 +187,6 @@ install -p -c -m 0644 %{SOURCE3} $RPM_BUILD_ROOT/etc/pam.d/sudo-i
%exclude %{_pkgdocdir}/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
- Backport patches from upstream community