Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 2 Jul 2019 19:07:18 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r349609 - in head: lib/libc/sys sys/compat/freebsd32 sys/kern sys/sys sys/vm
Message-ID:  <201907021907.x62J7IdO092798@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Tue Jul  2 19:07:17 2019
New Revision: 349609
URL: https://svnweb.freebsd.org/changeset/base/349609

Log:
  Control implicit PROT_MAX() using procctl(2) and the FreeBSD note
  feature bit.
  
  In particular, allocate the bit to opt-out the image from implicit
  PROTMAX enablement.  Provide procctl(2) verbs to set and query
  implicit PROTMAX handling.  The knobs mimic the same per-image flag
  and per-process controls for ASLR.
  
  Reviewed by:	emaste, markj (previous version)
  Discussed with:	brooks
  Sponsored by:	The FreeBSD Foundation
  Differential revision:	https://reviews.freebsd.org/D20795

Modified:
  head/lib/libc/sys/procctl.2
  head/sys/compat/freebsd32/freebsd32_misc.c
  head/sys/kern/kern_procctl.c
  head/sys/sys/elf_common.h
  head/sys/sys/proc.h
  head/sys/sys/procctl.h
  head/sys/sys/syscallsubr.h
  head/sys/vm/vm_mmap.c

Modified: head/lib/libc/sys/procctl.2
==============================================================================
--- head/lib/libc/sys/procctl.2	Tue Jul  2 19:01:14 2019	(r349608)
+++ head/lib/libc/sys/procctl.2	Tue Jul  2 19:07:17 2019	(r349609)
@@ -94,7 +94,7 @@ Same notes as for
 .Dv PROC_ASLR_FORCE_ENABLE
 apply.
 .It Dv PROC_ASLR_NOFORCE
-Use system-wide configured policy for ASLR.
+Use the system-wide configured policy for ASLR.
 .El
 .It Dv PROC_ASLR_STATUS
 Returns the current status of ASLR enablement for the target process.
@@ -112,6 +112,47 @@ If the currently executed image in the process itself 
 the
 .Dv PROC_ASLR_ACTIVE
 flag is or-ed with the value listed above.
+.It Dv PROC_PROTMAX_CTL
+Controls implicit application of PROT_MAX protection equal to the
+.Fa prot
+argument of the
+.Xr mmap 2
+syscall, in the target process.
+The
+.Va arg
+parameter must point to the integer variable holding one of the following
+values:
+.Bl -tag -width PROC_PROTMAX_FORCE_DISABLE
+.It Dv PROC_PROTMAX_FORCE_ENABLE
+Enables implicit PROT_MAX application,
+even if it is disabled system-wide by the sysctl
+.Va vm.imply_prot_max .
+The image flag might still prevent the enablement.
+.It Dv PROC_ASLR_FORCE_DISABLE
+Request that implicit application of PROT_MAX be disabled.
+Same notes as for
+.Dv PROC_PROTMAX_FORCE_ENABLE
+apply.
+.It Dv PROC_PROTMAX_NOFORCE
+Use the system-wide configured policy for PROT_MAX.
+.El
+.It Dv PROC_PROTMAX_STATUS
+Returns the current status of implicit PROT_MAX enablement for the
+target process.
+The
+.Va arg
+parameter must point to the integer variable, where one of the
+following values is written:
+.Bl -tag -width PROC_PROTMAX_FORCE_DISABLE
+.It Dv PROC_PROTMAX_FORCE_ENABLE
+.It Dv PROC_PROTMAX_FORCE_DISABLE
+.It Dv PROC_PROTMAX_NOFORCE
+.El
+.Pp
+If the currently executed image in the process itself has implicit PROT_MAX
+application enabled, the
+.Dv PROC_PROTMAX_ACTIVE
+flag is or-ed with the value listed above.
 .It Dv PROC_SPROTECT
 Set process protection state.
 This is used to mark a process as protected from being killed if the system
@@ -575,6 +616,8 @@ or invalid signal number.
 .Xr cap_enter 2,
 .Xr kill 2 ,
 .Xr ktrace 2 ,
+.Xr mmap 2 ,
+.Xr mprotect 2 ,
 .Xr ptrace 2 ,
 .Xr wait 2 ,
 .Xr capsicum 4 ,

Modified: head/sys/compat/freebsd32/freebsd32_misc.c
==============================================================================
--- head/sys/compat/freebsd32/freebsd32_misc.c	Tue Jul  2 19:01:14 2019	(r349608)
+++ head/sys/compat/freebsd32/freebsd32_misc.c	Tue Jul  2 19:07:17 2019	(r349609)
@@ -3333,6 +3333,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_
 
 	switch (uap->com) {
 	case PROC_ASLR_CTL:
+	case PROC_PROTMAX_CTL:
 	case PROC_SPROTECT:
 	case PROC_TRACE_CTL:
 	case PROC_TRAPCAP_CTL:
@@ -3365,6 +3366,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_
 		data = &x.rk;
 		break;
 	case PROC_ASLR_STATUS:
+	case PROC_PROTMAX_STATUS:
 	case PROC_TRACE_STATUS:
 	case PROC_TRAPCAP_STATUS:
 		data = &flags;
@@ -3394,6 +3396,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_
 			error = error1;
 		break;
 	case PROC_ASLR_STATUS:
+	case PROC_PROTMAX_STATUS:
 	case PROC_TRACE_STATUS:
 	case PROC_TRAPCAP_STATUS:
 		if (error == 0)

Modified: head/sys/kern/kern_procctl.c
==============================================================================
--- head/sys/kern/kern_procctl.c	Tue Jul  2 19:01:14 2019	(r349608)
+++ head/sys/kern/kern_procctl.c	Tue Jul  2 19:07:17 2019	(r349609)
@@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/systm.h>
 #include <sys/capsicum.h>
 #include <sys/lock.h>
+#include <sys/mman.h>
 #include <sys/mutex.h>
 #include <sys/priv.h>
 #include <sys/proc.h>
@@ -419,6 +420,51 @@ trapcap_status(struct thread *td, struct proc *p, int 
 }
 
 static int
+protmax_ctl(struct thread *td, struct proc *p, int state)
+{
+	PROC_LOCK_ASSERT(p, MA_OWNED);
+
+	switch (state) {
+	case PROC_PROTMAX_FORCE_ENABLE:
+		p->p_flag2 &= ~P2_PROTMAX_DISABLE;
+		p->p_flag2 |= P2_PROTMAX_ENABLE;
+		break;
+	case PROC_PROTMAX_FORCE_DISABLE:
+		p->p_flag2 |= P2_PROTMAX_DISABLE;
+		p->p_flag2 &= ~P2_PROTMAX_ENABLE;
+		break;
+	case PROC_PROTMAX_NOFORCE:
+		p->p_flag2 &= ~(P2_PROTMAX_ENABLE | P2_PROTMAX_DISABLE);
+		break;
+	default:
+		return (EINVAL);
+	}
+	return (0);
+}
+
+static int
+protmax_status(struct thread *td, struct proc *p, int *data)
+{
+	int d;
+
+	switch (p->p_flag2 & (P2_PROTMAX_ENABLE | P2_PROTMAX_DISABLE)) {
+	case 0:
+		d = PROC_ASLR_NOFORCE;
+		break;
+	case P2_PROTMAX_ENABLE:
+		d = PROC_PROTMAX_FORCE_ENABLE;
+		break;
+	case P2_PROTMAX_DISABLE:
+		d = PROC_PROTMAX_FORCE_DISABLE;
+		break;
+	}
+	if (kern_mmap_maxprot(p, PROT_READ) == PROT_READ)
+		d |= PROC_PROTMAX_ACTIVE;
+	*data = d;
+	return (0);
+}
+
+static int
 aslr_ctl(struct thread *td, struct proc *p, int state)
 {
 
@@ -500,6 +546,7 @@ sys_procctl(struct thread *td, struct procctl_args *ua
 
 	switch (uap->com) {
 	case PROC_ASLR_CTL:
+	case PROC_PROTMAX_CTL:
 	case PROC_SPROTECT:
 	case PROC_TRACE_CTL:
 	case PROC_TRAPCAP_CTL:
@@ -530,6 +577,7 @@ sys_procctl(struct thread *td, struct procctl_args *ua
 		data = &x.rk;
 		break;
 	case PROC_ASLR_STATUS:
+	case PROC_PROTMAX_STATUS:
 	case PROC_TRACE_STATUS:
 	case PROC_TRAPCAP_STATUS:
 		data = &flags;
@@ -558,6 +606,7 @@ sys_procctl(struct thread *td, struct procctl_args *ua
 			error = error1;
 		break;
 	case PROC_ASLR_STATUS:
+	case PROC_PROTMAX_STATUS:
 	case PROC_TRACE_STATUS:
 	case PROC_TRAPCAP_STATUS:
 		if (error == 0)
@@ -583,6 +632,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_PROTMAX_CTL:
+		return (protmax_ctl(td, p, *(int *)data));
+	case PROC_PROTMAX_STATUS:
+		return (protmax_status(td, p, data));
 	case PROC_REAP_ACQUIRE:
 		return (reap_acquire(td, p));
 	case PROC_REAP_RELEASE:
@@ -618,6 +671,8 @@ kern_procctl(struct thread *td, idtype_t idtype, id_t 
 	switch (com) {
 	case PROC_ASLR_CTL:
 	case PROC_ASLR_STATUS:
+	case PROC_PROTMAX_CTL:
+	case PROC_PROTMAX_STATUS:
 	case PROC_REAP_ACQUIRE:
 	case PROC_REAP_RELEASE:
 	case PROC_REAP_STATUS:
@@ -669,6 +724,8 @@ kern_procctl(struct thread *td, idtype_t idtype, id_t 
 		break;
 	case PROC_ASLR_CTL:
 	case PROC_ASLR_STATUS:
+	case PROC_PROTMAX_CTL:
+	case PROC_PROTMAX_STATUS:
 	case PROC_TRACE_STATUS:
 	case PROC_TRAPCAP_STATUS:
 		tree_locked = false;

Modified: head/sys/sys/elf_common.h
==============================================================================
--- head/sys/sys/elf_common.h	Tue Jul  2 19:01:14 2019	(r349608)
+++ head/sys/sys/elf_common.h	Tue Jul  2 19:07:17 2019	(r349609)
@@ -777,6 +777,7 @@ typedef struct {
 
 /* NT_FREEBSD_FEATURE_CTL desc[0] bits */
 #define	NT_FREEBSD_FCTL_ASLR_DISABLE	0x00000001
+#define	NT_FREEBSD_FCTL_PROTMAX_DISABLE	0x00000002
 
 /* Values for n_type.  Used in core files. */
 #define	NT_PRSTATUS	1	/* Process status. */

Modified: head/sys/sys/proc.h
==============================================================================
--- head/sys/sys/proc.h	Tue Jul  2 19:01:14 2019	(r349608)
+++ head/sys/sys/proc.h	Tue Jul  2 19:07:17 2019	(r349609)
@@ -761,6 +761,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_PROTMAX_ENABLE 0x00000200	/* Force enable implied PROT_MAX. */
+#define	P2_PROTMAX_DISABLE 0x00000400	/* Force disable implied PROT_MAX. */
 
 /* Flags protected by proctree_lock, kept in p_treeflags. */
 #define	P_TREE_ORPHANED		0x00000001	/* Reparented, on orphan list */

Modified: head/sys/sys/procctl.h
==============================================================================
--- head/sys/sys/procctl.h	Tue Jul  2 19:01:14 2019	(r349608)
+++ head/sys/sys/procctl.h	Tue Jul  2 19:07:17 2019	(r349609)
@@ -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_PROTMAX_CTL	15	/* en/dis implicit PROT_MAX */
+#define	PROC_PROTMAX_STATUS	16	/* query implicit PROT_MAX status */
 
 /* 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_PROTMAX_FORCE_ENABLE	1
+#define	PROC_PROTMAX_FORCE_DISABLE	2
+#define	PROC_PROTMAX_NOFORCE		3
+#define	PROC_PROTMAX_ACTIVE		0x80000000
 
 #ifndef _KERNEL
 __BEGIN_DECLS

Modified: head/sys/sys/syscallsubr.h
==============================================================================
--- head/sys/sys/syscallsubr.h	Tue Jul  2 19:01:14 2019	(r349608)
+++ head/sys/sys/syscallsubr.h	Tue Jul  2 19:07:17 2019	(r349609)
@@ -175,6 +175,7 @@ int	kern_mlock(struct proc *proc, struct ucred *cred, 
 	    size_t len);
 int	kern_mmap(struct thread *td, uintptr_t addr, size_t len, int prot,
 	    int flags, int fd, off_t pos);
+int	kern_mmap_maxprot(struct proc *p, int prot);
 int	kern_mprotect(struct thread *td, uintptr_t addr, size_t size, int prot);
 int	kern_msgctl(struct thread *, int, int, struct msqid_ds *);
 int	kern_msgrcv(struct thread *, int, void *, size_t, long, int, long *);

Modified: head/sys/vm/vm_mmap.c
==============================================================================
--- head/sys/vm/vm_mmap.c	Tue Jul  2 19:01:14 2019	(r349608)
+++ head/sys/vm/vm_mmap.c	Tue Jul  2 19:07:17 2019	(r349609)
@@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/sysproto.h>
+#include <sys/elf.h>
 #include <sys/filedesc.h>
 #include <sys/priv.h>
 #include <sys/proc.h>
@@ -182,6 +183,19 @@ sys_mmap(struct thread *td, struct mmap_args *uap)
 }
 
 int
+kern_mmap_maxprot(struct proc *p, int prot)
+{
+
+	if ((p->p_flag2 & P2_PROTMAX_DISABLE) != 0 ||
+	    (p->p_fctl0 & NT_FREEBSD_FCTL_PROTMAX_DISABLE) != 0)
+		return (_PROT_ALL);
+	if (((p->p_flag2 & P2_PROTMAX_ENABLE) != 0 || imply_prot_max) &&
+	    prot != PROT_NONE)
+		 return (prot);
+	return (_PROT_ALL);
+}
+
+int
 kern_mmap(struct thread *td, uintptr_t addr0, size_t len, int prot, int flags,
     int fd, off_t pos)
 {
@@ -206,12 +220,9 @@ kern_mmap(struct thread *td, uintptr_t addr0, size_t l
 	/*
 	 * Always honor PROT_MAX if set.  If not, default to all
 	 * permissions unless we're implying maximum permissions.
-	 *
-	 * XXX: should be tunable per process and ABI.
 	 */
 	if (max_prot == 0)
-		max_prot = (imply_prot_max && prot != PROT_NONE) ?
-		    prot : _PROT_ALL;
+		max_prot = kern_mmap_maxprot(p, prot);
 
 	vms = p->p_vmspace;
 	fp = NULL;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201907021907.x62J7IdO092798>