CVE-2019-25016 (published 2021-01-28T20:15Z)

In OpenDoas from 6.6 to 6.8 the users PATH variable was incorrectly inherited by authenticated executions if the authenticating rule allowed the user to execute any command. Rules that only allowed to authenticated user to execute specific commands were not affected by this issue.

Severity: MEDIUM
CVSS v2 base score: 6.5 (AV:N/AC:L/Au:S/C:P/I:P/A:P)
CVSS v3 base score: 8.8, HIGH (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-459
cwe_name: Incomplete Cleanup
description: The product does not properly "clean up" and remove temporary or supporting resources after they have been used.
extended_description: 
            
            
         
         
cwe_id: CWE-909
cwe_name: Missing Initialization of Resource
description: The product does not initialize a critical resource.
extended_description: Many resources require initialization before they can be properly used. If a resource is not initialized, it could contain unpredictable or expired data, or it could be initialized to defaults that are invalid. This can have security implications when the resource is expected to have certain properties or values.
         

Fix information:
repo_url: https://github.com/Duncaen/OpenDoas
commit_details: repo_url: https://github.com/Duncaen/OpenDoas
author: tedu
author_date: 2019-06-16 18:16:34+00:00
msg: redo the environment inheritance to not inherit. it was intended to make life easier, but it can be surprising or even unsafe. instead, reset just about everything to the target user's values. ok deraadt martijn Thanks to Sander Bos in particular for pointing out some nasty edge cases.
repository: repo_url: https://github.com/Duncaen/OpenDoas
repo_name: Duncaen/OpenDoas
description: A portable fork of the OpenBSD `doas` command
repo_language: C
owner: Duncaen
file_changes: filename: doas.c
change_type: ModificationType.MODIFY
diff: @@ -449,6 +449,7 @@ main(int argc, char **argv)
 
 #ifdef HAVE_SETUSERCONTEXT
 	if (setusercontext(NULL, targpw, target, LOGIN_SETGROUP |
+	    LOGIN_SETPATH |
 	    LOGIN_SETPRIORITY | LOGIN_SETRESOURCES | LOGIN_SETUMASK |
 	    LOGIN_SETUSER) != 0)
 		errx(1, "failed to set user context for target");
@@ -479,9 +480,10 @@ main(int argc, char **argv)
 	syslog(LOG_AUTHPRIV | LOG_INFO, "%s ran command %s as %s from %s",
 	    mypw->pw_name, cmdline, targpw->pw_name, cwd);
 
-	envp = prepenv(rule);
+	envp = prepenv(rule, mypw, targpw);
 
 	if (rule->cmd) {
+		/* do this again after setusercontext reset it */
 		if (setenv("PATH", safepath, 1) == -1)
 			err(1, "failed to set PATH '%s'", safepath);
 	}

programming_language: C
filename: doas.conf.5
change_type: ModificationType.MODIFY
diff: @@ -51,15 +51,9 @@ again for some time.
 .It Ic keepenv
 The user's environment is maintained.
 The default is to reset the environment, except for the variables
-.Ev DISPLAY ,
-.Ev HOME ,
-.Ev LOGNAME ,
-.Ev MAIL ,
-.Ev PATH ,
-.Ev TERM ,
-.Ev USER
+.Ev DISPLAY
 and
-.Ev USERNAME .
+.Ev TERM .
 .It Ic setenv { Oo Ar variable ... Oc Oo Ar variable=value ... Oc Ic }
 In addition to the variables mentioned above, keep the space-separated
 specified variables.

programming_language: PowerShell
filename: doas.h
change_type: ModificationType.MODIFY
diff: @@ -29,7 +29,10 @@ extern struct rule **rules;
 extern int nrules;
 extern int parse_errors;
 
-char **prepenv(const struct rule *);
+struct passwd;
+
+char **prepenv(const struct rule *, const struct passwd *,
+    const struct passwd *);
 
 #define PERMIT	1
 #define DENY	2

programming_language: C++
filename: env.c
change_type: ModificationType.MODIFY
diff: @@ -24,6 +24,7 @@
 #include <err.h>
 #include <unistd.h>
 #include <errno.h>
+#include <pwd.h>
 
 #include "doas.h"
 #include "includes.h"
@@ -39,6 +40,8 @@ struct env {
 	u_int count;
 };
 
+static void fillenv(struct env *env, const char **envlist);
+
 static int
 envcmp(struct envnode *a, struct envnode *b)
 {
@@ -69,8 +72,19 @@ freenode(struct envnode *node)
 	free(node);
 }
 
+static void
+addnode(struct env *env, const char *key, const char *value)
+{
+	struct envnode *node;
+
+	node = createnode(key, value);
+	RB_INSERT(envtree, &env->root, node);
+	env->count++;
+}
+
 static struct env *
-createenv(const struct rule *rule)
+createenv(const struct rule *rule, const struct passwd *mypw,
+    const struct passwd *targpw)
 {
 	struct env *env;
 	u_int i;
@@ -81,6 +95,8 @@ createenv(const struct rule *rule)
 	RB_INIT(&env->root);
 	env->count = 0;
 
+	addnode(env, "DOAS_USER", mypw->pw_name);
+
 	if (rule->options & KEEPENV) {
 		extern char **environ;
 
@@ -109,6 +125,19 @@ createenv(const struct rule *rule)
 				env->count++;
 			}
 		}
+	} else {
+		static const char *copyset[] = {
+			"DISPLAY", "TERM",
+			NULL
+		};
+
+		addnode(env, "HOME", targpw->pw_dir);
+		addnode(env, "LOGNAME", targpw->pw_name);
+		addnode(env, "PATH", getenv("PATH"));
+		addnode(env, "SHELL", targpw->pw_shell);
+		addnode(env, "USER", targpw->pw_name);
+
+		fillenv(env, copyset);
 	}
 
 	return env;
@@ -187,20 +216,12 @@ fillenv(struct env *env, const char **envlist)
 }
 
 char **
-prepenv(const struct rule *rule)
+prepenv(const struct rule *rule, const struct passwd *mypw,
+    const struct passwd *targpw)
 {
-	static const char *safeset[] = {
-		"DISPLAY", "HOME", "LOGNAME", "MAIL",
-		"PATH", "TERM", "USER", "USERNAME",
-		NULL
-	};
 	struct env *env;
 
-	env = createenv(rule);
-
-	/* if we started with blank, fill some defaults then apply rules */
-	if (!(rule->options & KEEPENV))
-		fillenv(env, safeset);
+	env = createenv(rule, mypw, targpw);
 	if (rule->envlist)
 		fillenv(env, rule->envlist);
 

programming_language: C
repo_url: https://github.com/Duncaen/OpenDoas
commit_details: repo_url: https://github.com/Duncaen/OpenDoas
author: Duncan Overbruck
author_date: 2021-01-28 17:58:34+01:00
msg: correctly reset path for rules without specific command

This is a fixup for commit 01c658f8c45cb92a343be5f32aa6da70b2032168
where the behaviour was changed to not inherit the PATH variable
by default.
repository: repo_url: https://github.com/Duncaen/OpenDoas
repo_name: Duncaen/OpenDoas
description: A portable fork of the OpenBSD `doas` command
repo_language: C
owner: Duncaen
file_changes: filename: doas.c
change_type: ModificationType.MODIFY
diff: @@ -386,6 +386,7 @@ main(int argc, char **argv)
 
 #ifdef HAVE_LOGIN_CAP_H
 	if (setusercontext(NULL, targpw, target, LOGIN_SETGROUP |
+	    LOGIN_SETPATH |
 	    LOGIN_SETPRIORITY | LOGIN_SETRESOURCES | LOGIN_SETUMASK |
 	    LOGIN_SETUSER) != 0)
 		errx(1, "failed to set user context for target");
@@ -396,6 +397,8 @@ main(int argc, char **argv)
 		err(1, "initgroups");
 	if (setresuid(target, target, target) != 0)
 		err(1, "setresuid");
+	if (setenv("PATH", safepath, 1) == -1)
+		err(1, "failed to set PATH '%s'", safepath);
 #endif
 
 	if (getcwd(cwdpath, sizeof(cwdpath)) == NULL)

programming_language: C