Page MenuHomeFreeBSD

D33704.id101415.diff
No OneTemporary

D33704.id101415.diff

Index: lib/libthr/thread/thr_init.c
===================================================================
--- lib/libthr/thread/thr_init.c
+++ lib/libthr/thread/thr_init.c
@@ -61,7 +61,7 @@
#include "libc_private.h"
#include "thr_private.h"
-char *_stacktop;
+char *_usrstack;
struct pthread *_thr_initial;
int _libthr_debug;
int _thread_event_mask;
@@ -388,7 +388,7 @@
* resource limits, so this stack needs an explicitly mapped
* red zone to protect the thread stack that is just beyond.
*/
- if (mmap(_stacktop - _thr_stack_initial -
+ if (mmap(_usrstack - _thr_stack_initial -
_thr_guard_default, _thr_guard_default, 0, MAP_ANON,
-1, 0) == MAP_FAILED)
PANIC("Cannot allocate red zone for initial thread");
@@ -402,7 +402,7 @@
* actually free() it; it just puts it in the free
* stack queue for later reuse.
*/
- thread->attr.stackaddr_attr = _stacktop - _thr_stack_initial;
+ thread->attr.stackaddr_attr = _usrstack - _thr_stack_initial;
thread->attr.stacksize_attr = _thr_stack_initial;
thread->attr.guardsize_attr = _thr_guard_default;
thread->attr.flags |= THR_STACK_USER;
@@ -427,7 +427,7 @@
thread->attr.prio = sched_param.sched_priority;
#ifdef _PTHREAD_FORCED_UNWIND
- thread->unwind_stackend = _stacktop;
+ thread->unwind_stackend = _usrstack;
#endif
/* Others cleared to zero by thr_alloc() */
@@ -464,13 +464,10 @@
__thr_malloc_init();
/* Find the stack top */
mib[0] = CTL_KERN;
- mib[1] = KERN_STACKTOP;
- len = sizeof (_stacktop);
- if (sysctl(mib, 2, &_stacktop, &len, NULL, 0) == -1) {
- mib[1] = KERN_USRSTACK;
- if (sysctl(mib, 2, &_stacktop, &len, NULL, 0) == -1)
- PANIC("Cannot get kern.usrstack from sysctl");
- }
+ mib[1] = KERN_USRSTACK;
+ len = sizeof (_usrstack);
+ if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1)
+ PANIC("Cannot get kern.usrstack from sysctl");
env_bigstack = getenv("LIBPTHREAD_BIGSTACK_MAIN");
env_splitstack = getenv("LIBPTHREAD_SPLITSTACK_MAIN");
if (env_bigstack != NULL || env_splitstack == NULL) {
Index: lib/libthr/thread/thr_private.h
===================================================================
--- lib/libthr/thread/thr_private.h
+++ lib/libthr/thread/thr_private.h
@@ -724,7 +724,7 @@
* Global variables for the pthread kernel.
*/
-extern char *_stacktop __hidden;
+extern char *_usrstack __hidden;
/* For debugger */
extern int _libthr_debug;
Index: lib/libthr/thread/thr_stack.c
===================================================================
--- lib/libthr/thread/thr_stack.c
+++ lib/libthr/thread/thr_stack.c
@@ -149,20 +149,17 @@
{
int mib[2];
struct rlimit rlim;
- u_long stacktop;
+ u_long usrstack;
size_t len;
mib[0] = CTL_KERN;
- mib[1] = KERN_STACKTOP;
- len = sizeof(stacktop);
- if (sysctl(mib, nitems(mib), &stacktop, &len, NULL, 0) == -1) {
- mib[1] = KERN_USRSTACK;
- if (sysctl(mib, nitems(mib), &stacktop, &len, NULL, 0) == -1)
- return;
- }
+ mib[1] = KERN_USRSTACK;
+ len = sizeof(usrstack);
+ if (sysctl(mib, nitems(mib), &usrstack, &len, NULL, 0) == -1)
+ return;
if (getrlimit(RLIMIT_STACK, &rlim) == -1)
return;
- mprotect((void *)(uintptr_t)(stacktop - rlim.rlim_cur),
+ mprotect((void *)(uintptr_t)(usrstack - rlim.rlim_cur),
rlim.rlim_cur, _rtld_get_stack_prot());
}
@@ -215,7 +212,7 @@
/*
* Use the garbage collector lock for synchronization of the
- * spare stack lists and allocations from stacktop.
+ * spare stack lists and allocations from usrstack.
*/
THREAD_LIST_WRLOCK(curthread);
/*
@@ -251,11 +248,11 @@
}
else {
/*
- * Allocate a stack from or below stacktop, depending
+ * Allocate a stack from or below usrstack, depending
* on the LIBPTHREAD_BIGSTACK_MAIN env variable.
*/
if (last_stack == NULL)
- last_stack = _stacktop - _thr_stack_initial -
+ last_stack = _usrstack - _thr_stack_initial -
_thr_guard_default;
/* Allocate a new stack. */
Index: sys/amd64/amd64/elf_machdep.c
===================================================================
--- sys/amd64/amd64/elf_machdep.c
+++ sys/amd64/amd64/elf_machdep.c
@@ -75,6 +75,7 @@
.sv_maxuser = VM_MAXUSER_ADDRESS_LA48,
.sv_usrstack = USRSTACK_LA48,
.sv_psstrings = PS_STRINGS_LA48,
+ .sv_psstringssz = sizeof(struct ps_strings),
.sv_stackprot = VM_PROT_ALL,
.sv_copyout_auxargs = __elfN(freebsd_copyout_auxargs),
.sv_copyout_strings = exec_copyout_strings,
@@ -91,7 +92,6 @@
.sv_schedtail = NULL,
.sv_thread_detach = NULL,
.sv_trap = NULL,
- .sv_stackgap = elf64_stackgap,
.sv_onexec_old = exec_onexec_old,
.sv_onexit = exit_onexit,
.sv_set_fork_retval = x86_set_fork_retval,
@@ -117,6 +117,7 @@
.sv_maxuser = VM_MAXUSER_ADDRESS_LA57,
.sv_usrstack = USRSTACK_LA57,
.sv_psstrings = PS_STRINGS_LA57,
+ .sv_psstringssz = sizeof(struct ps_strings),
.sv_stackprot = VM_PROT_ALL,
.sv_copyout_auxargs = __elfN(freebsd_copyout_auxargs),
.sv_copyout_strings = exec_copyout_strings,
@@ -133,7 +134,6 @@
.sv_schedtail = NULL,
.sv_thread_detach = NULL,
.sv_trap = NULL,
- .sv_stackgap = elf64_stackgap,
.sv_onexec_old = exec_onexec_old,
.sv_onexit = exit_onexit,
.sv_set_fork_retval= x86_set_fork_retval,
Index: sys/amd64/ia32/ia32_signal.c
===================================================================
--- sys/amd64/ia32/ia32_signal.c
+++ sys/amd64/ia32/ia32_signal.c
@@ -422,7 +422,7 @@
}
regs->tf_rsp = (uintptr_t)fp;
- regs->tf_rip = p->p_sysent->sv_psstrings -
+ regs->tf_rip = PROC_PS_STRINGS(p) -
(_binary_elf_vdso32_so_1_end - _binary_elf_vdso32_so_1_start) +
VDSO_IA32_OSIGCODE_OFFSET;
regs->tf_rflags &= ~(PSL_T | PSL_D);
Index: sys/amd64/ia32/ia32_syscall.c
===================================================================
--- sys/amd64/ia32/ia32_syscall.c
+++ sys/amd64/ia32/ia32_syscall.c
@@ -270,7 +270,7 @@
bzero(&uap, sizeof(uap));
uap.start = 0;
uap.num = 1;
- lcall_addr = curproc->p_sysent->sv_psstrings -
+ lcall_addr = PROC_PS_STRINGS(curproc) -
(_binary_elf_vdso32_so_1_end - _binary_elf_vdso32_so_1_start) +
VDSO_LCALL_TRAMP_OFFSET;
bzero(&desc, sizeof(desc));
Index: sys/amd64/linux/linux_sysvec.c
===================================================================
--- sys/amd64/linux/linux_sysvec.c
+++ sys/amd64/linux/linux_sysvec.c
@@ -359,7 +359,7 @@
struct proc *p;
p = imgp->proc;
- arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
+ arginfo = (struct ps_strings *)PROC_PS_STRINGS(p);
destp = (uintptr_t)arginfo;
if (imgp->execpath != NULL && imgp->auxargs != NULL) {
@@ -776,6 +776,7 @@
.sv_maxuser = VM_MAXUSER_ADDRESS_LA48,
.sv_usrstack = LINUX_USRSTACK_LA48,
.sv_psstrings = LINUX_PS_STRINGS_LA48,
+ .sv_psstringssz = sizeof(struct ps_strings),
.sv_stackprot = VM_PROT_ALL,
.sv_copyout_auxargs = linux_copyout_auxargs,
.sv_copyout_strings = linux_copyout_strings,
Index: sys/amd64/linux32/linux32_sysvec.c
===================================================================
--- sys/amd64/linux32/linux32_sysvec.c
+++ sys/amd64/linux32/linux32_sysvec.c
@@ -937,6 +937,7 @@
.sv_maxuser = LINUX32_MAXUSER,
.sv_usrstack = LINUX32_USRSTACK,
.sv_psstrings = LINUX32_PS_STRINGS,
+ .sv_psstringssz = sizeof(struct linux32_ps_strings),
.sv_stackprot = VM_PROT_ALL,
.sv_copyout_auxargs = linux_copyout_auxargs,
.sv_copyout_strings = linux_copyout_strings,
Index: sys/arm/arm/elf_machdep.c
===================================================================
--- sys/arm/arm/elf_machdep.c
+++ sys/arm/arm/elf_machdep.c
@@ -81,6 +81,7 @@
.sv_maxuser = VM_MAXUSER_ADDRESS,
.sv_usrstack = USRSTACK,
.sv_psstrings = PS_STRINGS,
+ .sv_psstringssz = sizeof(struct ps_strings),
.sv_stackprot = VM_PROT_ALL,
.sv_copyout_auxargs = __elfN(freebsd_copyout_auxargs),
.sv_copyout_strings = exec_copyout_strings,
Index: sys/arm/arm/exec_machdep.c
===================================================================
--- sys/arm/arm/exec_machdep.c
+++ sys/arm/arm/exec_machdep.c
@@ -340,7 +340,7 @@
if (sysent->sv_sigcode_base != 0)
tf->tf_usr_lr = (register_t)sysent->sv_sigcode_base;
else
- tf->tf_usr_lr = (register_t)(sysent->sv_psstrings -
+ tf->tf_usr_lr = (register_t)(PROC_PS_STRINGS(p) -
*(sysent->sv_szsigcode));
/* Set the mode to enter in the signal handler */
#if __ARM_ARCH >= 7
Index: sys/arm64/arm64/elf32_machdep.c
===================================================================
--- sys/arm64/arm64/elf32_machdep.c
+++ sys/arm64/arm64/elf32_machdep.c
@@ -99,6 +99,7 @@
.sv_maxuser = FREEBSD32_MAXUSER,
.sv_usrstack = FREEBSD32_USRSTACK,
.sv_psstrings = FREEBSD32_PS_STRINGS,
+ .sv_psstringssz = sizeof(struct freebsd32_ps_strings),
.sv_stackprot = VM_PROT_READ | VM_PROT_WRITE,
.sv_copyout_auxargs = elf32_freebsd_copyout_auxargs,
.sv_copyout_strings = freebsd32_copyout_strings,
Index: sys/arm64/arm64/elf_machdep.c
===================================================================
--- sys/arm64/arm64/elf_machdep.c
+++ sys/arm64/arm64/elf_machdep.c
@@ -77,6 +77,7 @@
.sv_maxuser = VM_MAXUSER_ADDRESS,
.sv_usrstack = USRSTACK,
.sv_psstrings = PS_STRINGS,
+ .sv_psstringssz = sizeof(struct ps_strings),
.sv_stackprot = VM_PROT_READ | VM_PROT_WRITE,
.sv_copyout_auxargs = __elfN(freebsd_copyout_auxargs),
.sv_copyout_strings = exec_copyout_strings,
@@ -93,7 +94,6 @@
.sv_schedtail = NULL,
.sv_thread_detach = NULL,
.sv_trap = NULL,
- .sv_stackgap = elf64_stackgap,
.sv_hwcap = &elf_hwcap,
.sv_hwcap2 = &elf_hwcap2,
.sv_onexec_old = exec_onexec_old,
Index: sys/arm64/arm64/freebsd32_machdep.c
===================================================================
--- sys/arm64/arm64/freebsd32_machdep.c
+++ sys/arm64/arm64/freebsd32_machdep.c
@@ -390,7 +390,7 @@
if (sysent->sv_sigcode_base != 0)
tf->tf_x[14] = (register_t)sysent->sv_sigcode_base;
else
- tf->tf_x[14] = (register_t)(sysent->sv_psstrings -
+ tf->tf_x[14] = (register_t)(PROC_PS_STRINGS(p) -
*(sysent->sv_szsigcode));
/* Set the mode to enter in the signal handler */
if ((register_t)catcher & 1)
Index: sys/arm64/linux/linux_sysvec.c
===================================================================
--- sys/arm64/linux/linux_sysvec.c
+++ sys/arm64/linux/linux_sysvec.c
@@ -256,7 +256,7 @@
int argc, envc, error;
p = imgp->proc;
- arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
+ arginfo = (struct ps_strings *)PROC_PS_STRINGS(p);
destp = (uintptr_t)arginfo;
if (imgp->execpath != NULL && imgp->auxargs != NULL) {
@@ -519,6 +519,7 @@
.sv_maxuser = VM_MAXUSER_ADDRESS,
.sv_usrstack = LINUX_USRSTACK,
.sv_psstrings = LINUX_PS_STRINGS,
+ .sv_psstringssz = sizeof(struct ps_strings),
.sv_stackprot = VM_PROT_READ | VM_PROT_WRITE,
.sv_copyout_auxargs = linux_copyout_auxargs,
.sv_copyout_strings = linux_copyout_strings,
Index: sys/compat/freebsd32/freebsd32_misc.c
===================================================================
--- sys/compat/freebsd32/freebsd32_misc.c
+++ sys/compat/freebsd32/freebsd32_misc.c
@@ -3404,7 +3404,7 @@
sysent = imgp->sysent;
- arginfo = (struct freebsd32_ps_strings *)sysent->sv_psstrings;
+ arginfo = (struct freebsd32_ps_strings *)PROC_PS_STRINGS(imgp->proc);
imgp->ps_strings = arginfo;
destp = (uintptr_t)arginfo;
@@ -3464,8 +3464,6 @@
destp = rounddown2(destp, sizeof(uint32_t));
ustringp = destp;
- exec_stackgap(imgp, &destp);
-
if (imgp->auxargs) {
/*
* Allocate room on the stack for the ELF auxargs
Index: sys/compat/ia32/ia32_sysvec.c
===================================================================
--- sys/compat/ia32/ia32_sysvec.c
+++ sys/compat/ia32/ia32_sysvec.c
@@ -121,6 +121,7 @@
.sv_maxuser = FREEBSD32_MAXUSER,
.sv_usrstack = FREEBSD32_USRSTACK,
.sv_psstrings = FREEBSD32_PS_STRINGS,
+ .sv_psstringssz = sizeof(struct freebsd32_ps_strings),
.sv_stackprot = VM_PROT_ALL,
.sv_copyout_auxargs = elf32_freebsd_copyout_auxargs,
.sv_copyout_strings = freebsd32_copyout_strings,
@@ -137,7 +138,6 @@
.sv_schedtail = NULL,
.sv_thread_detach = NULL,
.sv_trap = NULL,
- .sv_stackgap = elf32_stackgap,
.sv_onexec_old = exec_onexec_old,
.sv_onexit = exit_onexit,
.sv_set_fork_retval = x86_set_fork_retval,
Index: sys/i386/i386/elf_machdep.c
===================================================================
--- sys/i386/i386/elf_machdep.c
+++ sys/i386/i386/elf_machdep.c
@@ -70,6 +70,7 @@
.sv_maxuser = VM_MAXUSER_ADDRESS,
.sv_usrstack = USRSTACK,
.sv_psstrings = PS_STRINGS,
+ .sv_psstringssz = sizeof(struct ps_strings),
.sv_stackprot = VM_PROT_ALL,
.sv_copyout_auxargs = __elfN(freebsd_copyout_auxargs),
.sv_copyout_strings = exec_copyout_strings,
Index: sys/i386/i386/exec_machdep.c
===================================================================
--- sys/i386/i386/exec_machdep.c
+++ sys/i386/i386/exec_machdep.c
@@ -238,7 +238,7 @@
szosigcode;
} else {
/* a.out sysentvec does not use shared page */
- regs->tf_eip = p->p_sysent->sv_psstrings - szosigcode;
+ regs->tf_eip = PROC_PS_STRINGS(p) - szosigcode;
}
regs->tf_eflags &= ~(PSL_T | PSL_D);
regs->tf_cs = _ucodesel;
@@ -523,7 +523,7 @@
regs->tf_esp = (int)sfp;
regs->tf_eip = p->p_sysent->sv_sigcode_base;
if (regs->tf_eip == 0)
- regs->tf_eip = p->p_sysent->sv_psstrings - szsigcode;
+ regs->tf_eip = PROC_PS_STRINGS(p) - szsigcode;
regs->tf_eflags &= ~(PSL_T | PSL_D);
regs->tf_cs = _ucodesel;
regs->tf_ds = _udatasel;
Index: sys/i386/linux/imgact_linux.c
===================================================================
--- sys/i386/linux/imgact_linux.c
+++ sys/i386/linux/imgact_linux.c
@@ -213,6 +213,10 @@
vmspace->vm_daddr =
(caddr_t)(void *)(uintptr_t)(virtual_offset + a_out->a_text);
+ error = exec_map_stack(imgp);
+ if (error != 0)
+ goto fail;
+
/* Fill in image_params */
imgp->interpreted = 0;
imgp->entry_addr = a_out->a_entry;
Index: sys/i386/linux/linux_sysvec.c
===================================================================
--- sys/i386/linux/linux_sysvec.c
+++ sys/i386/linux/linux_sysvec.c
@@ -212,7 +212,7 @@
p = imgp->proc;
issetugid = imgp->proc->p_flag & P_SUGID ? 1 : 0;
- arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
+ arginfo = (struct ps_strings *)PROC_PS_STRINGS(p);
args = (Elf32_Auxargs *)imgp->auxargs;
argarray = pos = malloc(LINUX_AT_COUNT * sizeof(*pos), M_TEMP,
M_WAITOK | M_ZERO);
@@ -290,7 +290,7 @@
struct proc *p;
p = imgp->proc;
- arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
+ arginfo = (struct ps_strings *)PROC_PS_STRINGS(p);
destp = (uintptr_t)arginfo;
if (imgp->execpath != NULL && imgp->auxargs != NULL) {
@@ -845,6 +845,7 @@
.sv_maxuser = VM_MAXUSER_ADDRESS,
.sv_usrstack = LINUX_USRSTACK,
.sv_psstrings = PS_STRINGS,
+ .sv_psstringssz = sizeof(struct ps_strings),
.sv_stackprot = VM_PROT_ALL,
.sv_copyout_strings = exec_copyout_strings,
.sv_setregs = linux_exec_setregs,
@@ -885,6 +886,7 @@
.sv_maxuser = VM_MAXUSER_ADDRESS,
.sv_usrstack = LINUX_USRSTACK,
.sv_psstrings = LINUX_PS_STRINGS,
+ .sv_psstringssz = sizeof(struct ps_strings),
.sv_stackprot = VM_PROT_ALL,
.sv_copyout_auxargs = linux_copyout_auxargs,
.sv_copyout_strings = linux_copyout_strings,
Index: sys/kern/imgact_aout.c
===================================================================
--- sys/kern/imgact_aout.c
+++ sys/kern/imgact_aout.c
@@ -89,6 +89,7 @@
.sv_maxuser = AOUT32_USRSTACK,
.sv_usrstack = AOUT32_USRSTACK,
.sv_psstrings = AOUT32_PS_STRINGS,
+ .sv_psstringssz = sizeof(struct ps_strings),
.sv_stackprot = VM_PROT_ALL,
.sv_copyout_strings = exec_copyout_strings,
.sv_setregs = exec_setregs,
@@ -139,6 +140,7 @@
.sv_maxuser = AOUT32_USRSTACK,
.sv_usrstack = AOUT32_USRSTACK,
.sv_psstrings = AOUT32_PS_STRINGS,
+ .sv_psstringssz = sizeof(struct freebsd32_ps_strings),
.sv_stackprot = VM_PROT_ALL,
.sv_copyout_strings = freebsd32_copyout_strings,
.sv_setregs = ia32_setregs,
@@ -348,6 +350,10 @@
vmspace->vm_daddr = (caddr_t) (uintptr_t)
(virtual_offset + a_out->a_text);
+ error = exec_map_stack(imgp);
+ if (error != 0)
+ return (error);
+
/* Fill in image_params */
imgp->interpreted = 0;
imgp->entry_addr = a_out->a_entry;
Index: sys/kern/imgact_elf.c
===================================================================
--- sys/kern/imgact_elf.c
+++ sys/kern/imgact_elf.c
@@ -201,8 +201,24 @@
&__elfN(aslr_honor_sbrk), 0,
__XSTRING(__CONCAT(ELF, __ELF_WORD_SIZE)) ": assume sbrk is used");
-static int __elfN(aslr_stack_gap) = 0;
-SYSCTL_INT(ASLR_NODE_OID, OID_AUTO, stack_gap, CTLFLAG_RW,
+/*
+ * Stack randomization is incompatible with binaries that assume PS_STRINGS is
+ * at a fixed location.
+ */
+#if __ELF_WORD_SIZE == 32
+#define STACK_GAP_DEFAULT 0
+#ifdef COMPAT_43
+#define STACK_GAP_FLAG CTLFLAG_RD
+#else
+#define STACK_GAP_FLAG CTLFLAG_RW
+#endif
+#else
+#define STACK_GAP_DEFAULT 1
+#define STACK_GAP_FLAG CTLFLAG_RW
+#endif
+
+static int __elfN(aslr_stack_gap) = STACK_GAP_DEFAULT;
+SYSCTL_INT(ASLR_NODE_OID, OID_AUTO, stack_gap, STACK_GAP_FLAG,
&__elfN(aslr_stack_gap), 0,
__XSTRING(__CONCAT(ELF, __ELF_WORD_SIZE))
": maximum percentage of main stack to waste on a random gap");
@@ -1309,14 +1325,14 @@
imgp->map_flags |= MAP_WXORX;
error = exec_new_vmspace(imgp, sv);
- vmspace = imgp->proc->p_vmspace;
- map = &vmspace->vm_map;
imgp->proc->p_sysent = sv;
imgp->proc->p_elf_brandinfo = brand_info;
- maxv = vm_map_max(map) - lim_max(td, RLIMIT_STACK);
- if (mapsz >= maxv - vm_map_min(map)) {
+ vmspace = imgp->proc->p_vmspace;
+ map = &vmspace->vm_map;
+ maxv = sv->sv_usrstack;
+ if (error == 0 && mapsz >= maxv - vm_map_min(map)) {
uprintf("Excessive mapping size\n");
error = ENOEXEC;
}
@@ -1342,7 +1358,9 @@
if (error != 0)
goto ret;
- entry = (u_long)hdr->e_entry + et_dyn_addr;
+ error = exec_map_stack(imgp);
+ if (error != 0)
+ goto ret;
/*
* We load the dynamic linker where a userland call
@@ -1364,6 +1382,7 @@
map->anon_loc = addr;
}
+ entry = (u_long)hdr->e_entry + et_dyn_addr;
imgp->entry_addr = entry;
if (interp != NULL) {
@@ -2516,9 +2535,9 @@
KASSERT(*sizep == size, ("invalid size"));
structsize = sizeof(ps_strings);
#if defined(COMPAT_FREEBSD32) && __ELF_WORD_SIZE == 32
- ps_strings = PTROUT(p->p_sysent->sv_psstrings);
+ ps_strings = PTROUT(PROC_PS_STRINGS(p));
#else
- ps_strings = p->p_sysent->sv_psstrings;
+ ps_strings = PROC_PS_STRINGS(p);
#endif
sbuf_bcat(sb, &structsize, sizeof(structsize));
sbuf_bcat(sb, &ps_strings, sizeof(ps_strings));
@@ -2757,22 +2776,3 @@
flags |= PF_W;
return (flags);
}
-
-vm_size_t
-__elfN(stackgap)(struct image_params *imgp, uintptr_t *stack_base)
-{
- uintptr_t range, rbase, gap;
- int pct;
-
- pct = __elfN(aslr_stack_gap);
- if (pct == 0)
- return (0);
- if (pct > 50)
- pct = 50;
- range = imgp->eff_stack_sz * pct / 100;
- arc4rand(&rbase, sizeof(rbase), 0);
- gap = rbase % range;
- gap &= ~(sizeof(u_long) - 1);
- *stack_base -= gap;
- return (gap);
-}
Index: sys/kern/init_main.c
===================================================================
--- sys/kern/init_main.c
+++ sys/kern/init_main.c
@@ -424,6 +424,7 @@
.sv_maxuser = VM_MAXUSER_ADDRESS,
.sv_usrstack = USRSTACK,
.sv_psstrings = PS_STRINGS,
+ .sv_psstringssz = sizeof(struct ps_strings),
.sv_stackprot = VM_PROT_ALL,
.sv_copyout_strings = NULL,
.sv_setregs = NULL,
Index: sys/kern/kern_exec.c
===================================================================
--- sys/kern/kern_exec.c
+++ sys/kern/kern_exec.c
@@ -119,7 +119,6 @@
static int sysctl_kern_ps_strings(SYSCTL_HANDLER_ARGS);
static int sysctl_kern_usrstack(SYSCTL_HANDLER_ARGS);
-static int sysctl_kern_stacktop(SYSCTL_HANDLER_ARGS);
static int sysctl_kern_stackprot(SYSCTL_HANDLER_ARGS);
static int do_execve(struct thread *td, struct image_args *args,
struct mac *mac_p, struct vmspace *oldvmspace);
@@ -134,10 +133,6 @@
CTLFLAG_CAPRD|CTLFLAG_MPSAFE, NULL, 0, sysctl_kern_usrstack, "LU",
"Top of process stack");
-SYSCTL_PROC(_kern, KERN_STACKTOP, stacktop, CTLTYPE_ULONG | CTLFLAG_RD |
- CTLFLAG_CAPRD | CTLFLAG_MPSAFE, NULL, 0, sysctl_kern_stacktop, "LU",
- "Top of process stack with stack gap.");
-
SYSCTL_PROC(_kern, OID_AUTO, stackprot, CTLTYPE_INT|CTLFLAG_RD|CTLFLAG_MPSAFE,
NULL, 0, sysctl_kern_stackprot, "I",
"Stack memory permissions");
@@ -165,62 +160,37 @@
sysctl_kern_ps_strings(SYSCTL_HANDLER_ARGS)
{
struct proc *p;
- int error;
+ vm_offset_t ps_strings;
p = curproc;
#ifdef SCTL_MASK32
if (req->flags & SCTL_MASK32) {
unsigned int val;
- val = (unsigned int)p->p_sysent->sv_psstrings;
- error = SYSCTL_OUT(req, &val, sizeof(val));
- } else
+ val = (unsigned int)PROC_PS_STRINGS(p);
+ return (SYSCTL_OUT(req, &val, sizeof(val)));
+ }
#endif
- error = SYSCTL_OUT(req, &p->p_sysent->sv_psstrings,
- sizeof(p->p_sysent->sv_psstrings));
- return error;
+ ps_strings = PROC_PS_STRINGS(p);
+ return (SYSCTL_OUT(req, &ps_strings, sizeof(ps_strings)));
}
static int
sysctl_kern_usrstack(SYSCTL_HANDLER_ARGS)
{
struct proc *p;
- int error;
-
- p = curproc;
-#ifdef SCTL_MASK32
- if (req->flags & SCTL_MASK32) {
- unsigned int val;
- val = (unsigned int)p->p_sysent->sv_usrstack;
- error = SYSCTL_OUT(req, &val, sizeof(val));
- } else
-#endif
- error = SYSCTL_OUT(req, &p->p_sysent->sv_usrstack,
- sizeof(p->p_sysent->sv_usrstack));
- return (error);
-}
-
-static int
-sysctl_kern_stacktop(SYSCTL_HANDLER_ARGS)
-{
- vm_offset_t stacktop;
- struct proc *p;
- int error;
+ vm_offset_t val;
p = curproc;
#ifdef SCTL_MASK32
if (req->flags & SCTL_MASK32) {
- unsigned int val;
-
- val = (unsigned int)(p->p_sysent->sv_usrstack -
- p->p_vmspace->vm_stkgap);
- error = SYSCTL_OUT(req, &val, sizeof(val));
- } else
-#endif
- {
- stacktop = p->p_sysent->sv_usrstack - p->p_vmspace->vm_stkgap;
- error = SYSCTL_OUT(req, &stacktop, sizeof(stacktop));
+ unsigned int val32;
+ val32 = round_page((unsigned int)PROC_PS_STRINGS(p) +
+ p->p_sysent->sv_psstringssz);
+ return (SYSCTL_OUT(req, &val32, sizeof(val32)));
}
- return (error);
+#endif
+ val = round_page(PROC_PS_STRINGS(p) + p->p_sysent->sv_psstringssz);
+ return (SYSCTL_OUT(req, &val, sizeof(val)));
}
static int
@@ -1136,9 +1106,8 @@
}
/*
- * Destroy old address space, and allocate a new stack.
- * The new stack is only sgrowsiz large because it is grown
- * automatically on a page fault.
+ * Run down the current address space and install a new one. Map the shared
+ * page and compute the new image's stack size.
*/
int
exec_new_vmspace(struct image_params *imgp, struct sysentvec *sv)
@@ -1148,11 +1117,8 @@
struct vmspace *vmspace = p->p_vmspace;
struct thread *td = curthread;
vm_object_t obj;
- struct rlimit rlim_stack;
- vm_offset_t sv_minuser, stack_addr;
+ vm_offset_t sv_minuser;
vm_map_t map;
- vm_prot_t stack_prot;
- u_long ssiz;
imgp->vmspace_destroyed = true;
imgp->sysent = sv;
@@ -1213,7 +1179,28 @@
}
}
- /* Allocate a new stack */
+ return (sv->sv_onexec != NULL ? sv->sv_onexec(p, imgp) : 0);
+}
+
+/*
+ * Compute the stack size limit and map the main process stack.
+ */
+int
+exec_map_stack(struct image_params *imgp)
+{
+ struct rlimit rlim_stack;
+ struct sysentvec *sv;
+ struct proc *p;
+ vm_map_t map;
+ struct vmspace *vmspace;
+ vm_offset_t off, stack_addr, stack_top;
+ u_long ssiz;
+ int error, find_space;
+ vm_prot_t stack_prot;
+
+ p = imgp->proc;
+ sv = p->p_sysent;
+
if (imgp->stack_sz != 0) {
ssiz = trunc_page(imgp->stack_sz);
PROC_LOCK(p);
@@ -1230,30 +1217,49 @@
} else {
ssiz = maxssiz;
}
- imgp->eff_stack_sz = lim_cur(curthread, RLIMIT_STACK);
- if (ssiz < imgp->eff_stack_sz)
- imgp->eff_stack_sz = ssiz;
- stack_addr = sv->sv_usrstack - ssiz;
- stack_prot = obj != NULL && imgp->stack_prot != 0 ?
+
+ vmspace = p->p_vmspace;
+ map = &vmspace->vm_map;
+
+ stack_prot = sv->sv_shared_page_obj != NULL && imgp->stack_prot != 0 ?
imgp->stack_prot : sv->sv_stackprot;
- error = vm_map_stack(map, stack_addr, (vm_size_t)ssiz, stack_prot,
- VM_PROT_ALL, MAP_STACK_GROWS_DOWN);
+ if ((p->p_fctl0 & (NT_FREEBSD_FCTL_ASLR_DISABLE |
+ NT_FREEBSD_FCTL_ASG_DISABLE)) == 0 &&
+ (map->flags & MAP_ASLR) != 0) {
+ stack_addr = round_page((vm_offset_t)p->p_vmspace->vm_daddr +
+ lim_max(curthread, RLIMIT_DATA));
+ find_space = VMFS_ANY_SPACE;
+ } else {
+ stack_addr = sv->sv_usrstack - ssiz;
+ find_space = VMFS_NO_SPACE;
+ }
+ error = vm_map_find(map, NULL, 0, &stack_addr, (vm_size_t)ssiz,
+ sv->sv_usrstack, find_space, stack_prot, VM_PROT_ALL,
+ MAP_STACK_GROWS_DOWN);
if (error != KERN_SUCCESS) {
uprintf("exec_new_vmspace: mapping stack size %#jx prot %#x "
- "failed mach error %d errno %d\n", (uintmax_t)ssiz,
+ "failed, mach error %d errno %d\n", (uintmax_t)ssiz,
stack_prot, error, vm_mmap_to_errno(error));
return (vm_mmap_to_errno(error));
}
- vmspace->vm_stkgap = 0;
+
+ stack_top = stack_addr + ssiz;
+ if (find_space == VMFS_ANY_SPACE) {
+ /* Randomize within the first page of the stack. */
+ arc4rand(&off, sizeof(off), 0);
+ stack_top -= rounddown2(off % PAGE_SIZE, sizeof(void *));
+
+ }
+ p->p_stacktop = stack_top;
/*
* vm_ssize and vm_maxsaddr are somewhat antiquated concepts, but they
* are still used to enforce the stack rlimit on the process stack.
*/
- vmspace->vm_ssize = sgrowsiz >> PAGE_SHIFT;
vmspace->vm_maxsaddr = (char *)stack_addr;
+ vmspace->vm_ssize = sgrowsiz >> PAGE_SHIFT;
- return (sv->sv_onexec != NULL ? sv->sv_onexec(p, imgp) : 0);
+ return (0);
}
/*
@@ -1587,21 +1593,6 @@
return (args->endp);
}
-void
-exec_stackgap(struct image_params *imgp, uintptr_t *dp)
-{
- struct proc *p = imgp->proc;
-
- if (imgp->sysent->sv_stackgap == NULL ||
- (p->p_fctl0 & (NT_FREEBSD_FCTL_ASLR_DISABLE |
- NT_FREEBSD_FCTL_ASG_DISABLE)) != 0 ||
- (imgp->map_flags & MAP_ASLR) == 0) {
- p->p_vmspace->vm_stkgap = 0;
- return;
- }
- p->p_vmspace->vm_stkgap = imgp->sysent->sv_stackgap(imgp, dp);
-}
-
/*
* Copy strings out to the new process address space, constructing new arg
* and env vector tables. Return a pointer to the base so that it can be used
@@ -1624,9 +1615,8 @@
p = imgp->proc;
sysent = p->p_sysent;
- arginfo = (struct ps_strings *)sysent->sv_psstrings;
- destp = (uintptr_t)arginfo;
- imgp->ps_strings = arginfo;
+ destp = PROC_PS_STRINGS(p);
+ arginfo = imgp->ps_strings = (void *)destp;
/*
* Install sigcode.
@@ -1682,8 +1672,6 @@
destp = rounddown2(destp, sizeof(void *));
ustringp = destp;
- exec_stackgap(imgp, &destp);
-
if (imgp->auxargs) {
/*
* Allocate room on the stack for the ELF auxargs
Index: sys/kern/kern_proc.c
===================================================================
--- sys/kern/kern_proc.c
+++ sys/kern/kern_proc.c
@@ -1838,8 +1838,8 @@
int i, error;
error = 0;
- if (proc_readmem(td, p, (vm_offset_t)p->p_sysent->sv_psstrings, &pss,
- sizeof(pss)) != sizeof(pss))
+ if (proc_readmem(td, p, PROC_PS_STRINGS(p), &pss, sizeof(pss)) !=
+ sizeof(pss))
return (ENOMEM);
switch (type) {
case PROC_ARG:
@@ -1914,8 +1914,8 @@
if (SV_PROC_FLAG(p, SV_ILP32) != 0)
return (get_proc_vector32(td, p, proc_vectorp, vsizep, type));
#endif
- if (proc_readmem(td, p, (vm_offset_t)p->p_sysent->sv_psstrings, &pss,
- sizeof(pss)) != sizeof(pss))
+ if (proc_readmem(td, p, PROC_PS_STRINGS(p), &pss, sizeof(pss)) !=
+ sizeof(pss))
return (ENOMEM);
switch (type) {
case PROC_ARG:
@@ -2980,13 +2980,13 @@
* process.
*/
ps_strings32 = SV_PROC_FLAG(p, SV_ILP32) != 0 ?
- PTROUT(p->p_sysent->sv_psstrings) : 0;
+ PTROUT(PROC_PS_STRINGS(p)) : 0;
PROC_UNLOCK(p);
error = SYSCTL_OUT(req, &ps_strings32, sizeof(ps_strings32));
return (error);
}
#endif
- ps_strings = p->p_sysent->sv_psstrings;
+ ps_strings = PROC_PS_STRINGS(p);
PROC_UNLOCK(p);
error = SYSCTL_OUT(req, &ps_strings, sizeof(ps_strings));
return (error);
@@ -3103,9 +3103,9 @@
*sv->sv_szsigcode :
(uintptr_t)sv->sv_szsigcode);
} else {
- kst32.ksigtramp_start = sv->sv_psstrings -
+ kst32.ksigtramp_start = PROC_PS_STRINGS(p) -
*sv->sv_szsigcode;
- kst32.ksigtramp_end = sv->sv_psstrings;
+ kst32.ksigtramp_end = PROC_PS_STRINGS(p);
}
}
PROC_UNLOCK(p);
@@ -3120,9 +3120,9 @@
((sv->sv_flags & SV_DSO_SIG) == 0 ? *sv->sv_szsigcode :
(uintptr_t)sv->sv_szsigcode);
} else {
- kst.ksigtramp_start = (char *)sv->sv_psstrings -
+ kst.ksigtramp_start = (char *)PROC_PS_STRINGS(p) -
*sv->sv_szsigcode;
- kst.ksigtramp_end = (char *)sv->sv_psstrings;
+ kst.ksigtramp_end = (char *)PROC_PS_STRINGS(p);
}
PROC_UNLOCK(p);
error = SYSCTL_OUT(req, &kst, sizeof(kst));
Index: sys/kern/kern_resource.c
===================================================================
--- sys/kern/kern_resource.c
+++ sys/kern/kern_resource.c
@@ -672,9 +672,6 @@
if (limp->rlim_max < 0)
limp->rlim_max = RLIM_INFINITY;
- if (which == RLIMIT_STACK && limp->rlim_cur != RLIM_INFINITY)
- limp->rlim_cur += p->p_vmspace->vm_stkgap;
-
oldssiz.rlim_cur = 0;
newlim = lim_alloc();
PROC_LOCK(p);
Index: sys/kern/kern_thread.c
===================================================================
--- sys/kern/kern_thread.c
+++ sys/kern/kern_thread.c
@@ -101,7 +101,7 @@
"struct proc KBI p_filemon");
_Static_assert(offsetof(struct proc, p_comm) == 0x3e0,
"struct proc KBI p_comm");
-_Static_assert(offsetof(struct proc, p_emuldata) == 0x4c8,
+_Static_assert(offsetof(struct proc, p_emuldata) == 0x4d0,
"struct proc KBI p_emuldata");
#endif
#ifdef __i386__
@@ -121,7 +121,7 @@
"struct proc KBI p_filemon");
_Static_assert(offsetof(struct proc, p_comm) == 0x284,
"struct proc KBI p_comm");
-_Static_assert(offsetof(struct proc, p_emuldata) == 0x310,
+_Static_assert(offsetof(struct proc, p_emuldata) == 0x314,
"struct proc KBI p_emuldata");
#endif
Index: sys/powerpc/powerpc/elf32_machdep.c
===================================================================
--- sys/powerpc/powerpc/elf32_machdep.c
+++ sys/powerpc/powerpc/elf32_machdep.c
@@ -109,6 +109,7 @@
.sv_maxuser = VM_MAXUSER_ADDRESS32,
.sv_usrstack = FREEBSD32_USRSTACK,
.sv_psstrings = FREEBSD32_PS_STRINGS,
+ .sv_psstringssz = sizeof(struct freebsd32_ps_strings),
.sv_copyout_strings = freebsd32_copyout_strings,
.sv_setregs = ppc32_setregs,
.sv_syscallnames = freebsd32_syscallnames,
@@ -117,6 +118,7 @@
.sv_maxuser = VM_MAXUSER_ADDRESS,
.sv_usrstack = USRSTACK,
.sv_psstrings = PS_STRINGS,
+ .sv_psstringssz = sizeof(struct ps_strings),
.sv_copyout_strings = exec_copyout_strings,
.sv_setregs = exec_setregs,
.sv_syscallnames = syscallnames,
Index: sys/powerpc/powerpc/elf64_machdep.c
===================================================================
--- sys/powerpc/powerpc/elf64_machdep.c
+++ sys/powerpc/powerpc/elf64_machdep.c
@@ -78,6 +78,7 @@
.sv_maxuser = VM_MAXUSER_ADDRESS,
.sv_usrstack = USRSTACK,
.sv_psstrings = PS_STRINGS,
+ .sv_psstringssz = sizeof(struct ps_strings),
.sv_stackprot = VM_PROT_ALL,
.sv_copyout_auxargs = __elfN(powerpc_copyout_auxargs),
.sv_copyout_strings = exec_copyout_strings,
@@ -119,6 +120,7 @@
.sv_maxuser = VM_MAXUSER_ADDRESS,
.sv_usrstack = USRSTACK,
.sv_psstrings = PS_STRINGS,
+ .sv_psstringssz = sizeof(struct ps_strings),
.sv_stackprot = VM_PROT_ALL,
.sv_copyout_auxargs = __elfN(powerpc_copyout_auxargs),
.sv_copyout_strings = exec_copyout_strings,
Index: sys/riscv/riscv/elf_machdep.c
===================================================================
--- sys/riscv/riscv/elf_machdep.c
+++ sys/riscv/riscv/elf_machdep.c
@@ -81,6 +81,7 @@
.sv_maxuser = VM_MAXUSER_ADDRESS,
.sv_usrstack = USRSTACK,
.sv_psstrings = PS_STRINGS,
+ .sv_psstringssz = sizeof(struct ps_strings),
.sv_stackprot = VM_PROT_READ | VM_PROT_WRITE,
.sv_copyout_auxargs = __elfN(freebsd_copyout_auxargs),
.sv_copyout_strings = exec_copyout_strings,
Index: sys/riscv/riscv/exec_machdep.c
===================================================================
--- sys/riscv/riscv/exec_machdep.c
+++ sys/riscv/riscv/exec_machdep.c
@@ -409,7 +409,7 @@
if (sysent->sv_sigcode_base != 0)
tf->tf_ra = (register_t)sysent->sv_sigcode_base;
else
- tf->tf_ra = (register_t)(sysent->sv_psstrings -
+ tf->tf_ra = (register_t)(PROC_PS_STRINGS(p) -
*(sysent->sv_szsigcode));
CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_sepc,
Index: sys/sys/exec.h
===================================================================
--- sys/sys/exec.h
+++ sys/sys/exec.h
@@ -87,6 +87,7 @@
* Prefer the kern.ps_strings or kern.proc.ps_strings sysctls to this constant.
*/
#define PS_STRINGS (USRSTACK - sizeof(struct ps_strings))
+#define PROC_PS_STRINGS(p) ((p)->p_stacktop - (p)->p_sysent->sv_psstringssz)
int exec_map_first_page(struct image_params *);
void exec_unmap_first_page(struct image_params *);
Index: sys/sys/imgact.h
===================================================================
--- sys/sys/imgact.h
+++ sys/sys/imgact.h
@@ -83,7 +83,6 @@
int pagesizeslen;
vm_prot_t stack_prot;
u_long stack_sz;
- u_long eff_stack_sz;
struct ucred *newcred; /* new credentials if changing */
#define IMGACT_SHELL 0x1
#define IMGACT_BINMISC 0x2
@@ -114,12 +113,12 @@
void exec_cleanup(struct thread *td, struct vmspace *);
int exec_copyout_strings(struct image_params *, uintptr_t *);
void exec_free_args(struct image_args *);
+int exec_map_stack(struct image_params *);
int exec_new_vmspace(struct image_params *, struct sysentvec *);
void exec_setregs(struct thread *, struct image_params *, uintptr_t);
int exec_shell_imgact(struct image_params *);
int exec_copyin_args(struct image_args *, const char *, enum uio_seg,
char **, char **);
-void exec_stackgap(struct image_params *imgp, uintptr_t *dp);
int pre_execve(struct thread *td, struct vmspace **oldvmspace);
void post_execve(struct thread *td, int error, struct vmspace *oldvmspace);
#endif
Index: sys/sys/imgact_elf.h
===================================================================
--- sys/sys/imgact_elf.h
+++ sys/sys/imgact_elf.h
@@ -118,7 +118,6 @@
int __elfN(freebsd_fixup)(uintptr_t *, struct image_params *);
int __elfN(coredump)(struct thread *, struct vnode *, off_t, int);
size_t __elfN(populate_note)(int, void *, void *, size_t, void **);
-vm_size_t __elfN(stackgap)(struct image_params *, uintptr_t *);
int __elfN(freebsd_copyout_auxargs)(struct image_params *, uintptr_t);
void __elfN(puthdr)(struct thread *, void *, size_t, int, size_t, int);
void __elfN(prepare_notes)(struct thread *, struct note_info_list *,
Index: sys/sys/proc.h
===================================================================
--- sys/sys/proc.h
+++ sys/sys/proc.h
@@ -703,6 +703,7 @@
char p_comm[MAXCOMLEN + 1]; /* (x) Process name. */
struct sysentvec *p_sysent; /* (b) Syscall dispatch info. */
struct pargs *p_args; /* (c) Process arguments. */
+ vm_offset_t p_stacktop; /* (c) Top of the main process stack. */
rlim_t p_cpulimit; /* (c) Current CPU limit in seconds. */
signed char p_nice; /* (c) Process "nice" value. */
int p_fibnum; /* in this routing domain XXX MRT */
Index: sys/sys/sysctl.h
===================================================================
--- sys/sys/sysctl.h
+++ sys/sys/sysctl.h
@@ -976,7 +976,6 @@
#define KERN_HOSTUUID 36 /* string: host UUID identifier */
#define KERN_ARND 37 /* int: from arc4rand() */
#define KERN_MAXPHYS 38 /* int: MAXPHYS value */
-#define KERN_STACKTOP 39 /* int: USRSTACK - stack gap */
/*
* KERN_PROC subtypes
*/
Index: sys/sys/sysent.h
===================================================================
--- sys/sys/sysent.h
+++ sys/sys/sysent.h
@@ -120,7 +120,6 @@
void (*sv_elf_core_prepare_notes)(struct thread *,
struct note_info_list *, size_t *);
int (*sv_imgact_try)(struct image_params *);
- vm_size_t (*sv_stackgap)(struct image_params *, uintptr_t *);
int (*sv_copyout_auxargs)(struct image_params *,
uintptr_t);
int sv_minsigstksz; /* minimum signal stack size */
@@ -128,6 +127,7 @@
vm_offset_t sv_maxuser; /* VM_MAXUSER_ADDRESS */
vm_offset_t sv_usrstack; /* USRSTACK */
vm_offset_t sv_psstrings; /* PS_STRINGS */
+ size_t sv_psstringssz; /* PS_STRINGS size */
int sv_stackprot; /* vm protection for stack */
int (*sv_copyout_strings)(struct image_params *,
uintptr_t *);
Index: sys/vm/vm_map.h
===================================================================
--- sys/vm/vm_map.h
+++ sys/vm/vm_map.h
@@ -293,7 +293,6 @@
caddr_t vm_taddr; /* (c) user virtual address of text */
caddr_t vm_daddr; /* (c) user virtual address of data */
caddr_t vm_maxsaddr; /* user VA at max stack growth */
- vm_size_t vm_stkgap; /* stack gap size in bytes */
u_int vm_refcnt; /* number of references */
/*
* Keep the PMAP last, so that CPU-specific variations of that
Index: sys/vm/vm_map.c
===================================================================
--- sys/vm/vm_map.c
+++ sys/vm/vm_map.c
@@ -343,7 +343,6 @@
vm->vm_taddr = 0;
vm->vm_daddr = 0;
vm->vm_maxsaddr = 0;
- vm->vm_stkgap = 0;
return (vm);
}
@@ -4264,7 +4263,6 @@
vm2->vm_taddr = vm1->vm_taddr;
vm2->vm_daddr = vm1->vm_daddr;
vm2->vm_maxsaddr = vm1->vm_maxsaddr;
- vm2->vm_stkgap = vm1->vm_stkgap;
vm_map_lock(old_map);
if (old_map->busy)
vm_map_wait_busy(old_map);

File Metadata

Mime Type
text/plain
Expires
Wed, Mar 18, 5:26 AM (10 h, 21 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29883686
Default Alt Text
D33704.id101415.diff (36 KB)

Event Timeline