diff --git a/plugins/sudoers/def_data.c b/plugins/sudoers/def_data.c index 17495aa2c..07e17acda 100644 --- a/plugins/sudoers/def_data.c +++ b/plugins/sudoers/def_data.c @@ -597,6 +597,50 @@ struct sudo_defs_types sudo_defs_table[] = { "intercept_allow_setid", T_FLAG, N_("Allow an intercepted command to run set setuid or setgid programs"), NULL, + }, { + "rlimit_as", T_RLIMIT|T_BOOL, + N_("The maximum size to which the process's address space may grow (in bytes): %s"), + NULL, + }, { + "rlimit_core", T_RLIMIT|T_BOOL, + N_("The largest size core dump file that may be created (in bytes): %s"), + NULL, + }, { + "rlimit_cpu", T_RLIMIT|T_BOOL, + N_("The maximum amount of CPU time that the process may use (in seconds): %s"), + NULL, + }, { + "rlimit_data", T_RLIMIT|T_BOOL, + N_("The maximum size of the data segment for the process (in bytes): %s"), + NULL, + }, { + "rlimit_fsize", T_RLIMIT|T_BOOL, + N_("The largest size file that the process may create (in bytes): %s"), + NULL, + }, { + "rlimit_locks", T_RLIMIT|T_BOOL, + N_("The maximum number of locks that the process may establish: %s"), + NULL, + }, { + "rlimit_memlock", T_RLIMIT|T_BOOL, + N_("The maximum size that the process may lock in memory (in bytes): %s"), + NULL, + }, { + "rlimit_nofile", T_RLIMIT|T_BOOL, + N_("The maximum number of files that the process may have open: %s"), + NULL, + }, { + "rlimit_nproc", T_RLIMIT|T_BOOL, + N_("The maximum number of processes that the user may run simultaneously: %s"), + NULL, + }, { + "rlimit_rss", T_RLIMIT|T_BOOL, + N_("The maximum size to which the process's resident set size may grow (in bytes): %s"), + NULL, + }, { + "rlimit_stack", T_RLIMIT|T_BOOL, + N_("The maximum size to which the process's stack may grow (in bytes): %s"), + NULL, }, { NULL, 0, NULL } diff --git a/plugins/sudoers/def_data.h b/plugins/sudoers/def_data.h index e7983ceb6..49d17feec 100644 --- a/plugins/sudoers/def_data.h +++ b/plugins/sudoers/def_data.h @@ -276,6 +276,28 @@ #define def_intercept_authenticate (sudo_defs_table[I_INTERCEPT_AUTHENTICATE].sd_un.flag) #define I_INTERCEPT_ALLOW_SETID 137 #define def_intercept_allow_setid (sudo_defs_table[I_INTERCEPT_ALLOW_SETID].sd_un.flag) +#define I_RLIMIT_AS 138 +#define def_rlimit_as (sudo_defs_table[I_RLIMIT_AS].sd_un.str) +#define I_RLIMIT_CORE 139 +#define def_rlimit_core (sudo_defs_table[I_RLIMIT_CORE].sd_un.str) +#define I_RLIMIT_CPU 140 +#define def_rlimit_cpu (sudo_defs_table[I_RLIMIT_CPU].sd_un.str) +#define I_RLIMIT_DATA 141 +#define def_rlimit_data (sudo_defs_table[I_RLIMIT_DATA].sd_un.str) +#define I_RLIMIT_FSIZE 142 +#define def_rlimit_fsize (sudo_defs_table[I_RLIMIT_FSIZE].sd_un.str) +#define I_RLIMIT_LOCKS 143 +#define def_rlimit_locks (sudo_defs_table[I_RLIMIT_LOCKS].sd_un.str) +#define I_RLIMIT_MEMLOCK 144 +#define def_rlimit_memlock (sudo_defs_table[I_RLIMIT_MEMLOCK].sd_un.str) +#define I_RLIMIT_NOFILE 145 +#define def_rlimit_nofile (sudo_defs_table[I_RLIMIT_NOFILE].sd_un.str) +#define I_RLIMIT_NPROC 146 +#define def_rlimit_nproc (sudo_defs_table[I_RLIMIT_NPROC].sd_un.str) +#define I_RLIMIT_RSS 147 +#define def_rlimit_rss (sudo_defs_table[I_RLIMIT_RSS].sd_un.str) +#define I_RLIMIT_STACK 148 +#define def_rlimit_stack (sudo_defs_table[I_RLIMIT_STACK].sd_un.str) enum def_tuple { never, diff --git a/plugins/sudoers/def_data.in b/plugins/sudoers/def_data.in index 18272e995..ac66ba4ee 100644 --- a/plugins/sudoers/def_data.in +++ b/plugins/sudoers/def_data.in @@ -430,3 +430,36 @@ intercept_authenticate intercept_allow_setid T_FLAG "Allow an intercepted command to run set setuid or setgid programs" +rlimit_as + T_RLIMIT|T_BOOL + "The maximum size to which the process's address space may grow (in bytes): %s" +rlimit_core + T_RLIMIT|T_BOOL + "The largest size core dump file that may be created (in bytes): %s" +rlimit_cpu + T_RLIMIT|T_BOOL + "The maximum amount of CPU time that the process may use (in seconds): %s" +rlimit_data + T_RLIMIT|T_BOOL + "The maximum size of the data segment for the process (in bytes): %s" +rlimit_fsize + T_RLIMIT|T_BOOL + "The largest size file that the process may create (in bytes): %s" +rlimit_locks + T_RLIMIT|T_BOOL + "The maximum number of locks that the process may establish: %s" +rlimit_memlock + T_RLIMIT|T_BOOL + "The maximum size that the process may lock in memory (in bytes): %s" +rlimit_nofile + T_RLIMIT|T_BOOL + "The maximum number of files that the process may have open: %s" +rlimit_nproc + T_RLIMIT|T_BOOL + "The maximum number of processes that the user may run simultaneously: %s" +rlimit_rss + T_RLIMIT|T_BOOL + "The maximum size to which the process's resident set size may grow (in bytes): %s" +rlimit_stack + T_RLIMIT|T_BOOL + "The maximum size to which the process's stack may grow (in bytes): %s" diff --git a/plugins/sudoers/defaults.c b/plugins/sudoers/defaults.c index d4835b3b0..d9eda17f4 100644 --- a/plugins/sudoers/defaults.c +++ b/plugins/sudoers/defaults.c @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include #include "sudoers.h" @@ -67,6 +69,7 @@ static bool store_timeout(const char *str, union sudo_defs_val *sd_un); static bool store_tuple(const char *str, union sudo_defs_val *sd_un, struct def_values *tuple_vals); static bool store_uint(const char *str, union sudo_defs_val *sd_un); static bool store_timespec(const char *str, union sudo_defs_val *sd_un); +static bool store_rlimit(const char *str, union sudo_defs_val *sd_un); static bool list_op(const char *str, size_t, union sudo_defs_val *sd_un, enum list_ops op); static bool valid_path(struct sudo_defs_types *def, const char *val, const char *file, int line, int column, bool quiet); @@ -96,6 +99,7 @@ dump_defaults(void) sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", desc); break; case T_STR: + case T_RLIMIT: if (cur->sd_un.str) { sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.str); sudo_printf(SUDO_CONV_INFO_MSG, "\n"); @@ -314,6 +318,9 @@ parse_default_entry(struct sudo_defs_types *def, const char *val, int op, case T_TIMESPEC: rc = store_timespec(val, &def->sd_un); break; + case T_RLIMIT: + rc = store_rlimit(val, &def->sd_un); + break; default: if (!quiet) { if (line > 0) { @@ -553,6 +560,8 @@ init_defaults(void) if ((def_admin_flag = strdup(_PATH_SUDO_ADMIN_FLAG)) == NULL) goto oom; #endif + if ((def_rlimit_core = strdup("0,0")) == NULL) + goto oom; def_netgroup_tuple = false; def_sudoedit_checkdir = true; def_iolog_mode = S_IRUSR|S_IWUSR; @@ -856,6 +865,60 @@ store_uint(const char *str, union sudo_defs_val *sd_un) debug_return_bool(true); } +/* Check resource limit syntax, does not save as rlim_t. */ +static bool +check_rlimit(const char *str, bool soft) +{ + const size_t inflen = sizeof("infinity") - 1; + debug_decl(check_rlimit, SUDOERS_DEBUG_DEFAULTS); + + if (isdigit((unsigned char)*str)) { + unsigned long long ullval; + char *ep; + + /* XXX - some systems may lack strtoull() */ + errno = 0; + ullval = strtoull(str, &ep, 10); + if (str == ep || (errno == ERANGE && ullval == ULLONG_MAX)) + debug_return_bool(false); + if (*ep == '\0' || (soft && *ep == ',')) + debug_return_bool(true); + debug_return_bool(false); + } + if (strncmp(str, "infinity", inflen) == 0) { + if (str[inflen] == '\0' || (soft && str[inflen] == ',')) + debug_return_bool(true); + } + debug_return_bool(false); +} + +static bool +store_rlimit(const char *str, union sudo_defs_val *sd_un) +{ + debug_decl(store_rlimit, SUDOERS_DEBUG_DEFAULTS); + + /* The special values "user" and "default" are not compound. */ + if (str != NULL && strcmp(str, "user") != 0 && strcmp(str, "default") != 0) { + const char *hard, *soft = str; + /* + * Expect a limit in the form "soft,hard" or "limit" (both soft+hard). + */ + hard = strchr(str, ','); + if (hard != NULL) + hard++; + else + hard = soft; + + if (!check_rlimit(soft, true)) + debug_return_bool(false); + if (!check_rlimit(hard, false)) + debug_return_bool(false); + } + + /* Store as string, front-end will parse it as a limit. */ + debug_return_bool(store_str(str, sd_un)); +} + static bool store_timespec(const char *str, union sudo_defs_val *sd_un) { diff --git a/plugins/sudoers/defaults.h b/plugins/sudoers/defaults.h index b90481bd9..0e40f583a 100644 --- a/plugins/sudoers/defaults.h +++ b/plugins/sudoers/defaults.h @@ -105,6 +105,8 @@ struct early_default { #define T_TIMESPEC 0x010 #undef T_TIMEOUT #define T_TIMEOUT 0x011 +#undef T_RLIMIT +#define T_RLIMIT 0x012 #undef T_MASK #define T_MASK 0x0FF #undef T_BOOL diff --git a/plugins/sudoers/mkdefaults b/plugins/sudoers/mkdefaults index f0f0a1325..c1b93969d 100755 --- a/plugins/sudoers/mkdefaults +++ b/plugins/sudoers/mkdefaults @@ -46,6 +46,7 @@ BEGIN { type_map["T_TUPLE"] = "tuple" type_map["T_TIMESPEC"] = "tspec" type_map["T_TIMEOUT"] = "ival" + type_map["T_RLIMIT"] = "str" } { sub(/#.*/, "", $0) diff --git a/plugins/sudoers/policy.c b/plugins/sudoers/policy.c index c3f2ae47d..e17a0da58 100644 --- a/plugins/sudoers/policy.c +++ b/plugins/sudoers/policy.c @@ -632,7 +632,7 @@ sudoers_policy_store_result(bool accepted, char *argv[], char *envp[], } /* Increase the length of command_info as needed, it is *not* checked. */ - command_info = calloc(58, sizeof(char *)); + command_info = calloc(69, sizeof(char *)); if (command_info == NULL) goto oom; @@ -890,6 +890,50 @@ sudoers_policy_store_result(bool accepted, char *argv[], char *envp[], goto oom; } } + if (def_rlimit_as != NULL) { + if ((command_info[info_len++] = sudo_new_key_val("rlimit_as", def_rlimit_as)) == NULL) + goto oom; + } + if (def_rlimit_core != NULL) { + if ((command_info[info_len++] = sudo_new_key_val("rlimit_core", def_rlimit_core)) == NULL) + goto oom; + } + if (def_rlimit_cpu != NULL) { + if ((command_info[info_len++] = sudo_new_key_val("rlimit_cpu", def_rlimit_cpu)) == NULL) + goto oom; + } + if (def_rlimit_data != NULL) { + if ((command_info[info_len++] = sudo_new_key_val("rlimit_data", def_rlimit_data)) == NULL) + goto oom; + } + if (def_rlimit_fsize != NULL) { + if ((command_info[info_len++] = sudo_new_key_val("rlimit_fsize", def_rlimit_fsize)) == NULL) + goto oom; + } + if (def_rlimit_locks != NULL) { + if ((command_info[info_len++] = sudo_new_key_val("rlimit_locks", def_rlimit_locks)) == NULL) + goto oom; + } + if (def_rlimit_memlock != NULL) { + if ((command_info[info_len++] = sudo_new_key_val("rlimit_memlock", def_rlimit_memlock)) == NULL) + goto oom; + } + if (def_rlimit_nofile != NULL) { + if ((command_info[info_len++] = sudo_new_key_val("rlimit_nofile", def_rlimit_nofile)) == NULL) + goto oom; + } + if (def_rlimit_nproc != NULL) { + if ((command_info[info_len++] = sudo_new_key_val("rlimit_nproc", def_rlimit_nproc)) == NULL) + goto oom; + } + if (def_rlimit_rss != NULL) { + if ((command_info[info_len++] = sudo_new_key_val("rlimit_rss", def_rlimit_rss)) == NULL) + goto oom; + } + if (def_rlimit_stack != NULL) { + if ((command_info[info_len++] = sudo_new_key_val("rlimit_stack", def_rlimit_stack)) == NULL) + goto oom; + } #ifdef HAVE_LOGIN_CAP_H if (def_use_loginclass) { if ((command_info[info_len++] = sudo_new_key_val("login_class", login_class)) == NULL)