Tighten up the ELF signature checks, and actually look for the ABI tag added

in newer glibc versions.
This commit is contained in:
mycroft 2000-12-15 06:14:21 +00:00
parent 8ec0002acd
commit b29180b2ff
3 changed files with 119 additions and 146 deletions

View File

@ -1,7 +1,7 @@
/* $NetBSD: linux_exec_elf32.c,v 1.49 2000/12/01 12:28:33 jdolecek Exp $ */
/* $NetBSD: linux_exec_elf32.c,v 1.50 2000/12/15 06:14:21 mycroft Exp $ */
/*-
* Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
* Copyright (c) 1995, 1998, 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -71,7 +71,7 @@
#include <compat/linux/linux_syscall.h>
static int ELFNAME2(linux,signature) __P((struct proc *, struct exec_package *,
Elf_Ehdr *));
Elf_Ehdr *, char *));
#ifdef LINUX_GCC_SIGNATURE
static int ELFNAME2(linux,gcc_signature) __P((struct proc *p,
struct exec_package *, Elf_Ehdr *));
@ -95,18 +95,18 @@ ELFNAME2(linux,gcc_signature)(p, epp, eh)
struct exec_package *epp;
Elf_Ehdr *eh;
{
size_t shsize = sizeof(Elf_Shdr) * eh->e_shnum;
size_t shsize;
size_t i;
static const char signature[] = "\0GCC: (GNU) ";
char buf[sizeof(signature) - 1];
Elf_Shdr *sh;
int error;
error = ENOEXEC;
shsize = eh->e_shnum * sizeof(Elf_Shdr);
sh = (Elf_Shdr *) malloc(shsize, M_TEMP, M_WAITOK);
if ((error = ELFNAME(read_from)(p, epp->ep_vp, eh->e_shoff,
(caddr_t) sh, shsize)) != 0)
error = ELFNAME(read_from)(p, epp->ep_vp, eh->e_shoff, (caddr_t)sh,
shsize);
if (error)
goto out;
for (i = 0; i < eh->e_shnum; i++) {
@ -123,9 +123,10 @@ ELFNAME2(linux,gcc_signature)(p, epp, eh)
s->sh_size < sizeof(signature) - 1)
continue;
if ((error = ELFNAME(read_from)(p, epp->ep_vp, s->sh_offset,
(caddr_t) buf, sizeof(signature) - 1)) != 0)
goto out;
error = ELFNAME(read_from)(p, epp->ep_vp, s->sh_offset,
(caddr_t)buf, sizeof(signature) - 1);
if (error)
continue;
/*
* error is 0, if the signatures match we are done.
@ -133,115 +134,90 @@ ELFNAME2(linux,gcc_signature)(p, epp, eh)
#ifdef DEBUG_LINUX
printf("linux_gcc_sig: sig=%s\n", buf);
#endif
if (memcmp(buf, signature, sizeof(signature) - 1) == 0)
if (!memcmp(buf, signature, sizeof(signature) - 1)) {
error = 0;
goto out;
}
}
error = ENOEXEC;
out:
free(sh, M_TEMP);
#ifdef DEBUG_LINUX
printf("linux_gcc_sig: returning %d\n", error);
#endif
return error;
return (error);
}
#endif
static int
ELFNAME2(linux,signature)(p, epp, eh)
ELFNAME2(linux,signature)(p, epp, eh, itp)
struct proc *p;
struct exec_package *epp;
Elf_Ehdr *eh;
char *itp;
{
size_t i;
Elf_Phdr *ph;
Elf_Nhdr *notep;
size_t phsize;
int error = ENOEXEC;
int error;
phsize = eh->e_phnum * sizeof(Elf_Phdr);
ph = (Elf_Phdr *)malloc(phsize, M_TEMP, M_WAITOK);
if ((error = ELFNAME(read_from)(p, epp->ep_vp, eh->e_phoff,
(caddr_t) ph, phsize)) != 0)
goto out1;
error = ELFNAME(read_from)(p, epp->ep_vp, eh->e_phoff, (caddr_t)ph,
phsize);
if (error)
goto out;
for (i = 0; i < eh->e_phnum; i++) {
Elf_Phdr *ephp = &ph[i];
u_int32_t ostype;
Elf_Nhdr *np;
u_int32_t *abi;
if (ephp->p_type != PT_INTERP /* XAX PT_NOTE */
#if 0
|| ephp->p_flags != 0
|| ephp->p_filesz < sizeof(Elf_Nhdr))
#endif
)
if (ephp->p_type != PT_NOTE ||
ephp->p_filesz > 1024 ||
ephp->p_filesz < sizeof(Elf_Nhdr) + 20)
continue;
notep = (Elf_Nhdr *)malloc(ephp->p_filesz+1, M_TEMP, M_WAITOK);
if ((error = ELFNAME(read_from)(p, epp->ep_vp, ephp->p_offset,
(caddr_t)notep, ephp->p_filesz)) != 0)
goto out3;
np = (Elf_Nhdr *)malloc(ephp->p_filesz, M_TEMP, M_WAITOK);
error = ELFNAME(read_from)(p, epp->ep_vp, ephp->p_offset,
(caddr_t)np, ephp->p_filesz);
if (error)
goto next;
/* Check for "linux" in the intepreter name. */
if (ephp->p_filesz < 8 + 5) {
error = ENOEXEC;
goto out3;
}
#ifdef DEBUG_LINUX
printf("linux_signature: interp=%s\n", (char *)notep);
#endif
if (strncmp(&((char *)notep)[8], "linux", 5) == 0 ||
strncmp((char *)notep, "/lib/ld.so.", 11) == 0) {
if (np->n_type != ELF_NOTE_TYPE_ABI_TAG ||
np->n_namesz != ELF_NOTE_ABI_NAMESZ ||
np->n_descsz != ELF_NOTE_ABI_DESCSZ ||
memcmp((caddr_t)(np + 1), ELF_NOTE_ABI_NAME,
ELF_NOTE_ABI_NAMESZ))
goto next;
/* Make sure the OS is Linux. */
abi = (u_int32_t *)((caddr_t)np + sizeof(Elf_Nhdr) +
np->n_namesz);
if (abi[0] == ELF_NOTE_ABI_OS_LINUX)
error = 0;
goto out3;
}
else
error = ENOEXEC;
free(np, M_TEMP);
goto out;
goto out2;
next:
free(np, M_TEMP);
continue;
}
/* XXX XAX Should handle NETBSD_TYPE_EMULNAME */
if (notep->n_type != ELF_NOTE_TYPE_OSVERSION) {
free(notep, M_TEMP);
continue;
}
/* Check the name and description sizes. */
if (notep->n_namesz != ELF_NOTE_GNU_NAMESZ ||
notep->n_descsz != ELF_NOTE_GNU_DESCSZ)
goto out2;
/* Is the name "GNU\0"? */
if (memcmp((notep + sizeof(Elf_Nhdr)),
ELF_NOTE_GNU_NAME, ELF_NOTE_GNU_NAMESZ))
goto out2;
/* Make sure the OS is Linux */
ostype = (u_int32_t)(*((u_int32_t *)notep + sizeof(Elf_Nhdr) +
notep->n_namesz)) & ELF_NOTE_GNU_OSMASK;
if (ostype != ELF_NOTE_GNU_OSLINUX)
goto out2;
/* All checks succeeded. */
error = 0;
goto out3;
/* Check for certain intepreter names. */
if (itp[0]) {
if (!strncmp(itp, "/lib/ld-linux", 13) ||
!strncmp(itp, "/lib/ld.so.", 11))
error = 0;
else
error = ENOEXEC;
goto out;
}
error = ENOEXEC;
out1:
out:
free(ph, M_TEMP);
#ifdef DEBUG_LINUX
printf("linux_signature: out1=%d\n", error);
#endif
return error;
out2:
error = ENOEXEC;
out3:
free(notep, M_TEMP);
free(ph, M_TEMP);
#ifdef DEBUG_LINUX
printf("linux_signature: out2,3=%d\n", error);
#endif
return error;
return (error);
}
int
@ -256,7 +232,7 @@ ELFNAME2(linux,probe)(p, epp, eh, itp, pos)
int error;
size_t len;
if ((error = ELFNAME2(linux,signature)(p, epp, eh)) != 0)
if ((error = ELFNAME2(linux,signature)(p, epp, eh, itp)) != 0)
#ifdef LINUX_GCC_SIGNATURE
if ((error = ELFNAME2(linux,gcc_signature)(p, epp, eh)) != 0)
return error;

View File

@ -1,4 +1,4 @@
/* $NetBSD: exec_elf32.c,v 1.60 2000/12/11 05:29:02 mycroft Exp $ */
/* $NetBSD: exec_elf32.c,v 1.61 2000/12/15 06:14:21 mycroft Exp $ */
/*-
* Copyright (c) 1994, 2000 The NetBSD Foundation, Inc.
@ -179,20 +179,24 @@ ELFNAME(check_header)(Elf_Ehdr *eh, int type)
if (memcmp(eh->e_ident, ELFMAG, SELFMAG) != 0 ||
eh->e_ident[EI_CLASS] != ELFCLASS)
return ENOEXEC;
return (ENOEXEC);
switch (eh->e_machine) {
ELFDEFNNAME(MACHDEP_ID_CASES)
default:
return ENOEXEC;
return (ENOEXEC);
}
if (eh->e_type != type)
return ENOEXEC;
return (ENOEXEC);
return 0;
if (eh->e_shnum > 128 ||
eh->e_phnum > 128)
return (ENOEXEC);
return (0);
}
/*
@ -638,57 +642,53 @@ int
ELFNAME2(netbsd,signature)(struct proc *p, struct exec_package *epp,
Elf_Ehdr *eh)
{
Elf_Phdr *hph, *ph;
Elf_Nhdr *np = NULL;
size_t i;
Elf_Phdr *ph;
size_t phsize;
int error;
phsize = eh->e_phnum * sizeof(Elf_Phdr);
hph = (Elf_Phdr *)malloc(phsize, M_TEMP, M_WAITOK);
if ((error = ELFNAME(read_from)(p, epp->ep_vp, eh->e_phoff,
(caddr_t)hph, phsize)) != 0)
goto out1;
ph = (Elf_Phdr *)malloc(phsize, M_TEMP, M_WAITOK);
error = ELFNAME(read_from)(p, epp->ep_vp, eh->e_phoff, (caddr_t)ph,
phsize);
if (error)
goto out;
for (ph = hph; ph < &hph[eh->e_phnum]; ph++) {
if (ph->p_type != PT_NOTE ||
ph->p_filesz < sizeof(Elf_Nhdr) + ELF_NOTE_NETBSD_NAMESZ)
for (i = 0; i < eh->e_phnum; i++) {
Elf_Phdr *ephp = &ph[i];
Elf_Nhdr *np;
if (ephp->p_type != PT_NOTE ||
ephp->p_filesz > 1024 ||
ephp->p_filesz < sizeof(Elf_Nhdr) + ELF_NOTE_NETBSD_NAMESZ)
continue;
np = (Elf_Nhdr *)malloc(ph->p_filesz, M_TEMP, M_WAITOK);
if ((error = ELFNAME(read_from)(p, epp->ep_vp, ph->p_offset,
(caddr_t)np, ph->p_filesz)) != 0)
goto out2;
np = (Elf_Nhdr *)malloc(ephp->p_filesz, M_TEMP, M_WAITOK);
error = ELFNAME(read_from)(p, epp->ep_vp, ephp->p_offset,
(caddr_t)np, ephp->p_filesz);
if (error)
goto next;
if (np->n_type != ELF_NOTE_TYPE_OSVERSION) {
free(np, M_TEMP);
np = NULL;
continue;
}
/* Check the name and description sizes. */
if (np->n_namesz != ELF_NOTE_NETBSD_NAMESZ ||
np->n_descsz != ELF_NOTE_NETBSD_DESCSZ)
goto out3;
/* Is the name "NetBSD\0\0"? */
if (memcmp((np + 1), ELF_NOTE_NETBSD_NAME,
if (np->n_type != ELF_NOTE_TYPE_NETBSD_TAG ||
np->n_namesz != ELF_NOTE_NETBSD_NAMESZ ||
np->n_descsz != ELF_NOTE_NETBSD_DESCSZ ||
memcmp((caddr_t)(np + 1), ELF_NOTE_NETBSD_NAME,
ELF_NOTE_NETBSD_NAMESZ))
goto out3;
goto next;
/* XXX: We could check for the specific emulation here */
/* All checks succeeded. */
error = 0;
goto out2;
free(np, M_TEMP);
goto out;
next:
free(np, M_TEMP);
continue;
}
out3:
error = ENOEXEC;
out2:
if (np)
free(np, M_TEMP);
out1:
free(hph, M_TEMP);
return error;
out:
free(ph, M_TEMP);
return (error);
}
int

View File

@ -1,4 +1,4 @@
/* $NetBSD: exec_elf.h,v 1.39 2000/07/26 02:04:53 mycroft Exp $ */
/* $NetBSD: exec_elf.h,v 1.40 2000/12/15 06:14:21 mycroft Exp $ */
/*-
* Copyright (c) 1994 The NetBSD Foundation, Inc.
@ -557,13 +557,21 @@ typedef struct {
Elf64_Half n_type;
} Elf64_Nhdr;
#define ELF_NOTE_TYPE_OSVERSION 1
#define ELF_NOTE_TYPE_ABI_TAG 1
/* NetBSD-specific note type: OS Version. desc is 4-byte NetBSD integer. */
#define ELF_NOTE_NETBSD_TYPE_OSVERSION ELF_NOTE_TYPE_OSVERSION
/* GNU-specific note name and description sizes */
#define ELF_NOTE_ABI_NAMESZ 4
#define ELF_NOTE_ABI_DESCSZ 16
/* GNU-specific note name */
#define ELF_NOTE_ABI_NAME "GNU\0"
/* GNU-specific OS/version value stuff */
#define ELF_NOTE_ABI_OS_LINUX 0
#define ELF_NOTE_ABI_OS_HURD 1
#define ELF_NOTE_ABI_OS_SOLARIS 2
/* NetBSD-specific note type: Emulation name. desc is emul name string. */
#define ELF_NOTE_NETBSD_TYPE_EMULNAME 2
#define ELF_NOTE_TYPE_NETBSD_TAG 1
/* NetBSD-specific note name and description sizes */
#define ELF_NOTE_NETBSD_NAMESZ 7
@ -571,17 +579,6 @@ typedef struct {
/* NetBSD-specific note name */
#define ELF_NOTE_NETBSD_NAME "NetBSD\0\0"
/* GNU-specific note name and description sizes */
#define ELF_NOTE_GNU_NAMESZ 4
#define ELF_NOTE_GNU_DESCSZ 4
/* GNU-specific note name */
#define ELF_NOTE_GNU_NAME "GNU\0"
/* GNU-specific OS/version value stuff */
#define ELF_NOTE_GNU_OSMASK (__uint32_t)0xff000000
#define ELF_NOTE_GNU_OSLINUX (__uint32_t)0x01000000
#define ELF_NOTE_GNU_OSMACH (__uint32_t)0x00000000
#if defined(ELFSIZE)
#define CONCAT(x,y) __CONCAT(x,y)
#define ELFNAME(x) CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x)))