Skip site navigation (1)Skip section navigation (2)
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>