Rework how shared page related data is stored

Store the shared page address in struct vmspace.
Also instead of storing absolute addresses of various shared page
segments save their offsets with respect to the shared page address.
This will be more useful when the shared page address is randomized.

Approved by:	mw(mentor)
Sponsored by:	Stormshield
Obtained from:	Semihalf
Reviewed by:	kib
Differential Revision: https://reviews.freebsd.org/D35393
This commit is contained in:
Kornel Dulęba 2022-06-02 09:58:12 +02:00
parent f6ac79fb12
commit 361971fbca
23 changed files with 75 additions and 67 deletions

View File

@ -77,6 +77,7 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_param.h>
#include <vm/vm_extern.h>
#include <vm/pmap.h>
#include <vm/vm_map.h>
#ifdef DDB
#ifndef KDB

View File

@ -772,7 +772,7 @@ linux_exec_sysvec_init(void *param)
tkoff = kern_timekeep_base - linux_vdso_base;
ktimekeep_base = (l_uintptr_t *)(linux_vdso_mapping + tkoff);
*ktimekeep_base = sv->sv_timekeep_base;
*ktimekeep_base = sv->sv_shared_page_base + sv->sv_timekeep_offset;
tkoff = kern_tsc_selector - linux_vdso_base;
ktsc_selector = (l_uintptr_t *)(linux_vdso_mapping + tkoff);

View File

@ -924,7 +924,7 @@ linux_exec_sysvec_init(void *param)
tkoff = kern_timekeep_base - linux_vdso_base;
ktimekeep_base = (l_uintptr_t *)(linux_vdso_mapping + tkoff);
*ktimekeep_base = sv->sv_timekeep_base;
*ktimekeep_base = sv->sv_shared_page_base + sv->sv_timekeep_offset;
tkoff = kern_tsc_selector - linux_vdso_base;
ktsc_selector = (l_uintptr_t *)(linux_vdso_mapping + tkoff);

View File

@ -346,7 +346,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
tf->tf_pc = (register_t)catcher;
tf->tf_usr_sp = (register_t)fp;
sysent = p->p_sysent;
if (sysent->sv_sigcode_base != 0)
if (PROC_HAS_SHP(p))
tf->tf_usr_lr = (register_t)PROC_SIGCODE(p);
else
tf->tf_usr_lr = (register_t)(PROC_PS_STRINGS(p) -

View File

@ -50,6 +50,8 @@ __FBSDID("$FreeBSD$");
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>
#include <vm/vm_map.h>
#include <machine/armreg.h>
#include <machine/kdb.h>

View File

@ -418,7 +418,7 @@ freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
tf->tf_elr = (register_t)catcher;
tf->tf_x[13] = (register_t)fp;
sysent = p->p_sysent;
if (sysent->sv_sigcode_base != 0)
if (PROC_HAS_SHP(p))
tf->tf_x[14] = (register_t)PROC_SIGCODE(p);
else
tf->tf_x[14] = (register_t)(PROC_PS_STRINGS(p) -

View File

@ -619,7 +619,7 @@ linux_exec_sysvec_init(void *param)
tkoff = kern_timekeep_base - linux_vdso_base;
ktimekeep_base = (l_uintptr_t *)(linux_vdso_mapping + tkoff);
*ktimekeep_base = sv->sv_timekeep_base;
*ktimekeep_base = sv->sv_shared_page_base + sv->sv_timekeep_offset;
}
SYSINIT(elf_linux_exec_sysvec_init, SI_SUB_EXEC + 1, SI_ORDER_ANY,
linux_exec_sysvec_init, &elf_linux_sysvec);

View File

@ -3525,7 +3525,7 @@ freebsd32_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
/*
* Install sigcode.
*/
if (sysent->sv_sigcode_base == 0) {
if (!PROC_HAS_SHP(imgp->proc)) {
szsigcode = *sysent->sv_szsigcode;
destp -= szsigcode;
destp = rounddown2(destp, sizeof(uint32_t));

View File

@ -237,7 +237,7 @@ osendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
}
regs->tf_esp = (int)fp;
if (p->p_sysent->sv_sigcode_base != 0) {
if (PROC_HAS_SHP(p)) {
regs->tf_eip = PROC_SIGCODE(p) + szsigcode -
szosigcode;
} else {

View File

@ -866,7 +866,7 @@ linux_exec_sysvec_init(void *param)
tkoff = kern_timekeep_base - linux_vdso_base;
ktimekeep_base = (l_uintptr_t *)(linux_vdso_mapping + tkoff);
*ktimekeep_base = sv->sv_timekeep_base;
*ktimekeep_base = sv->sv_shared_page_base + sv->sv_timekeep_offset;
tkoff = kern_tsc_selector - linux_vdso_base;
ktsc_selector = (l_uintptr_t *)(linux_vdso_mapping + tkoff);

View File

@ -1433,11 +1433,14 @@ __elfN(freebsd_copyout_auxargs)(struct image_params *imgp, uintptr_t base)
{
Elf_Auxargs *args = (Elf_Auxargs *)imgp->auxargs;
Elf_Auxinfo *argarray, *pos;
struct vmspace *vmspace;
int error;
argarray = pos = malloc(AT_COUNT * sizeof(*pos), M_TEMP,
M_WAITOK | M_ZERO);
vmspace = imgp->proc->p_vmspace;
if (args->execfd != -1)
AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
@ -1461,9 +1464,9 @@ __elfN(freebsd_copyout_auxargs)(struct image_params *imgp, uintptr_t base)
AUXARGS_ENTRY_PTR(pos, AT_PAGESIZES, imgp->pagesizes);
AUXARGS_ENTRY(pos, AT_PAGESIZESLEN, imgp->pagesizeslen);
}
if (imgp->sysent->sv_timekeep_base != 0) {
if ((imgp->sysent->sv_flags & SV_TIMEKEEP) != 0) {
AUXARGS_ENTRY(pos, AT_TIMEKEEP,
imgp->sysent->sv_timekeep_base);
vmspace->vm_shp_base + imgp->sysent->sv_timekeep_offset);
}
AUXARGS_ENTRY(pos, AT_STACKPROT, imgp->sysent->sv_shared_page_obj
!= NULL && imgp->stack_prot != 0 ? imgp->stack_prot :
@ -1479,10 +1482,16 @@ __elfN(freebsd_copyout_auxargs)(struct image_params *imgp, uintptr_t base)
AUXARGS_ENTRY(pos, AT_ENVC, imgp->args->envc);
AUXARGS_ENTRY_PTR(pos, AT_ENVV, imgp->envv);
AUXARGS_ENTRY_PTR(pos, AT_PS_STRINGS, imgp->ps_strings);
if (imgp->sysent->sv_fxrng_gen_base != 0)
AUXARGS_ENTRY(pos, AT_FXRNG, imgp->sysent->sv_fxrng_gen_base);
if (imgp->sysent->sv_vdso_base != 0 && __elfN(vdso) != 0)
AUXARGS_ENTRY(pos, AT_KPRELOAD, imgp->sysent->sv_vdso_base);
#ifdef RANDOM_FENESTRASX
if ((imgp->sysent->sv_flags & SV_RNG_SEED_VER) != 0) {
AUXARGS_ENTRY(pos, AT_FXRNG,
vmspace->vm_shp_base + imgp->sysent->sv_fxrng_gen_offset);
}
#endif
if ((imgp->sysent->sv_flags & SV_DSO_SIG) != 0 && __elfN(vdso) != 0) {
AUXARGS_ENTRY(pos, AT_KPRELOAD,
vmspace->vm_shp_base + imgp->sysent->sv_vdso_offset);
}
AUXARGS_ENTRY(pos, AT_NULL, 0);
free(imgp->auxargs, M_TEMP);

View File

@ -1106,18 +1106,16 @@ void
exec_free_abi_mappings(struct proc *p)
{
struct vmspace *vmspace;
struct sysentvec *sv;
vmspace = p->p_vmspace;
if (refcount_load(&vmspace->vm_refcnt) != 1)
return;
sv = p->p_sysent;
if (sv->sv_shared_page_obj == NULL)
if (!PROC_HAS_SHP(p))
return;
pmap_remove(vmspace_pmap(vmspace), sv->sv_shared_page_base,
sv->sv_shared_page_base + sv->sv_shared_page_len);
pmap_remove(vmspace_pmap(vmspace), vmspace->vm_shp_base,
vmspace->vm_shp_base + p->p_sysent->sv_shared_page_len);
}
/*
@ -1192,6 +1190,7 @@ exec_new_vmspace(struct image_params *imgp, struct sysentvec *sv)
vm_object_deallocate(obj);
return (vm_mmap_to_errno(error));
}
vmspace->vm_shp_base = sv->sv_shared_page_base;
}
return (sv->sv_onexec != NULL ? sv->sv_onexec(p, imgp) : 0);
@ -1633,7 +1632,7 @@ exec_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
/*
* Install sigcode.
*/
if (sysent->sv_sigcode_base == 0 && sysent->sv_szsigcode != NULL) {
if (sysent->sv_shared_page_base == 0 && sysent->sv_szsigcode != NULL) {
szsigcode = *(sysent->sv_szsigcode);
destp -= szsigcode;
destp = rounddown2(destp, sizeof(void *));

View File

@ -3096,7 +3096,7 @@ sysctl_kern_proc_sigtramp(SYSCTL_HANDLER_ARGS)
if ((req->flags & SCTL_MASK32) != 0) {
bzero(&kst32, sizeof(kst32));
if (SV_PROC_FLAG(p, SV_ILP32)) {
if (sv->sv_sigcode_base != 0) {
if (PROC_HAS_SHP(p)) {
kst32.ksigtramp_start = PROC_SIGCODE(p);
kst32.ksigtramp_end = kst32.ksigtramp_start +
((sv->sv_flags & SV_DSO_SIG) == 0 ?
@ -3114,7 +3114,7 @@ sysctl_kern_proc_sigtramp(SYSCTL_HANDLER_ARGS)
}
#endif
bzero(&kst, sizeof(kst));
if (sv->sv_sigcode_base != 0) {
if (PROC_HAS_SHP(p)) {
kst.ksigtramp_start = (char *)PROC_SIGCODE(p);
kst.ksigtramp_end = (char *)kst.ksigtramp_start +
((sv->sv_flags & SV_DSO_SIG) == 0 ? *sv->sv_szsigcode :

View File

@ -305,10 +305,6 @@ void
exec_sysvec_init(void *param)
{
struct sysentvec *sv;
vm_offset_t sb;
#ifdef RANDOM_FENESTRASX
ptrdiff_t base;
#endif
u_int flags;
int res;
@ -322,19 +318,18 @@ exec_sysvec_init(void *param)
sv->sv_shared_page_obj = shared_page_obj;
if ((flags & SV_ABI_MASK) == SV_ABI_FREEBSD) {
if ((flags & SV_DSO_SIG) != 0) {
sb = sv->sv_shared_page_base;
res = shared_page_fill((uintptr_t)sv->sv_szsigcode,
16, sv->sv_sigcode);
if (res == -1)
panic("copying sigtramp to shared page");
sb += res;
sv->sv_vdso_base = sb;
sb += sv->sv_sigcodeoff;
sv->sv_sigcode_base = sb;
panic("copying vdso to shared page");
sv->sv_vdso_offset = res;
sv->sv_sigcode_offset = res + sv->sv_sigcodeoff;
} else {
sv->sv_sigcode_base = sv->sv_shared_page_base +
shared_page_fill(*(sv->sv_szsigcode), 16,
sv->sv_sigcode);
res = shared_page_fill(*(sv->sv_szsigcode),
16, sv->sv_sigcode);
if (res == -1)
panic("copying sigtramp to shared page");
sv->sv_sigcode_offset = res;
}
}
if ((flags & SV_TIMEKEEP) != 0) {
@ -348,8 +343,7 @@ exec_sysvec_init(void *param)
KASSERT(compat32_svtk != NULL,
("Compat32 not registered"));
}
sv->sv_timekeep_base = sv->sv_shared_page_base +
compat32_svtk->sv_timekeep_off;
sv->sv_timekeep_offset = compat32_svtk->sv_timekeep_off;
} else {
#endif
if ((flags & SV_ABI_MASK) == SV_ABI_FREEBSD) {
@ -360,8 +354,7 @@ exec_sysvec_init(void *param)
KASSERT(host_svtk != NULL,
("Host not registered"));
}
sv->sv_timekeep_base = sv->sv_shared_page_base +
host_svtk->sv_timekeep_off;
sv->sv_timekeep_offset = host_svtk->sv_timekeep_off;
#ifdef COMPAT_FREEBSD32
}
#endif
@ -375,8 +368,8 @@ exec_sysvec_init(void *param)
*/
if (fxrng_shpage_mapping == NULL)
alloc_sv_fxrng_generation();
base = (char *)fxrng_shpage_mapping - shared_page_mapping;
sv->sv_fxrng_gen_base = sv->sv_shared_page_base + base;
sv->sv_fxrng_gen_offset =
(char *)fxrng_shpage_mapping - shared_page_mapping;
}
#endif
}
@ -392,20 +385,10 @@ exec_sysvec_init_secondary(struct sysentvec *sv, struct sysentvec *sv2)
(sv->sv_flags & SV_RNG_SEED_VER));
sv2->sv_shared_page_obj = sv->sv_shared_page_obj;
sv2->sv_sigcode_base = sv2->sv_shared_page_base +
(sv->sv_sigcode_base - sv->sv_shared_page_base);
if ((sv2->sv_flags & SV_DSO_SIG) != 0) {
sv2->sv_vdso_base = sv2->sv_shared_page_base +
(sv->sv_vdso_base - sv->sv_shared_page_base);
}
sv2->sv_sigcode_offset = sv->sv_sigcode_offset;
sv2->sv_vdso_offset = sv->sv_vdso_offset;
if ((sv2->sv_flags & SV_ABI_MASK) != SV_ABI_FREEBSD)
return;
if ((sv2->sv_flags & SV_TIMEKEEP) != 0) {
sv2->sv_timekeep_base = sv2->sv_shared_page_base +
(sv->sv_timekeep_base - sv->sv_shared_page_base);
}
if ((sv2->sv_flags & SV_RNG_SEED_VER) != 0) {
sv2->sv_fxrng_gen_base = sv2->sv_shared_page_base +
(sv->sv_fxrng_gen_base - sv->sv_shared_page_base);
}
sv2->sv_timekeep_offset = sv->sv_timekeep_offset;
sv2->sv_fxrng_gen_offset = sv->sv_fxrng_gen_offset;
}

View File

@ -52,6 +52,8 @@
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>
#include <vm/vm_map.h>
#include <machine/altivec.h>
#include <machine/cpu.h>

View File

@ -49,6 +49,8 @@
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>
#include <vm/vm_map.h>
#include <machine/altivec.h>
#include <machine/cpu.h>
@ -216,10 +218,10 @@ ppc64_init_sysvecs(void *arg)
* exec_sysvec_init_secondary() assumes secondary sysvecs use
* identical signal code, and skips allocating a second copy.
* Since the ELFv2 trampoline is a strict subset of the ELFv1 code,
* we can work around this by adjusting the base address. This also
* we can work around this by adjusting the offset. This also
* avoids two copies of the trampoline code being allocated!
*/
elf64_freebsd_sysvec_v2.sv_sigcode_base +=
elf64_freebsd_sysvec_v2.sv_sigcode_offset +=
(uintptr_t)sigcode64_elfv2 - (uintptr_t)&sigcode64;
elf64_freebsd_sysvec_v2.sv_szsigcode = &szsigcode64_elfv2;
}

View File

@ -34,6 +34,7 @@ __elfN(powerpc_copyout_auxargs)(struct image_params *imgp, uintptr_t base)
{
Elf_Auxargs *args;
Elf_Auxinfo *argarray, *pos;
struct vmspace *vmspace;
int error;
/*
@ -58,6 +59,8 @@ __elfN(powerpc_copyout_auxargs)(struct image_params *imgp, uintptr_t base)
argarray = pos = malloc(AT_OLD_COUNT * sizeof(*pos), M_TEMP,
M_WAITOK | M_ZERO);
vmspace = imgp->proc->p_vmspace;
if (args->execfd != -1)
AUXARGS_ENTRY(pos, AT_OLD_EXECFD, args->execfd);
AUXARGS_ENTRY(pos, AT_OLD_PHDR, args->phdr);
@ -81,9 +84,9 @@ __elfN(powerpc_copyout_auxargs)(struct image_params *imgp, uintptr_t base)
AUXARGS_ENTRY_PTR(pos, AT_OLD_PAGESIZES, imgp->pagesizes);
AUXARGS_ENTRY(pos, AT_OLD_PAGESIZESLEN, imgp->pagesizeslen);
}
if (imgp->sysent->sv_timekeep_base != 0) {
if ((imgp->sysent->sv_flags & SV_TIMEKEEP) != 0) {
AUXARGS_ENTRY(pos, AT_OLD_TIMEKEEP,
imgp->sysent->sv_timekeep_base);
vmspace->vm_shp_base + imgp->sysent->sv_timekeep_offset);
}
AUXARGS_ENTRY(pos, AT_OLD_STACKPROT, imgp->sysent->sv_shared_page_obj
!= NULL && imgp->stack_prot != 0 ? imgp->stack_prot :

View File

@ -94,7 +94,10 @@ __FBSDID("$FreeBSD$");
#include <machine/trap.h>
#include <machine/vmparam.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>
#include <vm/vm_map.h>
#ifdef FPU_EMU
#include <powerpc/fpu/fpu_extern.h>

View File

@ -415,7 +415,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
tf->tf_sp = (register_t)fp;
sysent = p->p_sysent;
if (sysent->sv_sigcode_base != 0)
if (PROC_HAS_SHP(p))
tf->tf_ra = (register_t)PROC_SIGCODE(p);
else
tf->tf_ra = (register_t)(PROC_PS_STRINGS(p) -

View File

@ -92,11 +92,13 @@ struct execsw {
/*
* Address of signal trampoline (in user space).
* This assumes that the sigcode resides in the shared page, which is true
* in all cases, except for a.out binaries.
* This assumes that the sigcode resides in the shared page.
*/
#define PROC_SIGCODE(p) \
((p)->p_sysent->sv_sigcode_base)
((p)->p_vmspace->vm_shp_base + (p)->p_sysent->sv_sigcode_offset)
#define PROC_HAS_SHP(p) \
((p)->p_sysent->sv_shared_page_obj != NULL)
int exec_map_first_page(struct image_params *);
void exec_unmap_first_page(struct image_params *);

View File

@ -137,19 +137,19 @@ struct sysentvec {
void (*sv_set_syscall_retval)(struct thread *, int);
int (*sv_fetch_syscall_args)(struct thread *);
const char **sv_syscallnames;
vm_offset_t sv_timekeep_base;
vm_offset_t sv_timekeep_offset;
vm_offset_t sv_shared_page_base;
vm_offset_t sv_shared_page_len;
vm_offset_t sv_sigcode_base;
vm_offset_t sv_sigcode_offset;
void *sv_shared_page_obj;
vm_offset_t sv_vdso_base;
vm_offset_t sv_vdso_offset;
void (*sv_schedtail)(struct thread *);
void (*sv_thread_detach)(struct thread *);
int (*sv_trap)(struct thread *);
u_long *sv_hwcap; /* Value passed in AT_HWCAP. */
u_long *sv_hwcap2; /* Value passed in AT_HWCAP2. */
const char *(*sv_machine_arch)(struct proc *);
vm_offset_t sv_fxrng_gen_base;
vm_offset_t sv_fxrng_gen_offset;
void (*sv_onexec_old)(struct thread *td);
int (*sv_onexec)(struct proc *, struct image_params *);
void (*sv_onexit)(struct proc *);

View File

@ -4259,6 +4259,7 @@ vmspace_fork(struct vmspace *vm1, vm_ooffset_t *fork_charge)
vm2->vm_daddr = vm1->vm_daddr;
vm2->vm_maxsaddr = vm1->vm_maxsaddr;
vm2->vm_stacktop = vm1->vm_stacktop;
vm2->vm_shp_base = vm1->vm_shp_base;
vm_map_lock(old_map);
if (old_map->busy)
vm_map_wait_busy(old_map);

View File

@ -295,6 +295,7 @@ struct vmspace {
caddr_t vm_daddr; /* (c) user virtual address of data */
caddr_t vm_maxsaddr; /* user VA at max stack growth */
vm_offset_t vm_stacktop; /* top of the stack, may not be page-aligned */
vm_offset_t vm_shp_base; /* shared page address */
u_int vm_refcnt; /* number of references */
/*
* Keep the PMAP last, so that CPU-specific variations of that