DragonFlyBSD Kernel Audit
DF-0024 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -809,6 +809,18 @@
     } else {
 	kldname = NULL;
 	modname = file;
+	/*
+	 * Reject bare module names too long to safely assemble in
+	 * linker_search_path (prefix + sep + name + ".ko" + NUL must
+	 * fit in MAXPATHLEN).  32 is a conservative overhead covering
+	 * any reasonable linker_path prefix plus separator, ".ko" and
+	 * the NUL terminator.  Without this check linker_search_path()
+	 * overflows its kmalloc(MAXPATHLEN) buffer via strcpy().
+	 */
+	if (strlen(modname) > MAXPATHLEN - 32) {
+	    error = ENAMETOOLONG;
+	    goto out;
+	}
     }
 
     lockmgr(&kld_lock, LK_EXCLUSIVE);
@@ -1458,6 +1470,10 @@
     buf = kmalloc(MAXPATHLEN, M_LINKER, M_WAITOK);
     cp = linker_path;
     name_len = strlen(name);
+    size_t ext_max = 0;
+    for (ext = exts; *ext != NULL; ext++)
+	if (strlen(*ext) > ext_max)
+	    ext_max = strlen(*ext);
     for (;;) {
 	/* find the end of this component */
 	for (ep = cp; (*ep != 0) && (*ep != ';'); ep++)
@@ -1469,6 +1485,13 @@
 	else
 	    sep = 0;
 
+	/* Skip components whose assembly would overflow MAXPATHLEN */
+	if (prefix_len + sep + name_len + ext_max + 1 > MAXPATHLEN) {
+	    if (*ep == 0)
+		break;
+	    cp = ep + 1;
+	    continue;
+	}
 	result = buf;
 	strncpy(result, cp, prefix_len);
 	if (sep)