diff --git a/lib/csu/common/crtbrand.c b/lib/csu/common/crtbrand.c index 7e90144..e3309f8 100644 --- a/lib/csu/common/crtbrand.c +++ b/lib/csu/common/crtbrand.c @@ -43,7 +43,7 @@ static const struct { int32_t type; char name[sizeof ABI_VENDOR]; int32_t desc; -} abitag __attribute__ ((section (ABI_SECTION), aligned(4))) __unused = { +} abitag __attribute__ ((section (ABI_SECTION), aligned(4), used)) __unused = { sizeof ABI_VENDOR, sizeof(int32_t), ABI_NOTETYPE, diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c index 62d81f6..577851f 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -144,6 +144,9 @@ SYSCTL_INT(_machdep, OID_AUTO, kdb_on_nmi, CTLFLAG_RW, static int panic_on_nmi = 1; SYSCTL_INT(_machdep, OID_AUTO, panic_on_nmi, CTLFLAG_RW, &panic_on_nmi, 0, "Panic on NMI"); +static int prot_fault_translation = 0; +SYSCTL_INT(_machdep, OID_AUTO, prot_fault_translation, CTLFLAG_RW, + &prot_fault_translation, 0, "Select signal to deliver on protection fault"); extern char *syscallnames[]; @@ -312,8 +315,32 @@ trap(struct trapframe *frame) if (i == SIGSEGV) ucode = SEGV_MAPERR; else { - i = SIGSEGV; /* XXX hack */ - ucode = SEGV_ACCERR; + if (prot_fault_translation == 0) { + /* + * Autodetect. + * This check also covers the images + * without the ABI-tag ELF note. + */ + if (p->p_osrel >= 700004) { + i = SIGSEGV; + ucode = SEGV_ACCERR; + } else { + i = SIGBUS; + ucode = BUS_PAGE_FAULT; + } + } else if (prot_fault_translation == 1) { + /* + * Always compat mode. + */ + i = SIGBUS; + ucode = BUS_PAGE_FAULT; + } else { + /* + * Always SIGSEGV mode. + */ + i = SIGSEGV; + ucode = SEGV_ACCERR; + } } break; diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c index e66fa1e..cddffc0 100644 --- a/sys/i386/i386/trap.c +++ b/sys/i386/i386/trap.c @@ -158,6 +158,9 @@ SYSCTL_INT(_machdep, OID_AUTO, kdb_on_nmi, CTLFLAG_RW, static int panic_on_nmi = 1; SYSCTL_INT(_machdep, OID_AUTO, panic_on_nmi, CTLFLAG_RW, &panic_on_nmi, 0, "Panic on NMI"); +static int prot_fault_translation = 0; +SYSCTL_INT(_machdep, OID_AUTO, prot_fault_translation, CTLFLAG_RW, + &prot_fault_translation, 0, "Select signal to deliver on protection fault"); extern char *syscallnames[]; @@ -375,8 +378,32 @@ trap(struct trapframe *frame) if (i == SIGSEGV) ucode = SEGV_MAPERR; else { - i = SIGSEGV; /* XXX hack */ - ucode = SEGV_ACCERR; + if (prot_fault_translation == 0) { + /* + * Autodetect. + * This check also covers the images + * without the ABI-tag ELF note. + */ + if (p->p_osrel >= 700004) { + i = SIGSEGV; + ucode = SEGV_ACCERR; + } else { + i = SIGBUS; + ucode = BUS_PAGE_FAULT; + } + } else if (prot_fault_translation == 1) { + /* + * Always compat mode. + */ + i = SIGBUS; + ucode = BUS_PAGE_FAULT; + } else { + /* + * Always SIGSEGV mode. + */ + i = SIGSEGV; + ucode = SEGV_ACCERR; + } } addr = eva; break; diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index 6c77244..3bf667f 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -106,6 +106,10 @@ SYSCTL_INT(_debug, OID_AUTO, __elfN(legacy_coredump), CTLFLAG_RW, static Elf_Brandinfo *elf_brand_list[MAX_BRANDS]; +#define trunc_page_ps(va, ps) ((va) & ~(ps - 1)) +#define round_page_ps(va, ps) (((va) + (ps - 1)) & ~(ps - 1)) +#define aligned(a, t) (trunc_page_ps((u_long)(a), sizeof(t)) == (u_long)(a)) + int __elfN(insert_brand_entry)(Elf_Brandinfo *entry) { @@ -360,9 +364,6 @@ __elfN(load_section)(struct vmspace *vmspace, return (ENOEXEC); } -#define trunc_page_ps(va, ps) ((va) & ~(ps - 1)) -#define round_page_ps(va, ps) (((va) + (ps - 1)) & ~(ps - 1)) - map_addr = trunc_page_ps((vm_offset_t)vmaddr, pagesize); file_addr = trunc_page_ps(offset, pagesize); @@ -549,6 +550,10 @@ __elfN(load_file)(struct proc *p, const char *file, u_long *addr, } phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff); + if (!aligned(phdr, Elf_Addr)) { + error = ENOEXEC; + goto fail; + } for (i = 0, numsegs = 0; i < hdr->e_phnum; i++) { if (phdr[i].p_type == PT_LOAD) { /* Loadable segment */ @@ -592,11 +597,13 @@ fail: return (error); } +static const char FREEBSD_ABI_VENDOR[] = "FreeBSD"; + static int __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) { const Elf_Ehdr *hdr = (const Elf_Ehdr *)imgp->image_header; - const Elf_Phdr *phdr; + const Elf_Phdr *phdr, *pnote = NULL; Elf_Auxargs *elf_auxargs; struct vmspace *vmspace; vm_prot_t prot; @@ -607,7 +614,9 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) int error = 0, i; const char *interp = NULL; Elf_Brandinfo *brand_info; + const Elf_Note *note, *note_end; char *path; + const char *note_name; struct thread *td = curthread; struct sysentvec *sv; @@ -632,6 +641,8 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) return (ENOEXEC); } phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff); + if (!aligned(phdr, Elf_Addr)) + return (ENOEXEC); for (i = 0; i < hdr->e_phnum; i++) { if (phdr[i].p_type == PT_INTERP) { /* Path to interpreter */ @@ -747,6 +758,11 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) case PT_PHDR: /* Program header table info */ proghdr = phdr[i].p_vaddr; break; + case PT_NOTE: + pnote = &phdr[i]; + if (!aligned(pnote, Elf32_Addr)) + return (ENOEXEC); + break; default: break; } @@ -828,6 +844,36 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) imgp->auxargs = elf_auxargs; imgp->interpreted = 0; + /* + * Try to fetch the osreldate for FreeBSD binary from the ELF + * OSABI-note. Only the first page of the image is searched, + * the same as for headers. + */ + if (pnote != NULL && pnote->p_offset < PAGE_SIZE && + pnote->p_offset + pnote->p_filesz < PAGE_SIZE ) { + note = (const Elf_Note *)(imgp->image_header + pnote->p_offset); + note_end = (const Elf_Note *)(imgp->image_header + pnote->p_offset + + pnote->p_filesz); + while (note < note_end) { + if (note->n_namesz == sizeof(FREEBSD_ABI_VENDOR) && + note->n_descsz == sizeof(int32_t) && + note->n_type == 1 /* ABI_NOTETYPE */) { + note_name = (const char *)(note + 1); + if (strncmp(FREEBSD_ABI_VENDOR, note_name, + sizeof(FREEBSD_ABI_VENDOR)) == 0) { + imgp->proc->p_osrel = *(const int32_t *) + (note_name + + round_page_ps(sizeof(FREEBSD_ABI_VENDOR), + sizeof(Elf32_Addr))); + break; + } + } + note = (const Elf_Note *)((const char *)(note + 1) + + round_page_ps(note->n_namesz, sizeof(Elf32_Addr)) + + round_page_ps(note->n_descsz, sizeof(Elf32_Addr))); + } + } + return (error); } @@ -894,8 +940,6 @@ static void __elfN(puthdr)(struct thread *, void *, size_t *, int); static void __elfN(putnote)(void *, size_t *, const char *, int, const void *, size_t); -extern int osreldate; - int __elfN(coredump)(td, vp, limit) struct thread *td; diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index d4c04e5..3a85150 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -373,9 +373,10 @@ proc0_init(void *dummy __unused) td = &thread0; /* - * Initialize magic number. + * Initialize magic number and osrel. */ p->p_magic = P_MAGIC; + p->p_osrel = osreldate; /* * Initialize thread and process structures. diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 2d32c34..6545614 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -391,6 +391,7 @@ interpret: if (error) goto exec_fail_dealloc; + imgp->proc->p_osrel = 0; /* * If the current process has a special image activator it * wants to try first, call it. For example, emulating shell diff --git a/sys/kern/kern_mib.c b/sys/kern/kern_mib.c index 7280c52..78a9445 100644 --- a/sys/kern/kern_mib.c +++ b/sys/kern/kern_mib.c @@ -104,7 +104,6 @@ SYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD, * NOTICE: The *userland* release date is available in * /usr/include/osreldate.h */ -extern int osreldate; SYSCTL_INT(_kern, KERN_OSRELDATE, osreldate, CTLFLAG_RD, &osreldate, 0, "Kernel release date"); diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 54a8413..d75acb9 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -561,6 +561,8 @@ struct proc { /* The following fields are all copied upon creation in fork. */ #define p_startcopy p_endzero u_int p_magic; /* (b) Magic number. */ + int p_osrel; /* (x) osreldate for the + binary (from ELF note, if any) */ char p_comm[MAXCOMLEN + 1]; /* (b) Process name. */ struct pgrp *p_pgrp; /* (c + e) Pointer to process group. */ struct sysentvec *p_sysent; /* (b) Syscall dispatch info. */ diff --git a/sys/sys/systm.h b/sys/sys/systm.h index 1a9d964..95bc05f 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -101,6 +101,7 @@ extern int maxusers; /* system tune hint */ * in two files. * XXX most of these variables should be const. */ +extern int osreldate; extern int envmode; extern int hintmode; /* 0 = off. 1 = config, 2 = fallback */ extern int dynamic_kenv;