Fri Feb 21 07:47:02 2014 UTC ()
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@


(maxv)
diff -r1.59 -r1.60 src/sys/kern/exec_elf.c

cvs diff -r1.59 -r1.60 src/sys/kern/exec_elf.c (expand / switch to unified diff)

--- src/sys/kern/exec_elf.c 2014/02/19 15:23:20 1.59
+++ src/sys/kern/exec_elf.c 2014/02/21 07:47:02 1.60
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: exec_elf.c,v 1.59 2014/02/19 15:23:20 maxv Exp $ */ 1/* $NetBSD: exec_elf.c,v 1.60 2014/02/21 07:47:02 maxv Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1994, 2000, 2005 The NetBSD Foundation, Inc. 4 * Copyright (c) 1994, 2000, 2005 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas. 8 * by Christos Zoulas.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -47,27 +47,27 @@ @@ -47,27 +47,27 @@
47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
48 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 48 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
49 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 49 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
50 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 50 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
51 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 51 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
52 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 52 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
53 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 53 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
54 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 54 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
55 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 55 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
56 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 */ 57 */
58 58
59#include <sys/cdefs.h> 59#include <sys/cdefs.h>
60__KERNEL_RCSID(1, "$NetBSD: exec_elf.c,v 1.59 2014/02/19 15:23:20 maxv Exp $"); 60__KERNEL_RCSID(1, "$NetBSD: exec_elf.c,v 1.60 2014/02/21 07:47:02 maxv Exp $");
61 61
62#ifdef _KERNEL_OPT 62#ifdef _KERNEL_OPT
63#include "opt_pax.h" 63#include "opt_pax.h"
64#endif /* _KERNEL_OPT */ 64#endif /* _KERNEL_OPT */
65 65
66#include <sys/param.h> 66#include <sys/param.h>
67#include <sys/proc.h> 67#include <sys/proc.h>
68#include <sys/kmem.h> 68#include <sys/kmem.h>
69#include <sys/namei.h> 69#include <sys/namei.h>
70#include <sys/vnode.h> 70#include <sys/vnode.h>
71#include <sys/exec.h> 71#include <sys/exec.h>
72#include <sys/exec_elf.h> 72#include <sys/exec_elf.h>
73#include <sys/syscall.h> 73#include <sys/syscall.h>
@@ -863,27 +863,27 @@ bad: @@ -863,27 +863,27 @@ bad:
863 exec_free_emul_arg(epp); 863 exec_free_emul_arg(epp);
864 kmem_free(ph, phsize); 864 kmem_free(ph, phsize);
865 kill_vmcmds(&epp->ep_vmcmds); 865 kill_vmcmds(&epp->ep_vmcmds);
866 return error; 866 return error;
867} 867}
868 868
869int 869int
870netbsd_elf_signature(struct lwp *l, struct exec_package *epp, 870netbsd_elf_signature(struct lwp *l, struct exec_package *epp,
871 Elf_Ehdr *eh) 871 Elf_Ehdr *eh)
872{ 872{
873 size_t i; 873 size_t i;
874 Elf_Shdr *sh; 874 Elf_Shdr *sh;
875 Elf_Nhdr *np; 875 Elf_Nhdr *np;
876 size_t shsize; 876 size_t shsize, nsize;
877 int error; 877 int error;
878 int isnetbsd = 0; 878 int isnetbsd = 0;
879 char *ndata; 879 char *ndata;
880 880
881 epp->ep_pax_flags = 0; 881 epp->ep_pax_flags = 0;
882 if (eh->e_shnum > MAXSHNUM || eh->e_shnum == 0) 882 if (eh->e_shnum > MAXSHNUM || eh->e_shnum == 0)
883 return ENOEXEC; 883 return ENOEXEC;
884 884
885 shsize = eh->e_shnum * sizeof(Elf_Shdr); 885 shsize = eh->e_shnum * sizeof(Elf_Shdr);
886 sh = kmem_alloc(shsize, KM_SLEEP); 886 sh = kmem_alloc(shsize, KM_SLEEP);
887 error = exec_read_from(l, epp->ep_vp, eh->e_shoff, sh, shsize); 887 error = exec_read_from(l, epp->ep_vp, eh->e_shoff, sh, shsize);
888 if (error) 888 if (error)
889 goto out; 889 goto out;
@@ -892,42 +892,54 @@ netbsd_elf_signature(struct lwp *l, stru @@ -892,42 +892,54 @@ netbsd_elf_signature(struct lwp *l, stru
892 for (i = 0; i < eh->e_shnum; i++) { 892 for (i = 0; i < eh->e_shnum; i++) {
893 Elf_Shdr *shp = &sh[i]; 893 Elf_Shdr *shp = &sh[i];
894 894
895 if (shp->sh_type != SHT_NOTE || 895 if (shp->sh_type != SHT_NOTE ||
896 shp->sh_size > MAXNOTESIZE || 896 shp->sh_size > MAXNOTESIZE ||
897 shp->sh_size < sizeof(Elf_Nhdr) + ELF_NOTE_NETBSD_NAMESZ) 897 shp->sh_size < sizeof(Elf_Nhdr) + ELF_NOTE_NETBSD_NAMESZ)
898 continue; 898 continue;
899 899
900 error = exec_read_from(l, epp->ep_vp, shp->sh_offset, np, 900 error = exec_read_from(l, epp->ep_vp, shp->sh_offset, np,
901 shp->sh_size); 901 shp->sh_size);
902 if (error) 902 if (error)
903 continue; 903 continue;
904 904
 905 /* Point to the note, skip the header */
905 ndata = (char *)(np + 1); 906 ndata = (char *)(np + 1);
906 unsigned int maxlen = (unsigned int)(shp->sh_size - 907
907 ((char *)ndata - (char *)np)); 908 /*
908 if (maxlen < np->n_namesz) 909 * Padding is present if necessary to ensure 4-byte alignment.
 910 * The actual section size is therefore:
 911 * header size + 4-byte aligned name + 4-byte aligned desc
 912 * Ensure this size is consistent with what is indicated
 913 * in sh_size. The first check avoids integer overflows.
 914 */
 915 if (np->n_namesz > shp->sh_size || np->n_descsz > shp->sh_size)
909 goto bad; 916 goto bad;
 917 nsize = sizeof(*np) + roundup(np->n_namesz, 4) +
 918 roundup(np->n_descsz, 4);
 919 if (nsize != shp->sh_size)
 920 goto bad;
 921
910 switch (np->n_type) { 922 switch (np->n_type) {
911 case ELF_NOTE_TYPE_NETBSD_TAG: 923 case ELF_NOTE_TYPE_NETBSD_TAG:
912 /* 924 /*
913 * It is us 925 * It is us
914 */ 926 */
915 if (np->n_namesz == ELF_NOTE_NETBSD_NAMESZ && 927 if (np->n_namesz == ELF_NOTE_NETBSD_NAMESZ &&
916 np->n_descsz == ELF_NOTE_NETBSD_DESCSZ && 928 np->n_descsz == ELF_NOTE_NETBSD_DESCSZ &&
917 memcmp(ndata, ELF_NOTE_NETBSD_NAME, 929 memcmp(ndata, ELF_NOTE_NETBSD_NAME,
918 ELF_NOTE_NETBSD_NAMESZ) == 0) { 930 ELF_NOTE_NETBSD_NAMESZ) == 0) {
919 memcpy(&epp->ep_osversion, 931 memcpy(&epp->ep_osversion,
920 ndata + ELF_NOTE_NETBSD_NAMESZ + 1, 932 ndata + roundup(ELF_NOTE_NETBSD_NAMESZ, 4),
921 ELF_NOTE_NETBSD_DESCSZ); 933 ELF_NOTE_NETBSD_DESCSZ);
922 isnetbsd = 1; 934 isnetbsd = 1;
923 break; 935 break;
924 } 936 }
925 /* 937 /*
926 * Ignore SuSE tags 938 * Ignore SuSE tags
927 */ 939 */
928 if (np->n_namesz == ELF_NOTE_SUSE_NAMESZ && 940 if (np->n_namesz == ELF_NOTE_SUSE_NAMESZ &&
929 memcmp(ndata, ELF_NOTE_SUSE_NAME, 941 memcmp(ndata, ELF_NOTE_SUSE_NAME,
930 ELF_NOTE_SUSE_NAMESZ) == 0) 942 ELF_NOTE_SUSE_NAMESZ) == 0)
931 break; 943 break;
932 /* 944 /*
933 * Dunno, warn for diagnostic 945 * Dunno, warn for diagnostic
@@ -939,37 +951,38 @@ netbsd_elf_signature(struct lwp *l, stru @@ -939,37 +951,38 @@ netbsd_elf_signature(struct lwp *l, stru
939 np->n_descsz != ELF_NOTE_PAX_DESCSZ || 951 np->n_descsz != ELF_NOTE_PAX_DESCSZ ||
940 memcmp(ndata, ELF_NOTE_PAX_NAME, 952 memcmp(ndata, ELF_NOTE_PAX_NAME,
941 ELF_NOTE_PAX_NAMESZ)) { 953 ELF_NOTE_PAX_NAMESZ)) {
942bad: 954bad:
943#ifdef DIAGNOSTIC 955#ifdef DIAGNOSTIC
944 { 956 {
945 /* 957 /*
946 * Ignore GNU tags 958 * Ignore GNU tags
947 */ 959 */
948 if (np->n_namesz == ELF_NOTE_GNU_NAMESZ && 960 if (np->n_namesz == ELF_NOTE_GNU_NAMESZ &&
949 memcmp(ndata, ELF_NOTE_GNU_NAME, 961 memcmp(ndata, ELF_NOTE_GNU_NAME,
950 ELF_NOTE_GNU_NAMESZ) == 0) 962 ELF_NOTE_GNU_NAMESZ) == 0)
951 break; 963 break;
952 int ns = MIN(np->n_namesz, maxlen); 964
 965 int ns = MIN(np->n_namesz, shp->sh_size - sizeof(*np));
953 printf("%s: Unknown elf note type %d: " 966 printf("%s: Unknown elf note type %d: "
954 "[namesz=%d, descsz=%d name=%*.*s]\n", 967 "[namesz=%d, descsz=%d name=%*.*s]\n",
955 epp->ep_kname, np->n_type, np->n_namesz, 968 epp->ep_kname, np->n_type, np->n_namesz,
956 np->n_descsz, ns, ns, ndata); 969 np->n_descsz, ns, ns, ndata);
957 } 970 }
958#endif 971#endif
959 continue; 972 continue;
960 } 973 }
961 (void)memcpy(&epp->ep_pax_flags, 974 (void)memcpy(&epp->ep_pax_flags,
962 ndata + ELF_NOTE_PAX_NAMESZ, 975 ndata + roundup(ELF_NOTE_PAX_NAMESZ, 4),
963 sizeof(epp->ep_pax_flags)); 976 sizeof(epp->ep_pax_flags));
964 break; 977 break;
965 978
966 case ELF_NOTE_TYPE_MARCH_TAG: 979 case ELF_NOTE_TYPE_MARCH_TAG:
967 /* 980 /*
968 * Copy the machine arch into the package. 981 * Copy the machine arch into the package.
969 */ 982 */
970 if (np->n_namesz == ELF_NOTE_MARCH_NAMESZ 983 if (np->n_namesz == ELF_NOTE_MARCH_NAMESZ
971 && memcmp(ndata, ELF_NOTE_MARCH_NAME, 984 && memcmp(ndata, ELF_NOTE_MARCH_NAME,
972 ELF_NOTE_MARCH_NAMESZ) == 0) { 985 ELF_NOTE_MARCH_NAMESZ) == 0) {
973 strlcpy(epp->ep_machine_arch, 986 strlcpy(epp->ep_machine_arch,
974 ndata + roundup(ELF_NOTE_MARCH_NAMESZ, 4), 987 ndata + roundup(ELF_NOTE_MARCH_NAMESZ, 4),
975 sizeof(epp->ep_machine_arch)); 988 sizeof(epp->ep_machine_arch));