Module Name:    src
Committed By:   maxv
Date:           Wed Jul  9 05:50:51 UTC 2014

Modified Files:
        src/sys/kern: subr_kobj.c

Log Message:
 - limit the number of sections with ELF_MAXSHNUM
 - fix the (symstrindex > hdr->e_shnum) check: it should be >=, otherwise 
there's an
   off-by-one
 - fix the (symstrindex < 0) check: the value is unsigned, so it can't be <0. 
However,
   we should ensure that symstrindex!=0 (done with SHN_UNDEF)
 - set 'error' as appropriate
 - ensure that e_shstrndx < hdr->e_shnum, to prevent out-of-bound reads

Fixes several crashes that could occur when loading a kernel module.

Quick glance from martin@


To generate a diff of this commit:
cvs rdiff -u -r1.48 -r1.49 src/sys/kern/subr_kobj.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/subr_kobj.c
diff -u src/sys/kern/subr_kobj.c:1.48 src/sys/kern/subr_kobj.c:1.49
--- src/sys/kern/subr_kobj.c:1.48	Sun Jul  6 15:35:32 2014
+++ src/sys/kern/subr_kobj.c	Wed Jul  9 05:50:51 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: subr_kobj.c,v 1.48 2014/07/06 15:35:32 maxv Exp $	*/
+/*	$NetBSD: subr_kobj.c,v 1.49 2014/07/09 05:50:51 maxv Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -63,7 +63,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_kobj.c,v 1.48 2014/07/06 15:35:32 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_kobj.c,v 1.49 2014/07/09 05:50:51 maxv Exp $");
 
 #include "opt_modular.h"
 
@@ -225,13 +225,13 @@ kobj_load(kobj_t ko)
 	/*
 	 * Allocate and read in the section header.
 	 */
-	ko->ko_shdrsz = hdr->e_shnum * hdr->e_shentsize;
-	if (ko->ko_shdrsz == 0 || hdr->e_shoff == 0 ||
-	    hdr->e_shentsize != sizeof(Elf_Shdr)) {
+	if (hdr->e_shnum == 0 || hdr->e_shnum > ELF_MAXSHNUM ||
+	    hdr->e_shoff == 0 || hdr->e_shentsize != sizeof(Elf_Shdr)) {
 		kobj_error(ko, "bad sizes");
 		error = ENOEXEC;
 		goto out;
 	}
+	ko->ko_shdrsz = hdr->e_shnum * sizeof(Elf_Shdr);
 	error = ko->ko_read(ko, (void **)&shdr, ko->ko_shdrsz, hdr->e_shoff,
 	    true);
 	if (error != 0) {
@@ -282,7 +282,9 @@ kobj_load(kobj_t ko)
 		goto out;
 	}
 	KASSERT(symtabindex != -1);
-	if (symstrindex < 0 || symstrindex > hdr->e_shnum ||
+	KASSERT(symstrindex != -1);
+
+	if (symstrindex == SHN_UNDEF || symstrindex >= hdr->e_shnum ||
 	    shdr[symstrindex].sh_type != SHT_STRTAB) {
 		kobj_error(ko, "file has invalid symbol strings");
 		error = ENOEXEC;
@@ -326,6 +328,7 @@ kobj_load(kobj_t ko)
 	ko->ko_symcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym);
 	if (ko->ko_symcnt == 0) {
 		kobj_error(ko, "no symbol table");
+		error = ENOEXEC;
 		goto out;
 	}
 	error = ko->ko_read(ko, (void **)&ko->ko_symtab,
@@ -342,6 +345,7 @@ kobj_load(kobj_t ko)
 	ko->ko_strtabsz = shdr[symstrindex].sh_size;
 	if (ko->ko_strtabsz == 0) {
 		kobj_error(ko, "no symbol strings");
+		error = ENOEXEC;
 		goto out;
 	}
 	error = ko->ko_read(ko, (void *)&ko->ko_strtab, ko->ko_strtabsz,
@@ -365,16 +369,23 @@ kobj_load(kobj_t ko)
 	/*
 	 * Do we have a string table for the section names?
 	 */
-	if (hdr->e_shstrndx != 0 && shdr[hdr->e_shstrndx].sh_size != 0 &&
-	    shdr[hdr->e_shstrndx].sh_type == SHT_STRTAB) {
-		ko->ko_shstrtabsz = shdr[hdr->e_shstrndx].sh_size;
-		error = ko->ko_read(ko, (void **)&ko->ko_shstrtab,
-		    shdr[hdr->e_shstrndx].sh_size,
-		    shdr[hdr->e_shstrndx].sh_offset, true);
-		if (error != 0) {
-			kobj_error(ko, "read failed %d", error);
+	if (hdr->e_shstrndx != SHN_UNDEF) {
+		if (hdr->e_shstrndx >= hdr->e_shnum) {
+			kobj_error(ko, "bad shstrndx");
+			error = ENOEXEC;
 			goto out;
 		}
+		if (shdr[hdr->e_shstrndx].sh_size != 0 &&
+		    shdr[hdr->e_shstrndx].sh_type == SHT_STRTAB) {
+			ko->ko_shstrtabsz = shdr[hdr->e_shstrndx].sh_size;
+			error = ko->ko_read(ko, (void **)&ko->ko_shstrtab,
+			    shdr[hdr->e_shstrndx].sh_size,
+			    shdr[hdr->e_shstrndx].sh_offset, true);
+			if (error != 0) {
+				kobj_error(ko, "read failed %d", error);
+				goto out;
+			}
+		}
 	}
 
 	/*

Reply via email to