Update to 1.9.5p2
This commit is contained in:
parent
2b375dab5d
commit
425689e883
@ -1,90 +0,0 @@
|
||||
# HG changeset patch
|
||||
# Parent 111fde52d1166af65b622da6eae19791ce0e8871
|
||||
Reset valid_flags to MODE_NONINTERACTIVE for sudoedit.
|
||||
This is consistent with how the -e option is handled.
|
||||
Also reject -H and -P flags for sudoedit as was done in sudo 1.7.
|
||||
Found by Qualys.
|
||||
|
||||
--- a/src/parse_args.c
|
||||
+++ b/src/parse_args.c
|
||||
@@ -114,7 +114,10 @@ struct environment {
|
||||
/*
|
||||
* Default flags allowed when running a command.
|
||||
*/
|
||||
-#define DEFAULT_VALID_FLAGS (MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|MODE_LOGIN_SHELL|MODE_NONINTERACTIVE|MODE_SHELL)
|
||||
+#define DEFAULT_VALID_FLAGS (MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|MODE_LOGIN_SHELL|MODE_NONINTERACTIVE|MODE_PRESERVE_GROUPS|MODE_SHELL)
|
||||
+#define EDIT_VALID_FLAGS MODE_NONINTERACTIVE
|
||||
+#define LIST_VALID_FLAGS (MODE_NONINTERACTIVE|MODE_LONG_LIST)
|
||||
+#define VALIDATE_VALID_FLAGS MODE_NONINTERACTIVE
|
||||
|
||||
/* Option number for the --host long option due to ambiguity of the -h flag. */
|
||||
#define OPT_HOSTNAME 256
|
||||
@@ -257,6 +260,7 @@ parse_args(int argc, char **argv, int *o
|
||||
progname = "sudoedit";
|
||||
mode = MODE_EDIT;
|
||||
sudo_settings[ARG_SUDOEDIT].value = "true";
|
||||
+ valid_flags = EDIT_VALID_FLAGS;
|
||||
}
|
||||
|
||||
/* Load local IP addresses and masks. */
|
||||
@@ -354,7 +358,7 @@ parse_args(int argc, char **argv, int *o
|
||||
usage_excl();
|
||||
mode = MODE_EDIT;
|
||||
sudo_settings[ARG_SUDOEDIT].value = "true";
|
||||
- valid_flags = MODE_NONINTERACTIVE;
|
||||
+ valid_flags = EDIT_VALID_FLAGS;
|
||||
break;
|
||||
case 'g':
|
||||
assert(optarg != NULL);
|
||||
@@ -366,6 +370,7 @@ parse_args(int argc, char **argv, int *o
|
||||
break;
|
||||
case 'H':
|
||||
sudo_settings[ARG_SET_HOME].value = "true";
|
||||
+ SET(flags, MODE_RESET_HOME);
|
||||
break;
|
||||
case 'h':
|
||||
if (optarg == NULL) {
|
||||
@@ -420,7 +425,7 @@ parse_args(int argc, char **argv, int *o
|
||||
usage_excl();
|
||||
}
|
||||
mode = MODE_LIST;
|
||||
- valid_flags = MODE_NONINTERACTIVE|MODE_LONG_LIST;
|
||||
+ valid_flags = LIST_VALID_FLAGS;
|
||||
break;
|
||||
case 'n':
|
||||
SET(flags, MODE_NONINTERACTIVE);
|
||||
@@ -428,6 +433,7 @@ parse_args(int argc, char **argv, int *o
|
||||
break;
|
||||
case 'P':
|
||||
sudo_settings[ARG_PRESERVE_GROUPS].value = "true";
|
||||
+ SET(flags, MODE_PRESERVE_GROUPS);
|
||||
break;
|
||||
case 'p':
|
||||
/* An empty prompt is allowed. */
|
||||
@@ -486,7 +492,7 @@ parse_args(int argc, char **argv, int *o
|
||||
if (mode && mode != MODE_VALIDATE)
|
||||
usage_excl();
|
||||
mode = MODE_VALIDATE;
|
||||
- valid_flags = MODE_NONINTERACTIVE;
|
||||
+ valid_flags = VALIDATE_VALID_FLAGS;
|
||||
break;
|
||||
case 'V':
|
||||
if (mode && mode != MODE_VERSION)
|
||||
@@ -514,7 +520,7 @@ parse_args(int argc, char **argv, int *o
|
||||
if (!mode) {
|
||||
/* Defer -k mode setting until we know whether it is a flag or not */
|
||||
if (sudo_settings[ARG_IGNORE_TICKET].value != NULL) {
|
||||
- if (argc == 0 && !(flags & (MODE_SHELL|MODE_LOGIN_SHELL))) {
|
||||
+ if (argc == 0 && !ISSET(flags, MODE_SHELL|MODE_LOGIN_SHELL)) {
|
||||
mode = MODE_INVALIDATE; /* -k by itself */
|
||||
sudo_settings[ARG_IGNORE_TICKET].value = NULL;
|
||||
valid_flags = 0;
|
||||
@@ -578,7 +584,7 @@ parse_args(int argc, char **argv, int *o
|
||||
/*
|
||||
* For shell mode we need to rewrite argv
|
||||
*/
|
||||
- if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) {
|
||||
+ if (ISSET(flags, MODE_SHELL|MODE_LOGIN_SHELL) && ISSET(mode, MODE_RUN)) {
|
||||
char **av, *cmnd = NULL;
|
||||
int ac = 1;
|
||||
|
||||
@ -1,35 +0,0 @@
|
||||
# HG changeset patch
|
||||
# Parent 4e0af3ef53d71d1e0d1ee5894a0c078020ab391a
|
||||
Add sudoedit flag checks in plugin that are consistent with front-end.
|
||||
Don't assume the sudo front-end is sending reasonable mode flags.
|
||||
These checks need to be kept consistent between the sudo front-end
|
||||
and the sudoers plugin.
|
||||
|
||||
--- a/plugins/sudoers/policy.c
|
||||
+++ b/plugins/sudoers/policy.c
|
||||
@@ -87,10 +87,11 @@ parse_bool(const char *line, int varlen,
|
||||
int
|
||||
sudoers_policy_deserialize_info(void *v, char **runas_user, char **runas_group)
|
||||
{
|
||||
+ const int edit_mask = MODE_EDIT|MODE_IGNORE_TICKET|MODE_NONINTERACTIVE;
|
||||
struct sudoers_open_info *info = v;
|
||||
- char * const *cur;
|
||||
const char *p, *errstr, *groups = NULL;
|
||||
const char *remhost = NULL;
|
||||
+ char * const *cur;
|
||||
int flags = 0;
|
||||
debug_decl(sudoers_policy_deserialize_info, SUDOERS_DEBUG_PLUGIN);
|
||||
|
||||
@@ -319,6 +320,12 @@ sudoers_policy_deserialize_info(void *v,
|
||||
#endif
|
||||
}
|
||||
|
||||
+ /* Sudo front-end should restrict mode flags for sudoedit. */
|
||||
+ if (ISSET(flags, MODE_EDIT) && (flags & edit_mask) != flags) {
|
||||
+ sudo_warnx(U_("invalid mode flags from sudo front end: 0x%x"), flags);
|
||||
+ goto bad;
|
||||
+ }
|
||||
+
|
||||
user_gid = (gid_t)-1;
|
||||
user_sid = (pid_t)-1;
|
||||
user_uid = (gid_t)-1;
|
||||
@ -1,65 +0,0 @@
|
||||
Backport of:
|
||||
|
||||
# HG changeset patch
|
||||
# Parent 9b29e05ea310e187e41d8bcb58eddef8bd8b70d3
|
||||
Fix potential buffer overflow when unescaping backslashes in user_args.
|
||||
Do not try to unescaping backslashes unless in run mode *and* we are
|
||||
running the command via a shell.
|
||||
Found by Qualys.
|
||||
|
||||
--- a/plugins/sudoers/sudoers.c
|
||||
+++ b/plugins/sudoers/sudoers.c
|
||||
@@ -478,7 +478,7 @@ sudoers_policy_main(int argc, char * con
|
||||
|
||||
/* If run as root with SUDO_USER set, set sudo_user.pw to that user. */
|
||||
/* XXX - causes confusion when root is not listed in sudoers */
|
||||
- if (sudo_mode & (MODE_RUN | MODE_EDIT) && prev_user != NULL) {
|
||||
+ if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT) && prev_user != NULL) {
|
||||
if (user_uid == 0 && strcmp(prev_user, "root") != 0) {
|
||||
struct passwd *pw;
|
||||
|
||||
@@ -854,8 +854,8 @@ set_cmnd(void)
|
||||
if (user_cmnd == NULL)
|
||||
user_cmnd = NewArgv[0];
|
||||
|
||||
- if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) {
|
||||
- if (ISSET(sudo_mode, MODE_RUN | MODE_CHECK)) {
|
||||
+ if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT|MODE_CHECK)) {
|
||||
+ if (!ISSET(sudo_mode, MODE_EDIT)) {
|
||||
if (def_secure_path && !user_is_exempt())
|
||||
path = def_secure_path;
|
||||
if (!set_perms(PERM_RUNAS))
|
||||
@@ -894,7 +894,8 @@ set_cmnd(void)
|
||||
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||
debug_return_int(-1);
|
||||
}
|
||||
- if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {
|
||||
+ if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL) &&
|
||||
+ ISSET(sudo_mode, MODE_RUN)) {
|
||||
/*
|
||||
* When running a command via a shell, the sudo front-end
|
||||
* escapes potential meta chars. We unescape non-spaces
|
||||
@@ -902,10 +903,22 @@ set_cmnd(void)
|
||||
*/
|
||||
for (to = user_args, av = NewArgv + 1; (from = *av); av++) {
|
||||
while (*from) {
|
||||
- if (from[0] == '\\' && !isspace((unsigned char)from[1]))
|
||||
+ if (from[0] == '\\' && from[1] != '\0' &&
|
||||
+ !isspace((unsigned char)from[1])) {
|
||||
from++;
|
||||
+ }
|
||||
+ if (size - (to - user_args) < 1) {
|
||||
+ sudo_warnx(U_("internal error, %s overflow"),
|
||||
+ __func__);
|
||||
+ debug_return_int(NOT_FOUND_ERROR);
|
||||
+ }
|
||||
*to++ = *from++;
|
||||
}
|
||||
+ if (size - (to - user_args) < 1) {
|
||||
+ sudo_warnx(U_("internal error, %s overflow"),
|
||||
+ __func__);
|
||||
+ debug_return_int(NOT_FOUND_ERROR);
|
||||
+ }
|
||||
*to++ = ' ';
|
||||
}
|
||||
*--to = '\0';
|
||||
@ -1,19 +0,0 @@
|
||||
# HG changeset patch
|
||||
# Parent 5c6c54c8f971dfa21977935328942a57591ce5a8
|
||||
Fix the memset offset when converting a v1 timestamp to TS_LOCKEXCL.
|
||||
We want to zero the struct starting at flags, not type (which was just set).
|
||||
Found by Qualys.
|
||||
|
||||
--- a/plugins/sudoers/timestamp.c
|
||||
+++ b/plugins/sudoers/timestamp.c
|
||||
@@ -662,8 +662,8 @@ timestamp_lock(void *vcookie, struct pas
|
||||
if (entry.size == sizeof(struct timestamp_entry_v1)) {
|
||||
/* Old sudo record, convert it to TS_LOCKEXCL. */
|
||||
entry.type = TS_LOCKEXCL;
|
||||
- memset((char *)&entry + offsetof(struct timestamp_entry, type), 0,
|
||||
- nread - offsetof(struct timestamp_entry, type));
|
||||
+ memset((char *)&entry + offsetof(struct timestamp_entry, flags), 0,
|
||||
+ nread - offsetof(struct timestamp_entry, flags));
|
||||
if (ts_write(cookie->fd, cookie->fname, &entry, 0) == -1)
|
||||
debug_return_bool(false);
|
||||
} else {
|
||||
@ -1,31 +0,0 @@
|
||||
# HG changeset patch
|
||||
# Parent a84c8fe05da6097efaa00d8dee8a07b5816ae84e
|
||||
Don't assume that argv is allocated as a single flat buffer.
|
||||
While this is how the kernel behaves it is not a portable assumption.
|
||||
The assumption may also be violated if getopt_long(3) permutes arguments.
|
||||
Found by Qualys.
|
||||
|
||||
--- a/src/parse_args.c
|
||||
+++ b/src/parse_args.c
|
||||
@@ -591,16 +591,16 @@ parse_args(int argc, char **argv, int *o
|
||||
if (argc != 0) {
|
||||
/* shell -c "command" */
|
||||
char *src, *dst;
|
||||
- size_t cmnd_size = (size_t) (argv[argc - 1] - argv[0]) +
|
||||
- strlen(argv[argc - 1]) + 1;
|
||||
+ size_t size = 0;
|
||||
|
||||
- cmnd = dst = reallocarray(NULL, cmnd_size, 2);
|
||||
- if (cmnd == NULL)
|
||||
+ for (av = argv; *av != NULL; av++)
|
||||
+ size += strlen(*av) + 1;
|
||||
+ if (size == 0 || (cmnd = reallocarray(NULL, size, 2)) == NULL)
|
||||
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||
if (!gc_add(GC_PTR, cmnd))
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
- for (av = argv; *av != NULL; av++) {
|
||||
+ for (dst = cmnd, av = argv; *av != NULL; av++) {
|
||||
for (src = *av; *src != '\0'; src++) {
|
||||
/* quote potential meta characters */
|
||||
if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-' && *src != '$')
|
||||
@ -1,58 +0,0 @@
|
||||
From db1f27c0350e9e437c93780ffe88648ae1984467 Mon Sep 17 00:00:00 2001
|
||||
From: "Todd C. Miller" <Todd.Miller@sudo.ws>
|
||||
Date: Wed, 6 Jan 2021 10:16:00 -0700
|
||||
Subject: [PATCH] Fix potential directory existing info leak in sudoedit. When
|
||||
creating a new file, sudoedit checks to make sure the parent directory exists
|
||||
so it can provide the user with a sensible error message. However, this
|
||||
could be used to test for the existence of directories not normally
|
||||
accessible to the user by pointing to them with a symbolic link when the
|
||||
parent directory is controlled by the user. Problem reported by Matthias
|
||||
Gerstner of SUSE.
|
||||
|
||||
---
|
||||
src/sudo_edit.c | 29 ++++++++++++++++++++++++-----
|
||||
1 file changed, 24 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/src/sudo_edit.c b/src/sudo_edit.c
|
||||
index 82e04a71b..5502b7bd9 100644
|
||||
--- a/src/sudo_edit.c
|
||||
+++ b/src/sudo_edit.c
|
||||
@@ -541,14 +541,33 @@ sudo_edit_create_tfiles(struct command_details *command_details,
|
||||
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, command_details);
|
||||
if (ofd != -1 || errno == ENOENT) {
|
||||
if (ofd == -1) {
|
||||
- /* New file, verify parent dir exists unless in cwd. */
|
||||
+ /*
|
||||
+ * New file, verify parent dir exists unless in cwd.
|
||||
+ * This fails early so the user knows ahead of time if the
|
||||
+ * edit won't succeed. Additional checks are performed
|
||||
+ * when copying the temporary file back to the origin.
|
||||
+ */
|
||||
char *slash = strrchr(files[i], '/');
|
||||
if (slash != NULL && slash != files[i]) {
|
||||
- int serrno = errno;
|
||||
+ const int sflags = command_details->flags;
|
||||
+ const int serrno = errno;
|
||||
+ int dfd;
|
||||
+
|
||||
+ /*
|
||||
+ * The parent directory is allowed to be a symbolic
|
||||
+ * link as long as *its* parent is not writable.
|
||||
+ */
|
||||
*slash = '\0';
|
||||
- if (stat(files[i], &sb) == 0 && S_ISDIR(sb.st_mode)) {
|
||||
- memset(&sb, 0, sizeof(sb));
|
||||
- rc = 0;
|
||||
+ SET(command_details->flags, CD_SUDOEDIT_FOLLOW);
|
||||
+ dfd = sudo_edit_open(files[i], DIR_OPEN_FLAGS,
|
||||
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, command_details);
|
||||
+ command_details->flags = sflags;
|
||||
+ if (dfd != -1) {
|
||||
+ if (fstat(dfd, &sb) == 0 && S_ISDIR(sb.st_mode)) {
|
||||
+ memset(&sb, 0, sizeof(sb));
|
||||
+ rc = 0;
|
||||
+ }
|
||||
+ close(dfd);
|
||||
}
|
||||
*slash = '/';
|
||||
errno = serrno;
|
||||
@ -1,422 +0,0 @@
|
||||
From 7cd36222e765d8fc561e5a52a59a1c3a4feb38bb Mon Sep 17 00:00:00 2001
|
||||
From: "Todd C. Miller" <Todd.Miller@sudo.ws>
|
||||
Date: Wed, 6 Jan 2021 10:16:00 -0700
|
||||
Subject: [PATCH] Add security checks before using temp files for SELinux RBAC
|
||||
sudoedit. Otherwise, it may be possible for the user running sudoedit to
|
||||
replace the newly-created temporary files with a symbolic link and have
|
||||
sudoedit set the owner of an arbitrary file. Problem reported by Matthias
|
||||
Gerstner of SUSE.
|
||||
|
||||
---
|
||||
src/copy_file.c | 35 +++++++++++++++-
|
||||
src/sesh.c | 27 ++++++++-----
|
||||
src/sudo_edit.c | 104 +++++++++++++++++++++++++++++++-----------------
|
||||
src/sudo_exec.h | 4 +-
|
||||
4 files changed, 121 insertions(+), 49 deletions(-)
|
||||
|
||||
diff --git a/src/copy_file.c b/src/copy_file.c
|
||||
index a90a3743c..08a59fe11 100644
|
||||
--- a/src/copy_file.c
|
||||
+++ b/src/copy_file.c
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: ISC
|
||||
*
|
||||
- * Copyright (c) 2020 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||
+ * Copyright (c) 2020-2021 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
|
||||
@@ -23,6 +23,8 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
+#include <sys/stat.h>
|
||||
+
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
@@ -134,3 +136,34 @@ sudo_copy_file(const char *src, int src_fd, off_t src_len, const char *dst,
|
||||
sudo_warn(U_("unable to write to %s"), dst);
|
||||
debug_return_int(-1);
|
||||
}
|
||||
+
|
||||
+#ifdef HAVE_SELINUX
|
||||
+bool
|
||||
+sudo_check_temp_file(int tfd, const char *tfile, uid_t uid, struct stat *sb)
|
||||
+{
|
||||
+ struct stat sbuf;
|
||||
+ debug_decl(sudo_check_temp_file, SUDO_DEBUG_UTIL);
|
||||
+
|
||||
+ if (sb == NULL)
|
||||
+ sb = &sbuf;
|
||||
+
|
||||
+ if (fstat(tfd, sb) == -1) {
|
||||
+ sudo_warn(U_("unable to stat %s"), tfile);
|
||||
+ debug_return_bool(false);
|
||||
+ }
|
||||
+ if (!S_ISREG(sb->st_mode)) {
|
||||
+ sudo_warnx(U_("%s: not a regular file"), tfile);
|
||||
+ debug_return_bool(false);
|
||||
+ }
|
||||
+ if ((sb->st_mode & ALLPERMS) != (S_IRUSR|S_IWUSR)) {
|
||||
+ sudo_warnx(U_("%s: bad file mode: 0%o"), tfile, sb->st_mode & ALLPERMS);
|
||||
+ debug_return_bool(false);
|
||||
+ }
|
||||
+ if (sb->st_uid != uid) {
|
||||
+ sudo_warnx(U_("%s is owned by uid %u, should be %u"),
|
||||
+ tfile, (unsigned int)sb->st_uid, (unsigned int)uid);
|
||||
+ debug_return_bool(false);
|
||||
+ }
|
||||
+ debug_return_bool(true);
|
||||
+}
|
||||
+#endif /* SELINUX */
|
||||
diff --git a/src/sesh.c b/src/sesh.c
|
||||
index 8241f13f1..abbef2577 100644
|
||||
--- a/src/sesh.c
|
||||
+++ b/src/sesh.c
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: ISC
|
||||
*
|
||||
- * Copyright (c) 2008, 2010-2018, 2020 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||
+ * Copyright (c) 2008, 2010-2018, 2020-2021 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
|
||||
@@ -132,7 +132,7 @@ main(int argc, char *argv[], char *envp[])
|
||||
static int
|
||||
sesh_sudoedit(int argc, char *argv[])
|
||||
{
|
||||
- int i, oflags_dst, post, ret = SESH_ERR_FAILURE;
|
||||
+ int i, oflags_src, oflags_dst, post, ret = SESH_ERR_FAILURE;
|
||||
int fd_src = -1, fd_dst = -1, follow = 0;
|
||||
struct stat sb;
|
||||
struct timespec times[2];
|
||||
@@ -174,10 +174,12 @@ sesh_sudoedit(int argc, char *argv[])
|
||||
debug_return_int(SESH_ERR_BAD_PATHS);
|
||||
|
||||
/*
|
||||
- * Use O_EXCL if we are not in the post editing stage
|
||||
- * so that it's ensured that the temporary files are
|
||||
- * created by us and that we are not opening any symlinks.
|
||||
+ * In the pre-editing stage, use O_EXCL to ensure that the temporary
|
||||
+ * files are created by us and that we are not opening any symlinks.
|
||||
+ * In the post-editing stage, use O_NOFOLLOW so we don't follow symlinks
|
||||
+ * when opening the temporary files.
|
||||
*/
|
||||
+ oflags_src = O_RDONLY|(post ? O_NONBLOCK|O_NOFOLLOW : follow);
|
||||
oflags_dst = O_WRONLY|O_CREAT|(post ? follow : O_EXCL);
|
||||
for (i = 0; i < argc - 1; i += 2) {
|
||||
const char *path_src = argv[i];
|
||||
@@ -187,7 +189,7 @@ sesh_sudoedit(int argc, char *argv[])
|
||||
* doesn't exist, that's OK, we'll create an empty
|
||||
* destination file.
|
||||
*/
|
||||
- if ((fd_src = open(path_src, O_RDONLY|follow, S_IRUSR|S_IWUSR)) < 0) {
|
||||
+ if ((fd_src = open(path_src, oflags_src, S_IRUSR|S_IWUSR)) < 0) {
|
||||
if (errno != ENOENT) {
|
||||
sudo_warn("%s", path_src);
|
||||
if (post) {
|
||||
@@ -197,6 +199,14 @@ sesh_sudoedit(int argc, char *argv[])
|
||||
goto cleanup_0;
|
||||
}
|
||||
}
|
||||
+ if (post) {
|
||||
+ /* Make sure the temporary file is safe and has the proper owner. */
|
||||
+ if (!sudo_check_temp_file(fd_src, path_src, geteuid(), &sb)) {
|
||||
+ ret = SESH_ERR_SOME_FILES;
|
||||
+ goto nocleanup;
|
||||
+ }
|
||||
+ fcntl(fd_src, F_SETFL, fcntl(fd_src, F_GETFL, 0) & ~O_NONBLOCK);
|
||||
+ }
|
||||
|
||||
if ((fd_dst = open(path_dst, oflags_dst, post ?
|
||||
(S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) : (S_IRUSR|S_IWUSR))) < 0) {
|
||||
@@ -214,10 +224,7 @@ sesh_sudoedit(int argc, char *argv[])
|
||||
off_t len_dst = -1;
|
||||
|
||||
if (post) {
|
||||
- if (fstat(fd_src, &sb) != 0) {
|
||||
- ret = SESH_ERR_SOME_FILES;
|
||||
- goto nocleanup;
|
||||
- }
|
||||
+ /* sudo_check_temp_file() filled in sb for us. */
|
||||
len_src = sb.st_size;
|
||||
if (fstat(fd_dst, &sb) != 0) {
|
||||
ret = SESH_ERR_SOME_FILES;
|
||||
diff --git a/src/sudo_edit.c b/src/sudo_edit.c
|
||||
index 5502b7bd9..93810c346 100644
|
||||
--- a/src/sudo_edit.c
|
||||
+++ b/src/sudo_edit.c
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: ISC
|
||||
*
|
||||
- * Copyright (c) 2004-2008, 2010-2020 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||
+ * Copyright (c) 2004-2008, 2010-2021 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
|
||||
@@ -259,8 +259,10 @@ sudo_edit_mktemp(const char *ofile, char **tfile)
|
||||
} else {
|
||||
len = asprintf(tfile, "%s/%s.XXXXXXXX", edit_tmpdir, cp);
|
||||
}
|
||||
- if (len == -1)
|
||||
- sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||
+ if (len == -1) {
|
||||
+ sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||
+ debug_return_int(-1);
|
||||
+ }
|
||||
tfd = mkstemps(*tfile, suff ? strlen(suff) : 0);
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
||||
"%s -> %s, fd %d", ofile, *tfile, tfd);
|
||||
@@ -735,7 +737,8 @@ sudo_edit_copy_tfiles(struct command_details *command_details,
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
static int
|
||||
-selinux_run_helper(char *argv[], char *envp[])
|
||||
+selinux_run_helper(uid_t uid, gid_t gid, int ngroups, GETGROUPS_T *groups,
|
||||
+ char *const argv[], char *const envp[])
|
||||
{
|
||||
int status, ret = SESH_ERR_FAILURE;
|
||||
const char *sesh;
|
||||
@@ -755,8 +758,10 @@ selinux_run_helper(char *argv[], char *envp[])
|
||||
break;
|
||||
case 0:
|
||||
/* child runs sesh in new context */
|
||||
- if (selinux_setcon() == 0)
|
||||
+ if (selinux_setcon() == 0) {
|
||||
+ switch_user(uid, gid, ngroups, groups);
|
||||
execve(sesh, argv, envp);
|
||||
+ }
|
||||
_exit(SESH_ERR_FAILURE);
|
||||
default:
|
||||
/* parent waits */
|
||||
@@ -775,7 +780,7 @@ selinux_edit_create_tfiles(struct command_details *command_details,
|
||||
struct tempfile *tf, char *files[], int nfiles)
|
||||
{
|
||||
char **sesh_args, **sesh_ap;
|
||||
- int i, rc, sesh_nargs;
|
||||
+ int i, error, sesh_nargs, ret = -1;
|
||||
struct stat sb;
|
||||
debug_decl(selinux_edit_create_tfiles, SUDO_DEBUG_EDIT);
|
||||
|
||||
@@ -787,7 +792,7 @@ selinux_edit_create_tfiles(struct command_details *command_details,
|
||||
sesh_args = sesh_ap = reallocarray(NULL, sesh_nargs, sizeof(char *));
|
||||
if (sesh_args == NULL) {
|
||||
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||
- debug_return_int(-1);
|
||||
+ goto done;
|
||||
}
|
||||
*sesh_ap++ = "sesh";
|
||||
*sesh_ap++ = "-e";
|
||||
@@ -795,7 +800,6 @@ selinux_edit_create_tfiles(struct command_details *command_details,
|
||||
*sesh_ap++ = "-h";
|
||||
*sesh_ap++ = "0";
|
||||
|
||||
- /* XXX - temp files should be created with user's context */
|
||||
for (i = 0; i < nfiles; i++) {
|
||||
char *tfile, *ofile = files[i];
|
||||
int tfd;
|
||||
@@ -813,8 +817,7 @@ selinux_edit_create_tfiles(struct command_details *command_details,
|
||||
if (tfd == -1) {
|
||||
sudo_warn("mkstemps");
|
||||
free(tfile);
|
||||
- free(sesh_args);
|
||||
- debug_return_int(-1);
|
||||
+ goto done;
|
||||
}
|
||||
/* Helper will re-create temp file with proper security context. */
|
||||
close(tfd);
|
||||
@@ -825,8 +828,10 @@ selinux_edit_create_tfiles(struct command_details *command_details,
|
||||
*sesh_ap = NULL;
|
||||
|
||||
/* Run sesh -e [-h] 0 <o1> <t1> ... <on> <tn> */
|
||||
- rc = selinux_run_helper(sesh_args, command_details->envp);
|
||||
- switch (rc) {
|
||||
+ error = selinux_run_helper(command_details->uid, command_details->gid,
|
||||
+ command_details->ngroups, command_details->groups, sesh_args,
|
||||
+ command_details->envp);
|
||||
+ switch (error) {
|
||||
case SESH_SUCCESS:
|
||||
break;
|
||||
case SESH_ERR_BAD_PATHS:
|
||||
@@ -836,21 +841,35 @@ selinux_edit_create_tfiles(struct command_details *command_details,
|
||||
case SESH_ERR_KILLED:
|
||||
sudo_fatalx("%s", U_("sesh: killed by a signal"));
|
||||
default:
|
||||
- sudo_fatalx(U_("sesh: unknown error %d"), rc);
|
||||
+ sudo_warnx(U_("sesh: unknown error %d"), error);
|
||||
+ goto done;
|
||||
}
|
||||
|
||||
- /* Chown to user's UID so they can edit the temporary files. */
|
||||
for (i = 0; i < nfiles; i++) {
|
||||
- if (chown(tf[i].tfile, user_details.uid, user_details.gid) != 0) {
|
||||
+ int tfd = open(tf[i].tfile, O_RDONLY|O_NONBLOCK|O_NOFOLLOW);
|
||||
+ if (tfd == -1) {
|
||||
+ sudo_warn(U_("unable to open %s"), tf[i].tfile);
|
||||
+ goto done;
|
||||
+ }
|
||||
+ if (!sudo_check_temp_file(tfd, tf[i].tfile, command_details->uid, NULL)) {
|
||||
+ close(tfd);
|
||||
+ goto done;
|
||||
+ }
|
||||
+ if (fchown(tfd, user_details.uid, user_details.gid) != 0) {
|
||||
sudo_warn("unable to chown(%s) to %d:%d for editing",
|
||||
tf[i].tfile, user_details.uid, user_details.gid);
|
||||
+ close(tfd);
|
||||
+ goto done;
|
||||
}
|
||||
+ close(tfd);
|
||||
}
|
||||
+ ret = nfiles;
|
||||
|
||||
+done:
|
||||
/* Contents of tf will be freed by caller. */
|
||||
free(sesh_args);
|
||||
|
||||
- return (nfiles);
|
||||
+ debug_return_int(ret);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -858,7 +877,8 @@ selinux_edit_copy_tfiles(struct command_details *command_details,
|
||||
struct tempfile *tf, int nfiles, struct timespec *times)
|
||||
{
|
||||
char **sesh_args, **sesh_ap;
|
||||
- int i, rc, sesh_nargs, ret = 1;
|
||||
+ int i, error, sesh_nargs, ret = 1;
|
||||
+ int tfd = -1;
|
||||
struct timespec ts;
|
||||
struct stat sb;
|
||||
debug_decl(selinux_edit_copy_tfiles, SUDO_DEBUG_EDIT);
|
||||
@@ -879,33 +899,43 @@ selinux_edit_copy_tfiles(struct command_details *command_details,
|
||||
|
||||
/* Construct args for sesh -e 1 */
|
||||
for (i = 0; i < nfiles; i++) {
|
||||
- if (stat(tf[i].tfile, &sb) == 0) {
|
||||
- mtim_get(&sb, ts);
|
||||
- if (tf[i].osize == sb.st_size && sudo_timespeccmp(&tf[i].omtim, &ts, ==)) {
|
||||
- /*
|
||||
- * If mtime and size match but the user spent no measurable
|
||||
- * time in the editor we can't tell if the file was changed.
|
||||
- */
|
||||
- if (sudo_timespeccmp(×[0], ×[1], !=)) {
|
||||
- sudo_warnx(U_("%s unchanged"), tf[i].ofile);
|
||||
- unlink(tf[i].tfile);
|
||||
- continue;
|
||||
- }
|
||||
+ if (tfd != -1)
|
||||
+ close(tfd);
|
||||
+ if ((tfd = open(tf[i].tfile, O_RDONLY|O_NONBLOCK|O_NOFOLLOW)) == -1) {
|
||||
+ sudo_warn(U_("unable to open %s"), tf[i].tfile);
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (!sudo_check_temp_file(tfd, tf[i].tfile, user_details.uid, &sb))
|
||||
+ continue;
|
||||
+ mtim_get(&sb, ts);
|
||||
+ if (tf[i].osize == sb.st_size && sudo_timespeccmp(&tf[i].omtim, &ts, ==)) {
|
||||
+ /*
|
||||
+ * If mtime and size match but the user spent no measurable
|
||||
+ * time in the editor we can't tell if the file was changed.
|
||||
+ */
|
||||
+ if (sudo_timespeccmp(×[0], ×[1], !=)) {
|
||||
+ sudo_warnx(U_("%s unchanged"), tf[i].ofile);
|
||||
+ unlink(tf[i].tfile);
|
||||
+ continue;
|
||||
}
|
||||
}
|
||||
*sesh_ap++ = tf[i].tfile;
|
||||
*sesh_ap++ = tf[i].ofile;
|
||||
- if (chown(tf[i].tfile, command_details->uid, command_details->gid) != 0) {
|
||||
+ if (fchown(tfd, command_details->uid, command_details->gid) != 0) {
|
||||
sudo_warn("unable to chown(%s) back to %d:%d", tf[i].tfile,
|
||||
command_details->uid, command_details->gid);
|
||||
}
|
||||
}
|
||||
*sesh_ap = NULL;
|
||||
+ if (tfd != -1)
|
||||
+ close(tfd);
|
||||
|
||||
if (sesh_ap - sesh_args > 3) {
|
||||
/* Run sesh -e 1 <t1> <o1> ... <tn> <on> */
|
||||
- rc = selinux_run_helper(sesh_args, command_details->envp);
|
||||
- switch (rc) {
|
||||
+ error = selinux_run_helper(command_details->uid, command_details->gid,
|
||||
+ command_details->ngroups, command_details->groups, sesh_args,
|
||||
+ command_details->envp);
|
||||
+ switch (error) {
|
||||
case SESH_SUCCESS:
|
||||
ret = 0;
|
||||
break;
|
||||
@@ -921,7 +951,7 @@ selinux_edit_copy_tfiles(struct command_details *command_details,
|
||||
sudo_warnx("%s", U_("sesh: killed by a signal"));
|
||||
break;
|
||||
default:
|
||||
- sudo_warnx(U_("sesh: unknown error %d"), rc);
|
||||
+ sudo_warnx(U_("sesh: unknown error %d"), error);
|
||||
break;
|
||||
}
|
||||
if (ret != 0)
|
||||
@@ -943,7 +973,7 @@ sudo_edit(struct command_details *command_details)
|
||||
{
|
||||
struct command_details saved_command_details;
|
||||
char **nargv = NULL, **ap, **files = NULL;
|
||||
- int errors, i, ac, nargc, rc;
|
||||
+ int errors, i, ac, nargc, ret;
|
||||
int editor_argc = 0, nfiles = 0;
|
||||
struct timespec times[2];
|
||||
struct tempfile *tf = NULL;
|
||||
@@ -1038,7 +1068,7 @@ sudo_edit(struct command_details *command_details)
|
||||
command_details->ngroups = user_details.ngroups;
|
||||
command_details->groups = user_details.groups;
|
||||
command_details->argv = nargv;
|
||||
- rc = run_command(command_details);
|
||||
+ ret = run_command(command_details);
|
||||
if (sudo_gettime_real(×[1]) == -1) {
|
||||
sudo_warn("%s", U_("unable to read the clock"));
|
||||
goto cleanup;
|
||||
@@ -1062,14 +1092,14 @@ sudo_edit(struct command_details *command_details)
|
||||
errors = sudo_edit_copy_tfiles(command_details, tf, nfiles, times);
|
||||
if (errors) {
|
||||
/* Preserve the edited temporary files. */
|
||||
- rc = W_EXITCODE(1, 0);
|
||||
+ ret = W_EXITCODE(1, 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < nfiles; i++)
|
||||
free(tf[i].tfile);
|
||||
free(tf);
|
||||
free(nargv);
|
||||
- debug_return_int(rc);
|
||||
+ debug_return_int(ret);
|
||||
|
||||
cleanup:
|
||||
/* Clean up temp files and return. */
|
||||
diff --git a/src/sudo_exec.h b/src/sudo_exec.h
|
||||
index 39164a785..ec213a6f0 100644
|
||||
--- a/src/sudo_exec.h
|
||||
+++ b/src/sudo_exec.h
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: ISC
|
||||
*
|
||||
- * Copyright (c) 2010-2016 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||
+ * Copyright (c) 2010-2017, 2020-2021 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
|
||||
@@ -84,9 +84,11 @@
|
||||
*/
|
||||
struct command_details;
|
||||
struct command_status;
|
||||
+struct stat;
|
||||
|
||||
/* copy_file.c */
|
||||
int sudo_copy_file(const char *src, int src_fd, off_t src_len, const char *dst, int dst_fd, off_t dst_len);
|
||||
+bool sudo_check_temp_file(int tfd, const char *tname, uid_t uid, struct stat *sb);
|
||||
|
||||
/* exec.c */
|
||||
void exec_cmnd(struct command_details *details, int errfd);
|
||||
@ -1,43 +0,0 @@
|
||||
From 92e5d81943c890d3ea4b9c140d968563c63b8309 Mon Sep 17 00:00:00 2001
|
||||
From: Evan Anderson <evan@eaanderson.com>
|
||||
Date: Sun, 6 Sep 2020 14:30:54 -0500
|
||||
Subject: [PATCH] configure: Fix runstatedir handling for distros that do not
|
||||
support it
|
||||
|
||||
runstatedir was added in yet-to-be released autoconf 2.70. Some distros
|
||||
are shipping this addition in their autoconf packages, but others, such as Fedora,
|
||||
are not. This causes the rundir variable to be set incorrectly if the configure script
|
||||
is regenerated with an unpatched autoconf since the runstatedir variable set is deleted
|
||||
after regeneration. This change works around that problem by checking that runstatedir
|
||||
is non-empty before potentially using it to set the rundir variable
|
||||
---
|
||||
configure | 2 +-
|
||||
m4/sudo.m4 | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/configure b/configure
|
||||
index 0f6ceb16c..2e0838e01 100755
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -26718,7 +26718,7 @@ EOF
|
||||
$as_echo_n "checking for sudo run dir location... " >&6; }
|
||||
if test -n "$with_rundir"; then
|
||||
rundir="$with_rundir"
|
||||
-elif test "$runstatedir" != '${localstatedir}/run'; then
|
||||
+elif test -n "$runstatedir" && test "$runstatedir" != '${localstatedir}/run'; then
|
||||
rundir="$runstatedir/sudo"
|
||||
else
|
||||
# No --with-rundir or --runstatedir specified
|
||||
diff --git a/m4/sudo.m4 b/m4/sudo.m4
|
||||
index a5a972b3c..b3a40b208 100644
|
||||
--- a/m4/sudo.m4
|
||||
+++ b/m4/sudo.m4
|
||||
@@ -120,7 +120,7 @@ dnl
|
||||
AC_DEFUN([SUDO_RUNDIR], [AC_MSG_CHECKING(for sudo run dir location)
|
||||
if test -n "$with_rundir"; then
|
||||
rundir="$with_rundir"
|
||||
-elif test "$runstatedir" != '${localstatedir}/run'; then
|
||||
+elif test -n "$runstatedir" && test "$runstatedir" != '${localstatedir}/run'; then
|
||||
rundir="$runstatedir/sudo"
|
||||
else
|
||||
# No --with-rundir or --runstatedir specified
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
BIN
sudo-1.9.5p2.tar.gz
Normal file
BIN
sudo-1.9.5p2.tar.gz
Normal file
Binary file not shown.
31
sudo.spec
31
sudo.spec
@ -1,6 +1,6 @@
|
||||
Name: sudo
|
||||
Version: 1.9.2
|
||||
Release: 3
|
||||
Version: 1.9.5p2
|
||||
Release: 1
|
||||
Summary: Allows restricted root access for specified users
|
||||
License: ISC
|
||||
URL: http://www.courtesan.com/sudo/
|
||||
@ -10,16 +10,6 @@ Source1: sudoers
|
||||
Source2: sudo
|
||||
Source3: sudo-i
|
||||
|
||||
Patch0: backport-CVE-2021-23239-Fix-potential-directory.patch
|
||||
Patch1: backport-Fix-some-warnings-from-pvs-studio.patch
|
||||
Patch2: backport-CVE-2021-23240-Add-security-checks.patch
|
||||
Patch3: backport-0001-CVE-2021-3156-Reset-valid_flags.patch
|
||||
Patch4: backport-0002-CVE-2021-3156-Add-sudoedit-flag-checks.patch
|
||||
Patch5: backport-0003-CVE-2021-3156-Fix-potential-buffer-overflow.patch
|
||||
Patch6: backport-0004-CVE-2021-3156-Fix-the-memset-offset.patch
|
||||
Patch7: backport-0005-CVE-2021-3156-Dont-assume-that-argv.patch
|
||||
Patch8: backport-Fix-runstatedir-handling-for-distros-that-do-not-support-it.patch
|
||||
|
||||
Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
Requires: pam
|
||||
Recommends: vim-minimal
|
||||
@ -27,7 +17,7 @@ Requires(post): coreutils
|
||||
|
||||
BuildRequires: pam-devel groff openldap-devel flex bison automake autoconf libtool
|
||||
BuildRequires: audit-libs-devel libcap-devel libselinux-devel sendmail gettext zlib-devel
|
||||
BuildRequires: chrpath git
|
||||
BuildRequires: chrpath git openssl-devel python3-devel
|
||||
|
||||
%description
|
||||
Sudo is a program designed to allow a sysadmin to give limited root privileges
|
||||
@ -55,9 +45,8 @@ export CFLAGS="$RPM_OPT_FLAGS -fpie" LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now"
|
||||
--sbindir=%{_sbindir} \
|
||||
--libdir=%{_libdir} \
|
||||
--docdir=%{_pkgdocdir} \
|
||||
--enable-openssl \
|
||||
--disable-root-mailer \
|
||||
--disable-log-server \
|
||||
--disable-log-client \
|
||||
--with-logging=syslog \
|
||||
--with-logfac=authpriv \
|
||||
--with-pam \
|
||||
@ -69,6 +58,7 @@ export CFLAGS="$RPM_OPT_FLAGS -fpie" LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now"
|
||||
--with-ldap \
|
||||
--with-selinux \
|
||||
--with-passprompt="[sudo] password for %p: " \
|
||||
--enable-python \
|
||||
--with-linux-audit \
|
||||
--with-sssd
|
||||
|
||||
@ -123,8 +113,8 @@ install -p -c -m 0644 %{SOURCE3} $RPM_BUILD_ROOT/etc/pam.d/sudo-i
|
||||
%attr(0440,root,root) %config(noreplace) /etc/sudoers
|
||||
%attr(0750,root,root) %dir /etc/sudoers.d/
|
||||
%attr(0644,root,root) %{_tmpfilesdir}/sudo.conf
|
||||
%attr(0644,root,root) /etc/dnf/protected.d/sudo.conf
|
||||
%attr(0640,root,root) /etc/sudo.conf
|
||||
%attr(0644,root,root) %config(noreplace) /etc/dnf/protected.d/sudo.conf
|
||||
%attr(0640,root,root) %config(noreplace) /etc/sudo.conf
|
||||
%attr(4111,root,root) %{_bindir}/sudo
|
||||
%attr(0111,root,root) %{_bindir}/sudoreplay
|
||||
%{_bindir}/sudoedit
|
||||
@ -138,6 +128,10 @@ install -p -c -m 0644 %{SOURCE3} $RPM_BUILD_ROOT/etc/pam.d/sudo-i
|
||||
%attr(0644,root,root) %{_libexecdir}/sudo/audit_json.so
|
||||
%attr(0644,root,root) %{_libexecdir}/sudo/sample_approval.so
|
||||
%attr(0644,root,root) %{_libexecdir}/sudo/libsudo_util.so*
|
||||
%attr(0644,root,root) %{_libexecdir}/sudo/python_plugin.so
|
||||
%attr(0640,root,root) %config(noreplace) /etc/sudo_logsrvd.conf
|
||||
%attr(0755,root,root) %{_sbindir}/sudo_logsrvd
|
||||
%attr(0755,root,root) %{_sbindir}/sudo_sendlog
|
||||
%dir /var/db/sudo
|
||||
%dir /var/db/sudo/lectured
|
||||
%dir %{_libexecdir}/sudo
|
||||
@ -159,6 +153,9 @@ install -p -c -m 0644 %{SOURCE3} $RPM_BUILD_ROOT/etc/pam.d/sudo-i
|
||||
%exclude %{_pkgdocdir}/ChangeLog
|
||||
|
||||
%changelog
|
||||
* Wed Jul 7 2021 panxiaohe <panxiaohe@huawei.com> - 1.9.5p2-1
|
||||
- Update to 1.9.5p2
|
||||
|
||||
* Fri Jan 29 2021 zoulin <zoulin13@huawei.com> - 1.9.2-3
|
||||
- Fix runstatedir handling for distros that do not support it
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user