CVE-2019-15900 (published 2019-10-18T16:15Z)

An issue was discovered in slicer69 doas before 6.2 on certain platforms other than OpenBSD. On platforms without strtonum(3), sscanf was used without checking for error cases. Instead, the uninitialized variable errstr was checked and in some cases returned success even if sscanf failed. The result was that, instead of reporting that the supplied username or group name did not exist, it would execute the command as root.

Severity: HIGH
CVSS v2 base score: 10.0 (AV:N/AC:L/Au:N/C:C/I:C/A:C)
CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-754
cwe_name: Improper Check for Unusual or Exceptional Conditions
description: The product does not check or incorrectly checks for unusual or exceptional conditions that are not expected to occur frequently during day to day operation of the product.
extended_description: 
            The programmer may assume that certain events or conditions will never occur or do not need to be worried about, such as low memory conditions, lack of access to resources due to restrictive permissions, or misbehaving clients or components. However, attackers may intentionally trigger these unusual conditions, thus violating the programmer's assumptions, possibly introducing instability, incorrect behavior, or a vulnerability.
            Note that this entry is not exclusively about the use of exceptions and exception handling, which are mechanisms for both checking and handling unusual or unexpected conditions.
         
         
cwe_id: CWE-252
cwe_name: Unchecked Return Value
description: The product does not check the return value from a method or function, which can prevent it from detecting unexpected states and conditions.
extended_description: Two common programmer assumptions are "this function call can never fail" and "it doesn't matter if this function call fails". If an attacker can force the function to fail or otherwise return a value that is not expected, then the subsequent program logic could lead to a vulnerability, because the product is not in a state that the programmer assumes. For example, if the program calls a function to drop privileges but does not check the return code to ensure that privileges were successfully dropped, then the program will continue to operate with the higher privileges.
         
cwe_id: CWE-863
cwe_name: Incorrect Authorization
description: The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check. This allows attackers to bypass intended access restrictions.
extended_description: 
            Assuming a user with a given identity, authorization is the process of determining whether that user can access a given resource, based on the user's privileges and any permissions or other access-control specifications that apply to the resource.
            When access control checks are incorrectly applied, users are able to access data or perform actions that they should not be allowed to perform. This can lead to a wide range of problems, including information exposures, denial of service, and arbitrary code execution.
         
         
cwe_id: CWE-908
cwe_name: Use of Uninitialized Resource
description: The product uses or accesses a resource that has not been initialized.
extended_description: When a resource has not been properly initialized, the product may behave unexpectedly. This may lead to a crash or invalid memory access, but the consequences vary depending on the type of resource and how it is used within the product.
         

Fix information:
repo_url: https://github.com/slicer69/doas
commit_details: repo_url: https://github.com/slicer69/doas
author: Jesse Smith
author_date: 2019-09-03 11:42:27-03:00
msg: Added optimization to Makefile (can be set/overruled using OPT).
Added flag to display all warnings during compiling.
Added status checks when parsing user/group IDs for Linux.
Make sure Linux drops original user's groups when running as another user.
repository: repo_url: https://github.com/slicer69/doas
repo_name: slicer69/doas
description: A port of OpenBSD's doas which runs on FreeBSD, Linux, NetBSD, and illumos
repo_language: C
owner: slicer69
file_changes: filename: Makefile
change_type: ModificationType.MODIFY
diff: @@ -5,9 +5,10 @@ PREFIX?=/usr/local
 MANDIR?=$(DESTDIR)$(PREFIX)/man
 SYSCONFDIR?=$(DESTDIR)$(PREFIX)/etc
 OBJECTS=doas.o env.o execvpe.o reallocarray.o y.tab.o
+OPT?=-O2
 # Can set GLOBAL_PATH here to set PATH for target user.
 # TARGETPATH=-DGLOBAL_PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:\"
-CFLAGS+=-DUSE_PAM -DDOAS_CONF=\"${SYSCONFDIR}/doas.conf\" $(TARGETPATH)
+CFLAGS+=-Wall $(OPT) -DUSE_PAM -DDOAS_CONF=\"${SYSCONFDIR}/doas.conf\" $(TARGETPATH)
 LDFLAGS+=-lpam
 UNAME_S := $(shell uname -s)
 ifeq ($(UNAME_S),Linux)

programming_language: Shell
filename: doas.c
change_type: ModificationType.MODIFY
diff: @@ -85,7 +85,11 @@ static int
 parseuid(const char *s, uid_t *uid)
 {
 	struct passwd *pw;
-	const char *errstr;
+	#if !defined(__linux__) && !defined(__NetBSD__)
+	const char *errstr = NULL;
+        #else
+        int status;
+        #endif
 
 	if ((pw = getpwnam(s)) != NULL) {
 		*uid = pw->pw_uid;
@@ -93,11 +97,13 @@ parseuid(const char *s, uid_t *uid)
 	}
 	#if !defined(__linux__) && !defined(__NetBSD__)
 	*uid = strtonum(s, 0, UID_MAX, &errstr);
-	#else
-	sscanf(s, "%d", uid);
-	#endif
 	if (errstr)
 		return -1;
+	#else
+	status = sscanf(s, "%d", uid);
+        if (status != 1)
+           return -1;
+	#endif
 	return 0;
 }
 
@@ -117,7 +123,11 @@ static int
 parsegid(const char *s, gid_t *gid)
 {
 	struct group *gr;
-	const char *errstr;
+	#if !defined(__linux__) && !defined(__NetBSD__)
+	const char *errstr = NULL;
+        #else
+        int status;
+        #endif
 
 	if ((gr = getgrnam(s)) != NULL) {
 		*gid = gr->gr_gid;
@@ -125,11 +135,13 @@ parsegid(const char *s, gid_t *gid)
 	}
 	#if !defined(__linux__) && !defined(__NetBSD__)
 	*gid = strtonum(s, 0, GID_MAX, &errstr);
-	#else
-	sscanf(s, "%d", gid);
-	#endif
 	if (errstr)
 		return -1;
+	#else
+	status = sscanf(s, "%d", gid);
+        if (status != 1)
+            return -1;
+	#endif
 	return 0;
 }
 

programming_language: C