PATH, HOME, MAIL, SHELL, LOGNAME, USER, USERNAME and SUDO_* variables in
addition to variables from the invoking process permitted by the
_\be_\bn_\bv_\b__\bc_\bh_\be_\bc_\bk and _\be_\bn_\bv_\b__\bk_\be_\be_\bp options. This is effectively a whitelist for
- environment variables.
+ environment variables. Environment variables with a value beginning with
+ () are removed unless both the name and value parts are matched by
+ _\be_\bn_\bv_\b__\bk_\be_\be_\bp or _\be_\bn_\bv_\b__\bc_\bh_\be_\bc_\bk, as they could be interpreted as b\bba\bas\bsh\bh functions.
+ Prior to version 1.8.11, such variables were always removed.
If, however, the _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt option is disabled, any variables not
explicitly denied by the _\be_\bn_\bv_\b__\bc_\bh_\be_\bc_\bk and _\be_\bn_\bv_\b__\bd_\be_\bl_\be_\bt_\be options are inherited
from the invoking process. In this case, _\be_\bn_\bv_\b__\bc_\bh_\be_\bc_\bk and _\be_\bn_\bv_\b__\bd_\be_\bl_\be_\bt_\be behave
- like a blacklist. Since it is not possible to blacklist all potentially
- dangerous environment variables, use of the default _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt behavior is
+ like a blacklist. Environment variables with a value beginning with ()
+ are always removed, even if they do not match one of the blacklists.
+ Since it is not possible to blacklist all potentially dangerous
+ environment variables, use of the default _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt behavior is
encouraged.
- In all cases, environment variables with a value beginning with () are
- removed as they could be interpreted as b\bba\bas\bsh\bh functions. The list of
- environment variables that s\bsu\bud\bdo\bo allows or denies is contained in the
- output of ``sudo -V'' when run as root.
+ By default, environment variables are matched by name. However, if the
+ pattern includes an equal sign (`='), both the variables name and value
+ must match. For example, a b\bba\bas\bsh\bh function could be matched as follows:
+
+ env_keep += "my_func=()*"
+
+ Without the ``=()*'' suffix, this would not match, as b\bba\bas\bsh\bh functions are
+ not preserved by default.
+
+ The list of environment variables that s\bsu\bud\bdo\bo allows or denies is contained
+ in the output of ``sudo -V'' when run as root.
Note that the dynamic linker on most operating systems will remove
variables that can control dynamic linking from the environment of setuid
file distributed with s\bsu\bud\bdo\bo or http://www.sudo.ws/sudo/license.html for
complete details.
-Sudo 1.8.11 July 16, 2014 Sudo 1.8.11
+Sudo 1.8.11b1 July 16, 2014 Sudo 1.8.11b1
}
/*
- * Check the env_delete blacklist.
+ * Check for var against patterns in the specified environment list.
* Returns true if the variable was found, else false.
*/
static bool
-matches_env_delete(const char *var)
+matches_env_list(const char *var, struct list_members *list, bool *full_match)
{
struct list_member *cur;
- size_t len;
- bool iswild;
bool match = false;
- debug_decl(matches_env_delete, SUDO_DEBUG_ENV)
+ debug_decl(matches_env_list, SUDO_DEBUG_ENV)
- /* Skip anything listed in env_delete. */
- SLIST_FOREACH(cur, &def_env_delete, entries) {
- len = strlen(cur->value);
- /* Deal with '*' wildcard */
+ SLIST_FOREACH(cur, list, entries) {
+ size_t sep_pos, len = strlen(cur->value);
+ bool iswild = false;
+
+ /* Locate position of the '=' separator in var=value. */
+ sep_pos = strcspn(var, "=");
+
+ /* Deal with '*' wildcard at the end of the pattern. */
if (cur->value[len - 1] == '*') {
len--;
iswild = true;
- } else
- iswild = false;
+ }
if (strncmp(cur->value, var, len) == 0 &&
- (iswild || var[len] == '=')) {
+ (iswild || len == sep_pos || var[len] == '\0')) {
+ /* If we matched past the '=', count as a full match. */
+ *full_match = len > sep_pos + 1;
match = true;
break;
}
debug_return_bool(match);
}
+/*
+ * Check the env_delete blacklist.
+ * Returns true if the variable was found, else false.
+ */
+static bool
+matches_env_delete(const char *var)
+{
+ bool full_match; /* unused */
+ debug_decl(matches_env_delete, SUDO_DEBUG_ENV)
+
+ /* Skip anything listed in env_delete. */
+ debug_return_bool(matches_env_list(var, &def_env_delete, &full_match));
+}
+
/*
* Apply the env_check list.
* Returns true if the variable is allowed, false if denied
* or -1 if no match.
*/
static int
-matches_env_check(const char *var)
+matches_env_check(const char *var, bool *full_match)
{
- struct list_member *cur;
- size_t len;
- bool iswild;
int keepit = -1;
debug_decl(matches_env_check, SUDO_DEBUG_ENV)
- SLIST_FOREACH(cur, &def_env_check, entries) {
- len = strlen(cur->value);
- /* Deal with '*' wildcard */
- if (cur->value[len - 1] == '*') {
- len--;
- iswild = true;
- } else
- iswild = false;
- if (strncmp(cur->value, var, len) == 0 &&
- (iswild || var[len] == '=')) {
- keepit = !strpbrk(var, "/%");
- break;
- }
+ /* Skip anything listed in env_check that includes '/' or '%'. */
+ if (matches_env_list(var, &def_env_check, full_match)) {
+ const char *val = strchr(var, '=');
+ if (val != NULL)
+ keepit = !strpbrk(++val, "/%");
}
debug_return_bool(keepit);
}
* Returns true if the variable is allowed else false.
*/
static bool
-matches_env_keep(const char *var)
+matches_env_keep(const char *var, bool *full_match)
{
- struct list_member *cur;
- size_t len;
- bool iswild, keepit = false;
+ bool keepit = false;
debug_decl(matches_env_keep, SUDO_DEBUG_ENV)
/* Preserve SHELL variable for "sudo -s". */
if (ISSET(sudo_mode, MODE_SHELL) && strncmp(var, "SHELL=", 6) == 0) {
keepit = true;
- goto done;
- }
-
- SLIST_FOREACH(cur, &def_env_keep, entries) {
- len = strlen(cur->value);
- /* Deal with '*' wildcard */
- if (cur->value[len - 1] == '*') {
- len--;
- iswild = true;
- } else
- iswild = false;
- if (strncmp(cur->value, var, len) == 0 &&
- (iswild || var[len] == '=')) {
- keepit = true;
- break;
- }
+ } else if (matches_env_list(var, &def_env_keep, full_match)) {
+ keepit = true;
}
-done:
debug_return_bool(keepit);
}
static bool
env_should_delete(const char *var)
{
+ const char *cp;
int delete_it;
+ bool full_match = false;
debug_decl(env_should_delete, SUDO_DEBUG_ENV);
+ /* Skip variables with values beginning with () (bash functions) */
+ if ((cp = strchr(var, '=')) != NULL) {
+ if (strncmp(cp, "=() ", 3) == 0) {
+ delete_it = true;
+ goto done;
+ }
+ }
+
delete_it = matches_env_delete(var);
if (!delete_it)
- delete_it = matches_env_check(var) == false;
+ delete_it = matches_env_check(var, &full_match) == false;
+done:
sudo_debug_printf(SUDO_DEBUG_INFO, "delete %s: %s",
var, delete_it ? "YES" : "NO");
debug_return_bool(delete_it);
env_should_keep(const char *var)
{
int keepit;
+ bool full_match = false;
+ const char *cp;
debug_decl(env_should_keep, SUDO_DEBUG_ENV)
- keepit = matches_env_check(var);
+ keepit = matches_env_check(var, &full_match);
if (keepit == -1)
- keepit = matches_env_keep(var);
+ keepit = matches_env_keep(var, &full_match);
+ /* Skip bash functions unless we matched on the value as well as name. */
+ if (keepit && !full_match) {
+ if ((cp = strchr(var, '=')) != NULL) {
+ if (strncmp(cp, "=() ", 3) == 0)
+ keepit = false;
+ }
+ }
sudo_debug_printf(SUDO_DEBUG_INFO, "keep %s: %s",
var, keepit ? "YES" : "NO");
debug_return_bool(keepit == true);
debug_decl(env_merge, SUDO_DEBUG_ENV)
for (ep = envp; *ep != NULL; ep++) {
+ /* XXX - avoid checking value here too */
if (sudo_putenv(*ep, true, !env_should_keep(*ep)) == -1) {
/* XXX cannot undo on failure */
rval = false;
for (ep = old_envp; *ep; ep++) {
bool keepit;
- /* Skip variables with values beginning with () (bash functions) */
- if ((cp = strchr(*ep, '=')) != NULL) {
- if (strncmp(cp, "=() ", 3) == 0)
- continue;
- }
-
/*
* Look up the variable in the env_check and env_keep lists.
*/
* env_check.
*/
for (ep = old_envp; *ep; ep++) {
- /* Skip variables with values beginning with () (bash functions) */
- if ((cp = strchr(*ep, '=')) != NULL) {
- if (strncmp(cp, "=() ", 3) == 0)
- continue;
- }
-
/* Add variable unless it matches a black list. */
if (!env_should_delete(*ep)) {
if (strncmp(*ep, "SUDO_PS1=", 9) == 0)