Pass resource limits values to the plugin in user_info[]
Sudo resets the resource limits early in its execution so the plugin cannot tell what the original limits were itself.
This commit is contained in:
5
NEWS
5
NEWS
@@ -44,6 +44,11 @@ What's new in Sudo 1.9.3
|
||||
for "sudoers_policy" but "sudoers_audit" is not listed, those
|
||||
arguments will be applied to "sudoers_audit" instead.
|
||||
|
||||
* The user's resource limits are now passed to sudo plugins in
|
||||
the user_info[] list. A plugin cannot determine the limits
|
||||
itself because sudo changes the limits while it runs to prevent
|
||||
resource starvation.
|
||||
|
||||
What's new in Sudo 1.9.2
|
||||
|
||||
* Fixed package builds on RedHat Enterprise Linux 8.
|
||||
|
@@ -16,7 +16,7 @@
|
||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.TH "SUDO_PLUGIN" "5" "June 16, 2020" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
|
||||
.TH "SUDO_PLUGIN" "5" "August 31, 2020" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
|
||||
.nh
|
||||
.if n .ad l
|
||||
.SH "NAME"
|
||||
@@ -513,6 +513,97 @@ The parent process ID of the running
|
||||
process.
|
||||
Only available starting with API version 1.2.
|
||||
.TP 6n
|
||||
rlimit_as=soft,hard
|
||||
The maximum size to which the process's address space may grow (in bytes),
|
||||
if supported by the operating system.
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
\(lqinfinity\(rq
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.TP 6n
|
||||
rlimit_core=soft,hard
|
||||
The largest size core dump file that may be created (in bytes).
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
\(lqinfinity\(rq
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.TP 6n
|
||||
rlimit_cpu=soft,hard
|
||||
The maximum amount of CPU time that the process may use (in seconds).
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
\(lqinfinity\(rq
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.TP 6n
|
||||
rlimit_data=soft,hard
|
||||
The maximum size of the data segment for the process (in bytes).
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
\(lqinfinity\(rq
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.TP 6n
|
||||
rlimit_fsize=soft,hard
|
||||
The largest size file that the process may create (in bytes).
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
\(lqinfinity\(rq
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.TP 6n
|
||||
rlimit_locks=soft,hard
|
||||
The maximum number of locks that the process may establish,
|
||||
if supported by the operating system.
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
\(lqinfinity\(rq
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.TP 6n
|
||||
rlimit_memlock=soft,hard
|
||||
The maximum size that the process may lock in memory (in bytes),
|
||||
if supported by the operating system.
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
\(lqinfinity\(rq
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.TP 6n
|
||||
rlimit_nofile=soft,hard
|
||||
The maximum number of files that the process may have open.
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
\(lqinfinity\(rq
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.TP 6n
|
||||
rlimit_nproc=soft,hard
|
||||
The maximum number of processes that the user may run simultaneously.
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
\(lqinfinity\(rq
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.TP 6n
|
||||
rlimit_rss=soft,hard
|
||||
The maximum size to which the process's resident set size may grow (in bytes).
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
\(lqinfinity\(rq
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.TP 6n
|
||||
rlimit_stack=soft,hard
|
||||
The maximum size to which the process's stack may grow (in bytes).
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
\(lqinfinity\(rq
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.TP 6n
|
||||
sid=int
|
||||
The session ID of the running
|
||||
\fBsudo\fR
|
||||
@@ -4942,6 +5033,11 @@ command was not run.
|
||||
has increased from 255 to 1023 bytes.
|
||||
.sp
|
||||
Support for audit and approval plugins was added.
|
||||
.TP 6n
|
||||
Version 1.16 (sudo 1.9.3)
|
||||
Initial resource limit values were added to the
|
||||
\fRuser_info\fR
|
||||
list.
|
||||
.SH "SEE ALSO"
|
||||
sudo.conf(@mansectform@),
|
||||
sudoers(@mansectform@),
|
||||
|
@@ -15,7 +15,7 @@
|
||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd June 16, 2020
|
||||
.Dd August 31, 2020
|
||||
.Dt SUDO_PLUGIN @mansectform@
|
||||
.Os Sudo @PACKAGE_VERSION@
|
||||
.Sh NAME
|
||||
@@ -456,6 +456,86 @@ The parent process ID of the running
|
||||
.Nm sudo
|
||||
process.
|
||||
Only available starting with API version 1.2.
|
||||
.It rlimit_as=soft,hard
|
||||
The maximum size to which the process's address space may grow (in bytes),
|
||||
if supported by the operating system.
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
.Dq infinity
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.It rlimit_core=soft,hard
|
||||
The largest size core dump file that may be created (in bytes).
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
.Dq infinity
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.It rlimit_cpu=soft,hard
|
||||
The maximum amount of CPU time that the process may use (in seconds).
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
.Dq infinity
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.It rlimit_data=soft,hard
|
||||
The maximum size of the data segment for the process (in bytes).
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
.Dq infinity
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.It rlimit_fsize=soft,hard
|
||||
The largest size file that the process may create (in bytes).
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
.Dq infinity
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.It rlimit_locks=soft,hard
|
||||
The maximum number of locks that the process may establish,
|
||||
if supported by the operating system.
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
.Dq infinity
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.It rlimit_memlock=soft,hard
|
||||
The maximum size that the process may lock in memory (in bytes),
|
||||
if supported by the operating system.
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
.Dq infinity
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.It rlimit_nofile=soft,hard
|
||||
The maximum number of files that the process may have open.
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
.Dq infinity
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.It rlimit_nproc=soft,hard
|
||||
The maximum number of processes that the user may run simultaneously.
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
.Dq infinity
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.It rlimit_rss=soft,hard
|
||||
The maximum size to which the process's resident set size may grow (in bytes).
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
.Dq infinity
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.It rlimit_stack=soft,hard
|
||||
The maximum size to which the process's stack may grow (in bytes).
|
||||
The soft and hard limits are separated by a comma.
|
||||
A value of
|
||||
.Dq infinity
|
||||
indicates that there is no limit.
|
||||
Only available starting with API version 1.16.
|
||||
.It sid=int
|
||||
The session ID of the running
|
||||
.Nm sudo
|
||||
@@ -4367,6 +4447,10 @@ command was not run.
|
||||
has increased from 255 to 1023 bytes.
|
||||
.Pp
|
||||
Support for audit and approval plugins was added.
|
||||
.It Version 1.16 (sudo 1.9.3)
|
||||
Initial resource limit values were added to the
|
||||
.Li user_info
|
||||
list.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr sudo.conf @mansectform@ ,
|
||||
|
@@ -21,7 +21,7 @@
|
||||
|
||||
/* API version major/minor */
|
||||
#define SUDO_API_VERSION_MAJOR 1
|
||||
#define SUDO_API_VERSION_MINOR 15
|
||||
#define SUDO_API_VERSION_MINOR 16
|
||||
#define SUDO_API_MKVERSION(x, y) (((x) << 16) | (y))
|
||||
#define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR, SUDO_API_VERSION_MINOR)
|
||||
|
||||
|
@@ -26,7 +26,7 @@
|
||||
"INFO1=VALUE1",
|
||||
"info2=value2"
|
||||
\],
|
||||
"version": "1.15"
|
||||
"version": "1.16"
|
||||
}
|
||||
(APPROVAL 2) Constructed:
|
||||
{
|
||||
@@ -56,7 +56,7 @@
|
||||
"INFO1=VALUE1",
|
||||
"info2=value2"
|
||||
\],
|
||||
"version": "1.15"
|
||||
"version": "1.16"
|
||||
}
|
||||
(APPROVAL 1) Show version was called with arguments: (0,)
|
||||
Python approval plugin (API 1.0): ApprovalTestPlugin (loaded from 'SRC_DIR/regress/plugin_approval_test.py')
|
||||
|
@@ -309,7 +309,7 @@ sudo_terminated(struct command_status *cstat)
|
||||
debug_return_bool(false);
|
||||
}
|
||||
|
||||
#if SUDO_API_VERSION != SUDO_API_MKVERSION(1, 15)
|
||||
#if SUDO_API_VERSION != SUDO_API_MKVERSION(1, 16)
|
||||
# error "Update sudo_needs_pty() after changing the plugin API"
|
||||
#endif
|
||||
static bool
|
||||
|
89
src/limits.c
89
src/limits.c
@@ -24,6 +24,7 @@
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/resource.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#ifdef __linux__
|
||||
@@ -55,6 +56,11 @@
|
||||
# define RLIM_INFINITY RLIM64_INFINITY
|
||||
#endif /* HAVE_SETRLIMIT64 */
|
||||
|
||||
/* Older BSD systems have RLIMIT_VMEM, not RLIMIT_AS. */
|
||||
#if !defined(RLIMIT_AS) && defined(RLIMIT_VMEM)
|
||||
# define RLIMIT_AS RLIMIT_VMEM
|
||||
#endif
|
||||
|
||||
/*
|
||||
* macOS doesn't allow nofile soft limit to be infinite or
|
||||
* the stack hard limit to be infinite.
|
||||
@@ -64,27 +70,35 @@ static struct rlimit nofile_fallback = { SUDO_OPEN_MAX, RLIM_INFINITY };
|
||||
static struct rlimit stack_fallback = { SUDO_STACK_MIN, 65532 * 1024 };
|
||||
|
||||
static struct saved_limit {
|
||||
const char *name;
|
||||
int resource;
|
||||
bool saved;
|
||||
struct rlimit *fallback;
|
||||
struct rlimit newlimit;
|
||||
struct rlimit oldlimit;
|
||||
const char *name; /* rlimit_foo in lower case */
|
||||
int resource; /* RLIMIT_FOO definition */
|
||||
bool override; /* override limit while sudo executes? */
|
||||
bool saved; /* true if we were able to get the value */
|
||||
struct rlimit *fallback; /* fallback if we fail to set to newlimit */
|
||||
struct rlimit newlimit; /* new limit to use if override is true */
|
||||
struct rlimit oldlimit; /* original limit, valid if saved is true */
|
||||
} saved_limits[] = {
|
||||
#ifdef RLIMIT_AS
|
||||
{ "RLIMIT_AS", RLIMIT_AS, false, NULL, { RLIM_INFINITY, RLIM_INFINITY } },
|
||||
{ "rlimit_as", RLIMIT_AS, true, false, NULL, { RLIM_INFINITY, RLIM_INFINITY } },
|
||||
#endif
|
||||
{ "RLIMIT_CPU", RLIMIT_CPU, false, NULL, { RLIM_INFINITY, RLIM_INFINITY } },
|
||||
{ "RLIMIT_DATA", RLIMIT_DATA, false, NULL, { RLIM_INFINITY, RLIM_INFINITY } },
|
||||
{ "RLIMIT_FSIZE", RLIMIT_FSIZE, false, NULL, { RLIM_INFINITY, RLIM_INFINITY } },
|
||||
{ "RLIMIT_NOFILE", RLIMIT_NOFILE, false, &nofile_fallback, { RLIM_INFINITY, RLIM_INFINITY } },
|
||||
{ "rlimit_core", RLIMIT_CORE, false },
|
||||
{ "rlimit_cpu", RLIMIT_CPU, true, false, NULL, { RLIM_INFINITY, RLIM_INFINITY } },
|
||||
{ "rlimit_data", RLIMIT_DATA, true, false, NULL, { RLIM_INFINITY, RLIM_INFINITY } },
|
||||
{ "rlimit_fsize", RLIMIT_FSIZE, true, false, NULL, { RLIM_INFINITY, RLIM_INFINITY } },
|
||||
#ifdef RLIMIT_LOCKS
|
||||
{ "rlimit_locks", RLIMIT_LOCKS, false },
|
||||
#endif
|
||||
#ifdef RLIMIT_MEMLOCK
|
||||
{ "rlimit_memlock", RLIMIT_MEMLOCK, false },
|
||||
#endif
|
||||
{ "rlimit_nofile", RLIMIT_NOFILE, true, false, &nofile_fallback, { RLIM_INFINITY, RLIM_INFINITY } },
|
||||
#ifdef RLIMIT_NPROC
|
||||
{ "RLIMIT_NPROC", RLIMIT_NPROC, false, NULL, { RLIM_INFINITY, RLIM_INFINITY } },
|
||||
{ "rlimit_nproc", RLIMIT_NPROC, true, false, NULL, { RLIM_INFINITY, RLIM_INFINITY } },
|
||||
#endif
|
||||
#ifdef RLIMIT_RSS
|
||||
{ "RLIMIT_RSS", RLIMIT_RSS, false, NULL, { RLIM_INFINITY, RLIM_INFINITY } },
|
||||
{ "rlimit_rss", RLIMIT_RSS, true, false, NULL, { RLIM_INFINITY, RLIM_INFINITY } },
|
||||
#endif
|
||||
{ "RLIMIT_STACK", RLIMIT_STACK, false, &stack_fallback, { SUDO_STACK_MIN, RLIM_INFINITY } }
|
||||
{ "rlimit_stack", RLIMIT_STACK, true, false, &stack_fallback, { SUDO_STACK_MIN, RLIM_INFINITY } }
|
||||
};
|
||||
|
||||
static struct rlimit corelimit;
|
||||
@@ -228,6 +242,9 @@ unlimit_sudo(void)
|
||||
(long long)lim->oldlimit.rlim_max);
|
||||
|
||||
lim->saved = true;
|
||||
if (!lim->override)
|
||||
continue;
|
||||
|
||||
if (lim->newlimit.rlim_cur != RLIM_INFINITY) {
|
||||
/* Don't reduce the soft resource limit. */
|
||||
if (lim->oldlimit.rlim_cur == RLIM_INFINITY ||
|
||||
@@ -284,7 +301,7 @@ restore_limits(void)
|
||||
/* Restore resource limits to saved values. */
|
||||
for (idx = 0; idx < nitems(saved_limits); idx++) {
|
||||
struct saved_limit *lim = &saved_limits[idx];
|
||||
if (lim->saved) {
|
||||
if (lim->override && lim->saved) {
|
||||
struct rlimit rl = lim->oldlimit;
|
||||
int i, rc;
|
||||
|
||||
@@ -324,3 +341,45 @@ restore_limits(void)
|
||||
|
||||
debug_return;
|
||||
}
|
||||
|
||||
int
|
||||
serialize_limits(char **info, size_t info_max)
|
||||
{
|
||||
char *str;
|
||||
unsigned int idx, nstored = 0;
|
||||
debug_decl(serialize_limits, SUDO_DEBUG_UTIL);
|
||||
|
||||
for (idx = 0; idx < nitems(saved_limits); idx++) {
|
||||
const struct saved_limit *lim = &saved_limits[idx];
|
||||
const struct rlimit *rl = &lim->oldlimit;
|
||||
char curlim[(((sizeof(int) * 8) + 2) / 3) + 2];
|
||||
char maxlim[(((sizeof(int) * 8) + 2) / 3) + 2];
|
||||
|
||||
if (!lim->saved)
|
||||
continue;
|
||||
|
||||
if (nstored == info_max)
|
||||
goto oom;
|
||||
|
||||
if (rl->rlim_cur == RLIM_INFINITY) {
|
||||
strlcpy(curlim, "infinity", sizeof(curlim));
|
||||
} else {
|
||||
snprintf(curlim, sizeof(curlim), "%llu",
|
||||
(unsigned long long)rl->rlim_cur);
|
||||
}
|
||||
if (rl->rlim_max == RLIM_INFINITY) {
|
||||
strlcpy(maxlim, "infinity", sizeof(maxlim));
|
||||
} else {
|
||||
snprintf(maxlim, sizeof(maxlim), "%llu",
|
||||
(unsigned long long)rl->rlim_max);
|
||||
}
|
||||
if (asprintf(&str, "%s=%s,%s", lim->name, curlim, maxlim) == -1)
|
||||
goto oom;
|
||||
info[nstored++] = str;
|
||||
}
|
||||
debug_return_int(nstored);
|
||||
oom:
|
||||
while (nstored--)
|
||||
free(info[nstored]);
|
||||
debug_return_int(-1);
|
||||
}
|
||||
|
11
src/sudo.c
11
src/sudo.c
@@ -30,6 +30,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/socket.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
@@ -490,10 +491,11 @@ static char **
|
||||
get_user_info(struct user_details *ud)
|
||||
{
|
||||
char *cp, **user_info, path[PATH_MAX];
|
||||
size_t user_info_max = 32 + RLIM_NLIMITS;
|
||||
unsigned int i = 0;
|
||||
mode_t mask;
|
||||
struct passwd *pw;
|
||||
int fd;
|
||||
int fd, n;
|
||||
debug_decl(get_user_info, SUDO_DEBUG_UTIL);
|
||||
|
||||
/*
|
||||
@@ -512,7 +514,7 @@ get_user_info(struct user_details *ud)
|
||||
memset(ud, 0, sizeof(*ud));
|
||||
|
||||
/* XXX - bound check number of entries */
|
||||
user_info = reallocarray(NULL, 32, sizeof(char *));
|
||||
user_info = reallocarray(NULL, user_info_max, sizeof(char *));
|
||||
if (user_info == NULL)
|
||||
goto oom;
|
||||
|
||||
@@ -614,6 +616,11 @@ get_user_info(struct user_details *ud)
|
||||
if (asprintf(&user_info[++i], "cols=%d", ud->ts_cols) == -1)
|
||||
goto oom;
|
||||
|
||||
n = serialize_limits(&user_info[i + 1], user_info_max - (i + 1));
|
||||
if (n == -1)
|
||||
goto oom;
|
||||
i += n;
|
||||
|
||||
user_info[++i] = NULL;
|
||||
|
||||
/* Add to list of vectors to be garbage collected at exit. */
|
||||
|
@@ -293,5 +293,6 @@ void restore_limits(void);
|
||||
void restore_nproc(void);
|
||||
void unlimit_nproc(void);
|
||||
void unlimit_sudo(void);
|
||||
int serialize_limits(char **info, size_t info_max);
|
||||
|
||||
#endif /* SUDO_SUDO_H */
|
||||
|
Reference in New Issue
Block a user