CVE-2021-42341 (published 2021-10-14T05:15Z)

checkpath in OpenRC before 0.44.7 uses the direct output of strlen() to allocate strings, which does not account for the '\\0' byte at the end of the string. This results in memory corruption. CVE-2021-42341 was introduced in git commit 63db2d99e730547339d1bdd28e8437999c380cae, which was introduced as part of OpenRC 0.44.0 development.

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

Weakness information:
cwe_id: NVD-CWE-Other
cwe_name: Other
description: NVD is only using a subset of CWE for mapping instead of the entire CWE, and the weakness type is not covered by that subset.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/OpenRC/openrc
commit_details: repo_url: https://github.com/OpenRC/openrc
author: Sam James
author_date: 2021-10-08 04:52:55+01:00
msg: checkpath: fix allocation size of path buffer

strlen's return value isn't enough to be used
directly for (x)malloc; it doesn't include
the null byte at the end of the string.

X-Gentoo-Bug: 816900
X-Gentoo-Bug-URL: https://bugs.gentoo.org/816900
Fixes: #459
Fixes: #462
repository: repo_url: https://github.com/OpenRC/openrc
repo_name: OpenRC/openrc
description: The OpenRC init system
repo_language: C
owner: OpenRC
file_changes: filename: checkpath.c
change_type: ModificationType.MODIFY
diff: @@ -151,7 +151,7 @@ static char *clean_path(char *path)
 	char *ch;
 	char *ch2;
 	char *str;
-	str = xmalloc(strlen(path));
+	str = xmalloc(strlen(path) + 1);
 	ch = path;
 	ch2 = str;
 	while (true) {

programming_language: C
repo_url: https://github.com/OpenRC/openrc
commit_details: repo_url: https://github.com/OpenRC/openrc
author: William Hubbs
author_date: 2021-04-13 17:13:20-05:00
msg: checkpath: remove extra slashes from paths

This fixes #418.
repository: repo_url: https://github.com/OpenRC/openrc
repo_name: OpenRC/openrc
description: The OpenRC init system
repo_language: C
owner: OpenRC
file_changes: filename: checkpath.c
change_type: ModificationType.MODIFY
diff: @@ -93,13 +93,13 @@ static int get_dirfd(char *path, bool symlinks)
 	if (dirfd == -1)
 		eerrorx("%s: unable to open the root directory: %s",
 				applet, strerror(errno));
-	path_dupe = xstrdup(path);
-	ch = path_dupe;
+	ch = path;
 	while (*ch) {
 		if (*ch == '/')
 			components++;
 		ch++;
 	}
+	path_dupe = xstrdup(path);
 	item = strtok(path_dupe, "/");
 #ifdef O_PATH
 	flags |= O_PATH;
@@ -136,18 +136,44 @@ static int get_dirfd(char *path, bool symlinks)
 			dirfd = new_dirfd;
 			free(linkpath);
 			linkpath = NULL;
-			item = strtok(NULL, "/");
-			components--;
 		}
+		item = strtok(NULL, "/");
+		components--;
 	}
 	free(path_dupe);
-	if (linkpath) {
-		free(linkpath);
-		linkpath = NULL;
-	}
+	free(linkpath);
 	return dirfd;
 }
 
+static char *clean_path(char *path)
+{
+	char *ch;
+	char *ch2;
+	char *str;
+	str = xmalloc(strlen(path));
+	ch = path;
+	ch2 = str;
+	while (true) {
+		*ch2 = *ch;
+		ch++;
+		ch2++;
+		if (!*(ch-1))
+			break;
+		while (*(ch - 1) == '/' && *ch == '/')
+			ch++;
+	}
+	/* get rid of trailing / characters */
+	while ((ch = strrchr(str, '/'))) {
+		if (ch == str)
+			break;
+		if (!*(ch+1))
+			*ch = 0;
+		else
+			break;
+	}
+	return str;
+}
+
 static int do_check(char *path, uid_t uid, gid_t gid, mode_t mode,
 	inode_t type, bool trunc, bool chowner, bool symlinks, bool selinux_on)
 {
@@ -345,6 +371,7 @@ int main(int argc, char **argv)
 	bool symlinks = false;
 	bool writable = false;
 	bool selinux_on = false;
+	char *path = NULL;
 
 	applet = basename_c(argv[0]);
 	while ((opt = getopt_long(argc, argv, getoptstring,
@@ -407,12 +434,14 @@ int main(int argc, char **argv)
 		selinux_on = true;
 
 	while (optind < argc) {
+		path = clean_path(argv[optind]);
 		if (writable)
-			exit(!is_writable(argv[optind]));
-		if (do_check(argv[optind], uid, gid, mode, type, trunc, chowner,
+			exit(!is_writable(path));
+		if (do_check(path, uid, gid, mode, type, trunc, chowner,
 					symlinks, selinux_on))
 			retval = EXIT_FAILURE;
 		optind++;
+		free(path);
 	}
 
 	if (selinux_on)

programming_language: C