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;