sync with OpenBSD -current
This commit is contained in:
parent
34a3d7e18a
commit
ee68147dcd
30 changed files with 722 additions and 211 deletions
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: exec_elf.c,v 1.183 2023/07/12 19:34:14 jasper Exp $ */
|
||||
/* $OpenBSD: exec_elf.c,v 1.184 2024/01/16 19:05:01 deraadt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1996 Per Fogelstrom
|
||||
|
@ -81,6 +81,7 @@
|
|||
#include <sys/ptrace.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/pledge.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
|
@ -97,6 +98,8 @@ void elf_load_psection(struct exec_vmcmd_set *, struct vnode *,
|
|||
Elf_Phdr *, Elf_Addr *, Elf_Addr *, int *, int);
|
||||
int elf_os_pt_note_name(Elf_Note *);
|
||||
int elf_os_pt_note(struct proc *, struct exec_package *, Elf_Ehdr *, int *);
|
||||
int elf_read_pintable(struct proc *p, struct vnode *vp, Elf_Phdr *pp,
|
||||
u_int **pinp, int is_ldso, size_t len);
|
||||
|
||||
/* round up and down to page boundaries. */
|
||||
#define ELF_ROUND(a, b) (((a) + (b) - 1) & ~((b) - 1))
|
||||
|
@ -265,6 +268,74 @@ elf_read_from(struct proc *p, struct vnode *vp, u_long off, void *buf,
|
|||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* rebase the pin offsets inside a base,len window for the text segment only.
|
||||
*/
|
||||
void
|
||||
elf_adjustpins(vaddr_t *basep, size_t *lenp, u_int *pins, int npins, u_int offset)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Adjust offsets, base, len */
|
||||
for (i = 0; i < npins; i++) {
|
||||
if (pins[i] == -1 || pins[i] == 0)
|
||||
continue;
|
||||
pins[i] -= offset;
|
||||
}
|
||||
*basep += offset;
|
||||
*lenp -= offset;
|
||||
}
|
||||
|
||||
int
|
||||
elf_read_pintable(struct proc *p, struct vnode *vp, Elf_Phdr *pp,
|
||||
u_int **pinp, int is_ldso, size_t len)
|
||||
{
|
||||
struct pinsyscalls {
|
||||
u_int offset;
|
||||
u_int sysno;
|
||||
} *syscalls = NULL;
|
||||
int i, nsyscalls = 0, npins = 0;
|
||||
u_int *pins = NULL;
|
||||
|
||||
if (pp->p_filesz > SYS_MAXSYSCALL * 2 * sizeof(*syscalls) ||
|
||||
pp->p_filesz % sizeof(*syscalls) != 0)
|
||||
goto bad;
|
||||
nsyscalls = pp->p_filesz / sizeof(*syscalls);
|
||||
syscalls = malloc(pp->p_filesz, M_PINSYSCALL, M_WAITOK);
|
||||
if (elf_read_from(p, vp, pp->p_offset, syscalls,
|
||||
pp->p_filesz) != 0)
|
||||
goto bad;
|
||||
|
||||
/* Validate, and calculate pintable size */
|
||||
for (i = 0; i < nsyscalls; i++) {
|
||||
if (syscalls[i].sysno <= 0 ||
|
||||
syscalls[i].sysno >= SYS_MAXSYSCALL ||
|
||||
syscalls[i].offset > len)
|
||||
goto bad;
|
||||
npins = MAX(npins, syscalls[i].sysno);
|
||||
}
|
||||
if (is_ldso)
|
||||
npins = MAX(npins, SYS_kbind); /* XXX see ld.so/loader.c */
|
||||
npins++;
|
||||
|
||||
/* Fill pintable: 0 = invalid, -1 = allowed, else offset from base */
|
||||
pins = mallocarray(npins, sizeof(u_int), M_PINSYSCALL, M_WAITOK|M_ZERO);
|
||||
for (i = 0; i < nsyscalls; i++) {
|
||||
if (pins[syscalls[i].sysno])
|
||||
pins[syscalls[i].sysno] = -1; /* duplicated */
|
||||
else
|
||||
pins[syscalls[i].sysno] = syscalls[i].offset;
|
||||
}
|
||||
if (is_ldso)
|
||||
pins[SYS_kbind] = -1; /* XXX see ld.so/loader.c */
|
||||
*pinp = pins;
|
||||
pins = NULL;
|
||||
bad:
|
||||
free(syscalls, M_PINSYSCALL, nsyscalls * sizeof(*syscalls));
|
||||
free(pins, M_PINSYSCALL, npins * sizeof(u_int));
|
||||
return npins;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load a file (interpreter/library) pointed to by path [stolen from
|
||||
* coff_load_shlib()]. Made slightly generic so it might be used externally.
|
||||
|
@ -276,7 +347,7 @@ elf_load_file(struct proc *p, char *path, struct exec_package *epp,
|
|||
int error, i;
|
||||
struct nameidata nd;
|
||||
Elf_Ehdr eh;
|
||||
Elf_Phdr *ph = NULL;
|
||||
Elf_Phdr *ph = NULL, *syscall_ph = NULL;
|
||||
u_long phsize = 0;
|
||||
Elf_Addr addr;
|
||||
struct vnode *vp;
|
||||
|
@ -290,6 +361,7 @@ elf_load_file(struct proc *p, char *path, struct exec_package *epp,
|
|||
int file_align;
|
||||
int loop;
|
||||
size_t randomizequota = ELF_RANDOMIZE_LIMIT;
|
||||
vaddr_t text_start = -1, text_end = 0;
|
||||
|
||||
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, path, p);
|
||||
nd.ni_pledge = PLEDGE_RPATH;
|
||||
|
@ -432,6 +504,12 @@ elf_load_file(struct proc *p, char *path, struct exec_package *epp,
|
|||
epp->ep_entry += pos;
|
||||
ap->arg_interp = pos;
|
||||
}
|
||||
if (prot & PROT_EXEC) {
|
||||
if (addr < text_start)
|
||||
text_start = addr;
|
||||
if (addr+size >= text_end)
|
||||
text_end = addr + size;
|
||||
}
|
||||
addr += size;
|
||||
break;
|
||||
|
||||
|
@ -461,12 +539,34 @@ elf_load_file(struct proc *p, char *path, struct exec_package *epp,
|
|||
NEW_VMCMD(&epp->ep_vmcmds, vmcmd_mutable,
|
||||
ph[i].p_memsz, ph[i].p_vaddr + pos, NULLVP, 0, 0);
|
||||
break;
|
||||
|
||||
case PT_OPENBSD_SYSCALLS:
|
||||
syscall_ph = &ph[i];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (syscall_ph) {
|
||||
struct process *pr = p->p_p;
|
||||
vaddr_t base = pos;
|
||||
size_t len = text_end;
|
||||
u_int *pins;
|
||||
int npins;
|
||||
|
||||
npins = elf_read_pintable(p, nd.ni_vp, syscall_ph,
|
||||
&pins, 1, len);
|
||||
if (npins) {
|
||||
elf_adjustpins(&base, &len, pins, npins,
|
||||
text_start);
|
||||
pr->ps_pin.pn_start = base;
|
||||
pr->ps_pin.pn_end = base + len;
|
||||
pr->ps_pin.pn_pins = pins;
|
||||
pr->ps_pin.pn_npins = npins;
|
||||
pr->ps_flags |= PS_PIN;
|
||||
}
|
||||
}
|
||||
|
||||
vn_marktext(nd.ni_vp);
|
||||
|
||||
bad1:
|
||||
|
@ -491,8 +591,8 @@ int
|
|||
exec_elf_makecmds(struct proc *p, struct exec_package *epp)
|
||||
{
|
||||
Elf_Ehdr *eh = epp->ep_hdr;
|
||||
Elf_Phdr *ph, *pp, *base_ph = NULL;
|
||||
Elf_Addr phdr = 0, exe_base = 0;
|
||||
Elf_Phdr *ph, *pp, *base_ph = NULL, *syscall_ph = NULL;
|
||||
Elf_Addr phdr = 0, exe_base = 0, exe_end = 0;
|
||||
int error, i, has_phdr = 0, names = 0, textrel = 0;
|
||||
char *interp = NULL;
|
||||
u_long phsize;
|
||||
|
@ -633,11 +733,13 @@ exec_elf_makecmds(struct proc *p, struct exec_package *epp)
|
|||
|
||||
/*
|
||||
* Permit system calls in main-text static binaries.
|
||||
* Also block the ld.so syscall-grant
|
||||
* static binaries may not call msyscall() or
|
||||
* pinsyscalls()
|
||||
*/
|
||||
if (interp == NULL) {
|
||||
syscall = VMCMD_SYSCALL;
|
||||
p->p_vmspace->vm_map.flags |= VM_MAP_SYSCALL_ONCE;
|
||||
p->p_vmspace->vm_map.flags |= VM_MAP_PINSYSCALL_ONCE;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -696,6 +798,9 @@ exec_elf_makecmds(struct proc *p, struct exec_package *epp)
|
|||
epp->ep_tsize = addr+size -
|
||||
epp->ep_taddr;
|
||||
}
|
||||
if (interp == NULL)
|
||||
exe_end = epp->ep_taddr +
|
||||
epp->ep_tsize; /* end of TEXT */
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -735,7 +840,10 @@ exec_elf_makecmds(struct proc *p, struct exec_package *epp)
|
|||
NEW_VMCMD(&epp->ep_vmcmds, vmcmd_mutable,
|
||||
ph[i].p_memsz, ph[i].p_vaddr + exe_base, NULLVP, 0, 0);
|
||||
break;
|
||||
|
||||
case PT_OPENBSD_SYSCALLS:
|
||||
if (interp == NULL)
|
||||
syscall_ph = &ph[i];
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Not fatal, we don't need to understand everything
|
||||
|
@ -745,6 +853,25 @@ exec_elf_makecmds(struct proc *p, struct exec_package *epp)
|
|||
}
|
||||
}
|
||||
|
||||
if (syscall_ph) {
|
||||
vaddr_t base = exe_base;
|
||||
size_t len = exe_end - exe_base;
|
||||
u_int *pins;
|
||||
int npins;
|
||||
|
||||
npins = elf_read_pintable(p, epp->ep_vp, syscall_ph,
|
||||
&pins, 0, len);
|
||||
if (npins) {
|
||||
elf_adjustpins(&base, &len, pins, npins,
|
||||
epp->ep_taddr - exe_base);
|
||||
epp->ep_pinstart = base;
|
||||
epp->ep_pinend = base + len;
|
||||
epp->ep_pins = pins;
|
||||
epp->ep_npins = npins;
|
||||
p->p_p->ps_flags |= PS_PIN;
|
||||
}
|
||||
}
|
||||
|
||||
phdr += exe_base;
|
||||
|
||||
/*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue