Date: Tue, 10 Sep 2019 06:45:44 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r352117 - in stable/12: lib/libc/sys sys/compat/freebsd32 sys/kern sys/sys sys/vm Message-ID: <201909100645.x8A6jilL060867@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kib Date: Tue Sep 10 06:45:44 2019 New Revision: 352117 URL: https://svnweb.freebsd.org/changeset/base/352117 Log: MFC r351773: Add procctl(PROC_STACKGAP_CTL). PR: 239894 Modified: stable/12/lib/libc/sys/procctl.2 stable/12/sys/compat/freebsd32/freebsd32_misc.c stable/12/sys/kern/kern_exec.c stable/12/sys/kern/kern_fork.c stable/12/sys/kern/kern_procctl.c stable/12/sys/sys/proc.h stable/12/sys/sys/procctl.h stable/12/sys/vm/vm_map.c Directory Properties: stable/12/ (props changed) Modified: stable/12/lib/libc/sys/procctl.2 ============================================================================== --- stable/12/lib/libc/sys/procctl.2 Tue Sep 10 04:21:48 2019 (r352116) +++ stable/12/lib/libc/sys/procctl.2 Tue Sep 10 06:45:44 2019 (r352117) @@ -29,7 +29,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 23, 2019 +.Dd August 31, 2019 .Dt PROCCTL 2 .Os .Sh NAME @@ -462,6 +462,67 @@ must point to a memory location that can hold a value .Vt int . If signal delivery has not been requested, it will contain zero on return. +.It Dv PROC_STACKGAP_CTL +Controls the stack gaps in the specified process. +A stack gap is the part of the growth area for a +.Dv MAP_STACK +mapped region that is reserved and never filled by memory. +Instead, the process is guaranteed to receive a +.Dv SIGSEGV +signal on accessing pages in the gap. +Gaps protect against stack overflow corrupting memory adjacent +to the stack. +.Pp +The +.Fa data +argument must point to an integer variable containing flags. +The following flags are allowed: +.Bl -tag -width PROC_STACKGAP_DISABLE_EXEC +.It Dv PROC_STACKGAP_ENABLE +This flag is only accepted for consistency with +.Dv PROC_STACKGAP_STATUS . +If stack gaps are enabled, the flag is ignored. +If disabled, the flag causes an +.Ev EINVAL +error to be returned. +After gaps are disabled in a process, they can only be re-enabled when an +.Xr execve 2 +is performed. +.It Dv PROC_STACKGAP_DISABLE +Disable stack gaps for the process. +For existing stacks, the gap is no longer a reserved part of the growth +area and can be filled by memory on access. +.It Dv PROC_STACKGAP_ENABLE_EXEC +Enable stack gaps for programs started after an +.Xr execve 2 +by the specified process. +.It Dv PROC_STACKGAP_DISABLE_EXEC +Inherit disabled stack gaps state after +.Xr execve 2 . +In other words, if the currently executing program has stack gaps disabled, +they are kept disabled on exec. +If gaps were enabled, they are kept enabled after exec. +.El +.Pp +The stack gap state is inherited from the parent on +.Xr fork 2 . +.It Dv PROC_STACKGAP_STATUS +Returns the current stack gap state for the specified process. +.Fa data +must point to an integer variable, which is used to return a bitmask +consisting of the following flags: +.Bl -tag -width PROC_STACKGAP_DISABLE_EXEC +.It Dv PROC_STACKGAP_ENABLE +Stack gaps are enabled. +.It Dv PROC_STACKGAP_DISABLE +Stack gaps are disabled. +.It Dv PROC_STACKGAP_ENABLE_EXEC +Stack gaps are enabled in the process after +.Xr execve 2 . +.It Dv PROC_STACKGAP_DISABLE_EXEC +Stack gaps are disabled in the process after +.Xr execve 2 . +.El .El .Sh NOTES Disabling tracing on a process should not be considered a security Modified: stable/12/sys/compat/freebsd32/freebsd32_misc.c ============================================================================== --- stable/12/sys/compat/freebsd32/freebsd32_misc.c Tue Sep 10 04:21:48 2019 (r352116) +++ stable/12/sys/compat/freebsd32/freebsd32_misc.c Tue Sep 10 06:45:44 2019 (r352117) @@ -3360,6 +3360,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_ switch (uap->com) { case PROC_ASLR_CTL: case PROC_SPROTECT: + case PROC_STACKGAP_CTL: case PROC_TRACE_CTL: case PROC_TRAPCAP_CTL: error = copyin(PTRIN(uap->data), &flags, sizeof(flags)); @@ -3391,6 +3392,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_ data = &x.rk; break; case PROC_ASLR_STATUS: + case PROC_STACKGAP_STATUS: case PROC_TRACE_STATUS: case PROC_TRAPCAP_STATUS: data = &flags; @@ -3420,6 +3422,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_ error = error1; break; case PROC_ASLR_STATUS: + case PROC_STACKGAP_STATUS: case PROC_TRACE_STATUS: case PROC_TRAPCAP_STATUS: if (error == 0) Modified: stable/12/sys/kern/kern_exec.c ============================================================================== --- stable/12/sys/kern/kern_exec.c Tue Sep 10 04:21:48 2019 (r352116) +++ stable/12/sys/kern/kern_exec.c Tue Sep 10 06:45:44 2019 (r352117) @@ -756,6 +756,8 @@ interpret: p->p_flag |= P_EXEC; if ((p->p_flag2 & P2_NOTRACE_EXEC) == 0) p->p_flag2 &= ~P2_NOTRACE; + if ((p->p_flag2 & P2_STKGAP_DISABLE_EXEC) == 0) + p->p_flag2 &= ~P2_STKGAP_DISABLE; if (p->p_flag & P_PPWAIT) { p->p_flag &= ~(P_PPWAIT | P_PPTRACE); cv_broadcast(&p->p_pwait); Modified: stable/12/sys/kern/kern_fork.c ============================================================================== --- stable/12/sys/kern/kern_fork.c Tue Sep 10 04:21:48 2019 (r352116) +++ stable/12/sys/kern/kern_fork.c Tue Sep 10 06:45:44 2019 (r352117) @@ -508,7 +508,9 @@ do_fork(struct thread *td, struct fork_req *fr, struct */ p2->p_flag = P_INMEM; p2->p_flag2 = p1->p_flag2 & (P2_ASLR_DISABLE | P2_ASLR_ENABLE | - P2_ASLR_IGNSTART | P2_NOTRACE | P2_NOTRACE_EXEC | P2_TRAPCAP); + P2_ASLR_IGNSTART | P2_NOTRACE | P2_NOTRACE_EXEC | + P2_TRAPCAP | + P2_STKGAP_DISABLE | P2_STKGAP_DISABLE_EXEC); p2->p_swtick = ticks; if (p1->p_flag & P_PROFIL) startprofclock(p2); Modified: stable/12/sys/kern/kern_procctl.c ============================================================================== --- stable/12/sys/kern/kern_procctl.c Tue Sep 10 04:21:48 2019 (r352116) +++ stable/12/sys/kern/kern_procctl.c Tue Sep 10 06:45:44 2019 (r352117) @@ -474,6 +474,55 @@ aslr_status(struct thread *td, struct proc *p, int *da return (0); } +static int +stackgap_ctl(struct thread *td, struct proc *p, int state) +{ + PROC_LOCK_ASSERT(p, MA_OWNED); + + if ((state & ~(PROC_STACKGAP_ENABLE | PROC_STACKGAP_DISABLE | + PROC_STACKGAP_ENABLE_EXEC | PROC_STACKGAP_DISABLE_EXEC)) != 0) + return (EINVAL); + switch (state & (PROC_STACKGAP_ENABLE | PROC_STACKGAP_DISABLE)) { + case PROC_STACKGAP_ENABLE: + if ((p->p_flag2 & P2_STKGAP_DISABLE) != 0) + return (EINVAL); + break; + case PROC_STACKGAP_DISABLE: + p->p_flag2 |= P2_STKGAP_DISABLE; + break; + case 0: + break; + default: + return (EINVAL); + } + switch (state & (PROC_STACKGAP_ENABLE_EXEC | + PROC_STACKGAP_DISABLE_EXEC)) { + case PROC_STACKGAP_ENABLE_EXEC: + p->p_flag2 &= ~P2_STKGAP_DISABLE_EXEC; + break; + case PROC_STACKGAP_DISABLE_EXEC: + p->p_flag2 |= P2_STKGAP_DISABLE_EXEC; + break; + case 0: + break; + default: + return (EINVAL); + } + return (0); +} + +static int +stackgap_status(struct thread *td, struct proc *p, int *data) +{ + PROC_LOCK_ASSERT(p, MA_OWNED); + + *data = (p->p_flag2 & P2_STKGAP_DISABLE) != 0 ? PROC_STACKGAP_DISABLE : + PROC_STACKGAP_ENABLE; + *data |= (p->p_flag2 & P2_STKGAP_DISABLE_EXEC) != 0 ? + PROC_STACKGAP_DISABLE_EXEC : PROC_STACKGAP_ENABLE_EXEC; + return (0); +} + #ifndef _SYS_SYSPROTO_H_ struct procctl_args { idtype_t idtype; @@ -501,6 +550,7 @@ sys_procctl(struct thread *td, struct procctl_args *ua switch (uap->com) { case PROC_ASLR_CTL: case PROC_SPROTECT: + case PROC_STACKGAP_CTL: case PROC_TRACE_CTL: case PROC_TRAPCAP_CTL: error = copyin(uap->data, &flags, sizeof(flags)); @@ -530,6 +580,7 @@ sys_procctl(struct thread *td, struct procctl_args *ua data = &x.rk; break; case PROC_ASLR_STATUS: + case PROC_STACKGAP_STATUS: case PROC_TRACE_STATUS: case PROC_TRAPCAP_STATUS: data = &flags; @@ -558,6 +609,7 @@ sys_procctl(struct thread *td, struct procctl_args *ua error = error1; break; case PROC_ASLR_STATUS: + case PROC_STACKGAP_STATUS: case PROC_TRACE_STATUS: case PROC_TRAPCAP_STATUS: if (error == 0) @@ -583,6 +635,10 @@ kern_procctl_single(struct thread *td, struct proc *p, return (aslr_status(td, p, data)); case PROC_SPROTECT: return (protect_set(td, p, *(int *)data)); + case PROC_STACKGAP_CTL: + return (stackgap_ctl(td, p, *(int *)data)); + case PROC_STACKGAP_STATUS: + return (stackgap_status(td, p, data)); case PROC_REAP_ACQUIRE: return (reap_acquire(td, p)); case PROC_REAP_RELEASE: @@ -623,6 +679,8 @@ kern_procctl(struct thread *td, idtype_t idtype, id_t case PROC_REAP_STATUS: case PROC_REAP_GETPIDS: case PROC_REAP_KILL: + case PROC_STACKGAP_CTL: + case PROC_STACKGAP_STATUS: case PROC_TRACE_STATUS: case PROC_TRAPCAP_STATUS: case PROC_PDEATHSIG_CTL: @@ -669,6 +727,8 @@ kern_procctl(struct thread *td, idtype_t idtype, id_t break; case PROC_ASLR_CTL: case PROC_ASLR_STATUS: + case PROC_STACKGAP_CTL: + case PROC_STACKGAP_STATUS: case PROC_TRACE_STATUS: case PROC_TRAPCAP_STATUS: tree_locked = false; Modified: stable/12/sys/sys/proc.h ============================================================================== --- stable/12/sys/sys/proc.h Tue Sep 10 04:21:48 2019 (r352116) +++ stable/12/sys/sys/proc.h Tue Sep 10 06:45:44 2019 (r352117) @@ -763,6 +763,8 @@ struct proc { #define P2_ASLR_ENABLE 0x00000040 /* Force enable ASLR. */ #define P2_ASLR_DISABLE 0x00000080 /* Force disable ASLR. */ #define P2_ASLR_IGNSTART 0x00000100 /* Enable ASLR to consume sbrk area. */ +#define P2_STKGAP_DISABLE 0x00000800 /* Disable stack gap for MAP_STACK */ +#define P2_STKGAP_DISABLE_EXEC 0x00001000 /* Stack gap disabled after exec */ /* Flags protected by proctree_lock, kept in p_treeflags. */ #define P_TREE_ORPHANED 0x00000001 /* Reparented, on orphan list */ Modified: stable/12/sys/sys/procctl.h ============================================================================== --- stable/12/sys/sys/procctl.h Tue Sep 10 04:21:48 2019 (r352116) +++ stable/12/sys/sys/procctl.h Tue Sep 10 06:45:44 2019 (r352117) @@ -59,6 +59,8 @@ #define PROC_PDEATHSIG_STATUS 12 /* get parent death signal */ #define PROC_ASLR_CTL 13 /* en/dis ASLR */ #define PROC_ASLR_STATUS 14 /* query ASLR status */ +#define PROC_STACKGAP_CTL 17 /* en/dis stack gap on MAP_STACK */ +#define PROC_STACKGAP_STATUS 18 /* query stack gap */ /* Operations for PROC_SPROTECT (passed in integer arg). */ #define PPROT_OP(x) ((x) & 0xf) @@ -126,6 +128,11 @@ struct procctl_reaper_kill { #define PROC_ASLR_FORCE_DISABLE 2 #define PROC_ASLR_NOFORCE 3 #define PROC_ASLR_ACTIVE 0x80000000 + +#define PROC_STACKGAP_ENABLE 0x0001 +#define PROC_STACKGAP_DISABLE 0x0002 +#define PROC_STACKGAP_ENABLE_EXEC 0x0004 +#define PROC_STACKGAP_DISABLE_EXEC 0x0008 #ifndef _KERNEL __BEGIN_DECLS Modified: stable/12/sys/vm/vm_map.c ============================================================================== --- stable/12/sys/vm/vm_map.c Tue Sep 10 04:21:48 2019 (r352116) +++ stable/12/sys/vm/vm_map.c Tue Sep 10 06:45:44 2019 (r352117) @@ -4102,7 +4102,8 @@ vm_map_stack_locked(vm_map_t map, vm_offset_t addrbos, addrbos + max_ssize > vm_map_max(map) || addrbos + max_ssize <= addrbos) return (KERN_INVALID_ADDRESS); - sgp = (vm_size_t)stack_guard_page * PAGE_SIZE; + sgp = (curproc->p_flag2 & P2_STKGAP_DISABLE) != 0 ? 0 : + (vm_size_t)stack_guard_page * PAGE_SIZE; if (sgp >= max_ssize) return (KERN_INVALID_ARGUMENT); @@ -4153,6 +4154,8 @@ vm_map_stack_locked(vm_map_t map, vm_offset_t addrbos, KASSERT((orient & MAP_STACK_GROWS_UP) == 0 || (new_entry->eflags & MAP_ENTRY_GROWS_UP) != 0, ("new entry lacks MAP_ENTRY_GROWS_UP")); + if (gap_bot == gap_top) + return (KERN_SUCCESS); rv = vm_map_insert(map, NULL, 0, gap_bot, gap_top, VM_PROT_NONE, VM_PROT_NONE, MAP_CREATE_GUARD | (orient == MAP_STACK_GROWS_DOWN ? MAP_CREATE_STACK_GAP_DN : MAP_CREATE_STACK_GAP_UP)); @@ -4236,7 +4239,8 @@ retry: } else { return (KERN_FAILURE); } - guard = gap_entry->next_read; + guard = (curproc->p_flag2 & P2_STKGAP_DISABLE) != 0 ? 0 : + gap_entry->next_read; max_grow = gap_entry->end - gap_entry->start; if (guard > max_grow) return (KERN_NO_SPACE);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201909100645.x8A6jilL060867>