svn commit: r352125 - in stable/11: lib/libc/sys sys/compat/freebsd32 sys/kern sys/sys sys/vm
Konstantin Belousov
kib at FreeBSD.org
Tue Sep 10 07:29:24 UTC 2019
Author: kib
Date: Tue Sep 10 07:29:21 2019
New Revision: 352125
URL: https://svnweb.freebsd.org/changeset/base/352125
Log:
MFC r351773:
Add procctl(PROC_STACKGAP_CTL).
PR: 239894
Modified:
stable/11/lib/libc/sys/procctl.2
stable/11/sys/compat/freebsd32/freebsd32_misc.c
stable/11/sys/kern/kern_exec.c
stable/11/sys/kern/kern_fork.c
stable/11/sys/kern/kern_procctl.c
stable/11/sys/sys/proc.h
stable/11/sys/sys/procctl.h
stable/11/sys/vm/vm_map.c
Directory Properties:
stable/11/ (props changed)
Modified: stable/11/lib/libc/sys/procctl.2
==============================================================================
--- stable/11/lib/libc/sys/procctl.2 Tue Sep 10 07:28:27 2019 (r352124)
+++ stable/11/lib/libc/sys/procctl.2 Tue Sep 10 07:29:21 2019 (r352125)
@@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd February 23, 2019
+.Dd August 31, 2019
.Dt PROCCTL 2
.Os
.Sh NAME
@@ -422,6 +422,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/11/sys/compat/freebsd32/freebsd32_misc.c
==============================================================================
--- stable/11/sys/compat/freebsd32/freebsd32_misc.c Tue Sep 10 07:28:27 2019 (r352124)
+++ stable/11/sys/compat/freebsd32/freebsd32_misc.c Tue Sep 10 07:29:21 2019 (r352125)
@@ -3107,6 +3107,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_
switch (uap->com) {
case PROC_SPROTECT:
+ case PROC_STACKGAP_CTL:
case PROC_TRACE_CTL:
case PROC_TRAPCAP_CTL:
error = copyin(PTRIN(uap->data), &flags, sizeof(flags));
@@ -3137,6 +3138,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_
return (error);
data = &x.rk;
break;
+ case PROC_STACKGAP_STATUS:
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
data = &flags;
@@ -3165,6 +3167,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_
if (error == 0)
error = error1;
break;
+ case PROC_STACKGAP_STATUS:
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
if (error == 0)
Modified: stable/11/sys/kern/kern_exec.c
==============================================================================
--- stable/11/sys/kern/kern_exec.c Tue Sep 10 07:28:27 2019 (r352124)
+++ stable/11/sys/kern/kern_exec.c Tue Sep 10 07:29:21 2019 (r352125)
@@ -762,6 +762,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/11/sys/kern/kern_fork.c
==============================================================================
--- stable/11/sys/kern/kern_fork.c Tue Sep 10 07:28:27 2019 (r352124)
+++ stable/11/sys/kern/kern_fork.c Tue Sep 10 07:29:21 2019 (r352125)
@@ -513,7 +513,8 @@ do_fork(struct thread *td, struct fork_req *fr, struct
* Increase reference counts on shared objects.
*/
p2->p_flag = P_INMEM;
- p2->p_flag2 = p1->p_flag2 & (P2_NOTRACE | P2_NOTRACE_EXEC | P2_TRAPCAP);
+ p2->p_flag2 = p1->p_flag2 & (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/11/sys/kern/kern_procctl.c
==============================================================================
--- stable/11/sys/kern/kern_procctl.c Tue Sep 10 07:28:27 2019 (r352124)
+++ stable/11/sys/kern/kern_procctl.c Tue Sep 10 07:29:21 2019 (r352125)
@@ -413,6 +413,55 @@ trapcap_status(struct thread *td, struct proc *p, int
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;
@@ -435,6 +484,7 @@ sys_procctl(struct thread *td, struct procctl_args *ua
switch (uap->com) {
case PROC_SPROTECT:
+ case PROC_STACKGAP_CTL:
case PROC_TRACE_CTL:
case PROC_TRAPCAP_CTL:
error = copyin(uap->data, &flags, sizeof(flags));
@@ -463,6 +513,7 @@ sys_procctl(struct thread *td, struct procctl_args *ua
return (error);
data = &x.rk;
break;
+ case PROC_STACKGAP_STATUS:
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
data = &flags;
@@ -490,6 +541,7 @@ sys_procctl(struct thread *td, struct procctl_args *ua
if (error == 0)
error = error1;
break;
+ case PROC_STACKGAP_STATUS:
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
if (error == 0)
@@ -511,6 +563,10 @@ kern_procctl_single(struct thread *td, struct proc *p,
switch (com) {
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:
@@ -549,6 +605,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:
@@ -593,6 +651,8 @@ kern_procctl(struct thread *td, idtype_t idtype, id_t
sx_xlock(&proctree_lock);
tree_locked = true;
break;
+ case PROC_STACKGAP_CTL:
+ case PROC_STACKGAP_STATUS:
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
tree_locked = false;
Modified: stable/11/sys/sys/proc.h
==============================================================================
--- stable/11/sys/sys/proc.h Tue Sep 10 07:28:27 2019 (r352124)
+++ stable/11/sys/sys/proc.h Tue Sep 10 07:29:21 2019 (r352125)
@@ -745,6 +745,8 @@ struct proc {
#define P2_AST_SU 0x00000008 /* Handles SU ast for kthreads. */
#define P2_PTRACE_FSTP 0x00000010 /* SIGSTOP from PT_ATTACH not yet handled. */
#define P2_TRAPCAP 0x00000020 /* SIGTRAP on ENOTCAPABLE */
+#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/11/sys/sys/procctl.h
==============================================================================
--- stable/11/sys/sys/procctl.h Tue Sep 10 07:28:27 2019 (r352124)
+++ stable/11/sys/sys/procctl.h Tue Sep 10 07:29:21 2019 (r352125)
@@ -51,6 +51,8 @@
#define PROC_TRAPCAP_STATUS 10 /* query trap capability status */
#define PROC_PDEATHSIG_CTL 11 /* set parent death signal */
#define PROC_PDEATHSIG_STATUS 12 /* get parent death signal */
+#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)
@@ -113,6 +115,11 @@ struct procctl_reaper_kill {
#define PROC_TRAPCAP_CTL_ENABLE 1
#define PROC_TRAPCAP_CTL_DISABLE 2
+
+#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/11/sys/vm/vm_map.c
==============================================================================
--- stable/11/sys/vm/vm_map.c Tue Sep 10 07:28:27 2019 (r352124)
+++ stable/11/sys/vm/vm_map.c Tue Sep 10 07:29:21 2019 (r352125)
@@ -3632,7 +3632,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);
@@ -3683,6 +3684,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));
@@ -3766,7 +3769,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);
More information about the svn-src-stable
mailing list