| @@ -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 | |
869 | int | | 869 | int |
870 | netbsd_elf_signature(struct lwp *l, struct exec_package *epp, | | 870 | netbsd_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)) { |
942 | bad: | | 954 | bad: |
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)); |