Module Name:    src
Committed By:   maxv
Date:           Fri Feb 21 07:47:02 UTC 2014

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

Log Message:
Properly check the section size to avoid out-of-bound reads. The
computed size must be the exact same size that is indicated in
sh_size.

ok agc@ christos@


To generate a diff of this commit:
cvs rdiff -u -r1.59 -r1.60 src/sys/kern/exec_elf.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/exec_elf.c
diff -u src/sys/kern/exec_elf.c:1.59 src/sys/kern/exec_elf.c:1.60
--- src/sys/kern/exec_elf.c:1.59	Wed Feb 19 15:23:20 2014
+++ src/sys/kern/exec_elf.c	Fri Feb 21 07:47:02 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: exec_elf.c,v 1.59 2014/02/19 15:23:20 maxv Exp $	*/
+/*	$NetBSD: exec_elf.c,v 1.60 2014/02/21 07:47:02 maxv Exp $	*/
 
 /*-
  * Copyright (c) 1994, 2000, 2005 The NetBSD Foundation, Inc.
@@ -57,7 +57,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: exec_elf.c,v 1.59 2014/02/19 15:23:20 maxv Exp $");
+__KERNEL_RCSID(1, "$NetBSD: exec_elf.c,v 1.60 2014/02/21 07:47:02 maxv Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_pax.h"
@@ -873,7 +873,7 @@ netbsd_elf_signature(struct lwp *l, stru
 	size_t i;
 	Elf_Shdr *sh;
 	Elf_Nhdr *np;
-	size_t shsize;
+	size_t shsize, nsize;
 	int error;
 	int isnetbsd = 0;
 	char *ndata;
@@ -902,11 +902,23 @@ netbsd_elf_signature(struct lwp *l, stru
 		if (error)
 			continue;
 
+		/* Point to the note, skip the header */
 		ndata = (char *)(np + 1);
-		unsigned int maxlen = (unsigned int)(shp->sh_size -
-		    ((char *)ndata - (char *)np));
-		if (maxlen < np->n_namesz)
+
+		/*
+		 * Padding is present if necessary to ensure 4-byte alignment.
+		 * The actual section size is therefore:
+		 *    header size + 4-byte aligned name + 4-byte aligned desc
+		 * Ensure this size is consistent with what is indicated
+		 * in sh_size. The first check avoids integer overflows.
+		 */
+		if (np->n_namesz > shp->sh_size || np->n_descsz > shp->sh_size)
 			goto bad;
+		nsize = sizeof(*np) + roundup(np->n_namesz, 4) +
+		    roundup(np->n_descsz, 4);
+		if (nsize != shp->sh_size)
+			goto bad;
+
 		switch (np->n_type) {
 		case ELF_NOTE_TYPE_NETBSD_TAG:
 			/*
@@ -917,7 +929,7 @@ netbsd_elf_signature(struct lwp *l, stru
 			    memcmp(ndata, ELF_NOTE_NETBSD_NAME,
 			    ELF_NOTE_NETBSD_NAMESZ) == 0) {
 				memcpy(&epp->ep_osversion,
-				    ndata + ELF_NOTE_NETBSD_NAMESZ + 1,
+				    ndata + roundup(ELF_NOTE_NETBSD_NAMESZ, 4),
 				    ELF_NOTE_NETBSD_DESCSZ);
 				isnetbsd = 1;
 				break;
@@ -949,7 +961,8 @@ bad:
 				    memcmp(ndata, ELF_NOTE_GNU_NAME,
 				    ELF_NOTE_GNU_NAMESZ) == 0)
 				    break;
-				int ns = MIN(np->n_namesz, maxlen);
+
+				int ns = MIN(np->n_namesz, shp->sh_size - sizeof(*np));
 				printf("%s: Unknown elf note type %d: "
 				    "[namesz=%d, descsz=%d name=%*.*s]\n",
 				    epp->ep_kname, np->n_type, np->n_namesz,
@@ -959,7 +972,7 @@ bad:
 				continue;
 			}
 			(void)memcpy(&epp->ep_pax_flags,
-			    ndata + ELF_NOTE_PAX_NAMESZ,
+			    ndata + roundup(ELF_NOTE_PAX_NAMESZ, 4),
 			    sizeof(epp->ep_pax_flags));
 			break;
 

Reply via email to