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:
Todd C. Miller
2020-08-31 16:37:01 -06:00
parent 84e6e6ccf9
commit c4a579cf8a
9 changed files with 275 additions and 23 deletions

View File

@@ -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);
}