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
This commit is contained in:
parent
3730695151
commit
5dc7e31a09
@ -94,7 +94,7 @@ Same notes as for
|
|||||||
.Dv PROC_ASLR_FORCE_ENABLE
|
.Dv PROC_ASLR_FORCE_ENABLE
|
||||||
apply.
|
apply.
|
||||||
.It Dv PROC_ASLR_NOFORCE
|
.It Dv PROC_ASLR_NOFORCE
|
||||||
Use system-wide configured policy for ASLR.
|
Use the system-wide configured policy for ASLR.
|
||||||
.El
|
.El
|
||||||
.It Dv PROC_ASLR_STATUS
|
.It Dv PROC_ASLR_STATUS
|
||||||
Returns the current status of ASLR enablement for the target process.
|
Returns the current status of ASLR enablement for the target process.
|
||||||
@ -112,6 +112,47 @@ If the currently executed image in the process itself has ASLR enabled,
|
|||||||
the
|
the
|
||||||
.Dv PROC_ASLR_ACTIVE
|
.Dv PROC_ASLR_ACTIVE
|
||||||
flag is or-ed with the value listed above.
|
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
|
.It Dv PROC_SPROTECT
|
||||||
Set process protection state.
|
Set process protection state.
|
||||||
This is used to mark a process as protected from being killed if the system
|
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 cap_enter 2,
|
||||||
.Xr kill 2 ,
|
.Xr kill 2 ,
|
||||||
.Xr ktrace 2 ,
|
.Xr ktrace 2 ,
|
||||||
|
.Xr mmap 2 ,
|
||||||
|
.Xr mprotect 2 ,
|
||||||
.Xr ptrace 2 ,
|
.Xr ptrace 2 ,
|
||||||
.Xr wait 2 ,
|
.Xr wait 2 ,
|
||||||
.Xr capsicum 4 ,
|
.Xr capsicum 4 ,
|
||||||
|
@ -3333,6 +3333,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap)
|
|||||||
|
|
||||||
switch (uap->com) {
|
switch (uap->com) {
|
||||||
case PROC_ASLR_CTL:
|
case PROC_ASLR_CTL:
|
||||||
|
case PROC_PROTMAX_CTL:
|
||||||
case PROC_SPROTECT:
|
case PROC_SPROTECT:
|
||||||
case PROC_TRACE_CTL:
|
case PROC_TRACE_CTL:
|
||||||
case PROC_TRAPCAP_CTL:
|
case PROC_TRAPCAP_CTL:
|
||||||
@ -3365,6 +3366,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap)
|
|||||||
data = &x.rk;
|
data = &x.rk;
|
||||||
break;
|
break;
|
||||||
case PROC_ASLR_STATUS:
|
case PROC_ASLR_STATUS:
|
||||||
|
case PROC_PROTMAX_STATUS:
|
||||||
case PROC_TRACE_STATUS:
|
case PROC_TRACE_STATUS:
|
||||||
case PROC_TRAPCAP_STATUS:
|
case PROC_TRAPCAP_STATUS:
|
||||||
data = &flags;
|
data = &flags;
|
||||||
@ -3394,6 +3396,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap)
|
|||||||
error = error1;
|
error = error1;
|
||||||
break;
|
break;
|
||||||
case PROC_ASLR_STATUS:
|
case PROC_ASLR_STATUS:
|
||||||
|
case PROC_PROTMAX_STATUS:
|
||||||
case PROC_TRACE_STATUS:
|
case PROC_TRACE_STATUS:
|
||||||
case PROC_TRAPCAP_STATUS:
|
case PROC_TRAPCAP_STATUS:
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
|
@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
#include <sys/capsicum.h>
|
#include <sys/capsicum.h>
|
||||||
#include <sys/lock.h>
|
#include <sys/lock.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
#include <sys/mutex.h>
|
#include <sys/mutex.h>
|
||||||
#include <sys/priv.h>
|
#include <sys/priv.h>
|
||||||
#include <sys/proc.h>
|
#include <sys/proc.h>
|
||||||
@ -418,6 +419,51 @@ trapcap_status(struct thread *td, struct proc *p, int *data)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
static int
|
||||||
aslr_ctl(struct thread *td, struct proc *p, int state)
|
aslr_ctl(struct thread *td, struct proc *p, int state)
|
||||||
{
|
{
|
||||||
@ -500,6 +546,7 @@ sys_procctl(struct thread *td, struct procctl_args *uap)
|
|||||||
|
|
||||||
switch (uap->com) {
|
switch (uap->com) {
|
||||||
case PROC_ASLR_CTL:
|
case PROC_ASLR_CTL:
|
||||||
|
case PROC_PROTMAX_CTL:
|
||||||
case PROC_SPROTECT:
|
case PROC_SPROTECT:
|
||||||
case PROC_TRACE_CTL:
|
case PROC_TRACE_CTL:
|
||||||
case PROC_TRAPCAP_CTL:
|
case PROC_TRAPCAP_CTL:
|
||||||
@ -530,6 +577,7 @@ sys_procctl(struct thread *td, struct procctl_args *uap)
|
|||||||
data = &x.rk;
|
data = &x.rk;
|
||||||
break;
|
break;
|
||||||
case PROC_ASLR_STATUS:
|
case PROC_ASLR_STATUS:
|
||||||
|
case PROC_PROTMAX_STATUS:
|
||||||
case PROC_TRACE_STATUS:
|
case PROC_TRACE_STATUS:
|
||||||
case PROC_TRAPCAP_STATUS:
|
case PROC_TRAPCAP_STATUS:
|
||||||
data = &flags;
|
data = &flags;
|
||||||
@ -558,6 +606,7 @@ sys_procctl(struct thread *td, struct procctl_args *uap)
|
|||||||
error = error1;
|
error = error1;
|
||||||
break;
|
break;
|
||||||
case PROC_ASLR_STATUS:
|
case PROC_ASLR_STATUS:
|
||||||
|
case PROC_PROTMAX_STATUS:
|
||||||
case PROC_TRACE_STATUS:
|
case PROC_TRACE_STATUS:
|
||||||
case PROC_TRAPCAP_STATUS:
|
case PROC_TRAPCAP_STATUS:
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
@ -583,6 +632,10 @@ kern_procctl_single(struct thread *td, struct proc *p, int com, void *data)
|
|||||||
return (aslr_status(td, p, data));
|
return (aslr_status(td, p, data));
|
||||||
case PROC_SPROTECT:
|
case PROC_SPROTECT:
|
||||||
return (protect_set(td, p, *(int *)data));
|
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:
|
case PROC_REAP_ACQUIRE:
|
||||||
return (reap_acquire(td, p));
|
return (reap_acquire(td, p));
|
||||||
case PROC_REAP_RELEASE:
|
case PROC_REAP_RELEASE:
|
||||||
@ -618,6 +671,8 @@ kern_procctl(struct thread *td, idtype_t idtype, id_t id, int com, void *data)
|
|||||||
switch (com) {
|
switch (com) {
|
||||||
case PROC_ASLR_CTL:
|
case PROC_ASLR_CTL:
|
||||||
case PROC_ASLR_STATUS:
|
case PROC_ASLR_STATUS:
|
||||||
|
case PROC_PROTMAX_CTL:
|
||||||
|
case PROC_PROTMAX_STATUS:
|
||||||
case PROC_REAP_ACQUIRE:
|
case PROC_REAP_ACQUIRE:
|
||||||
case PROC_REAP_RELEASE:
|
case PROC_REAP_RELEASE:
|
||||||
case PROC_REAP_STATUS:
|
case PROC_REAP_STATUS:
|
||||||
@ -669,6 +724,8 @@ kern_procctl(struct thread *td, idtype_t idtype, id_t id, int com, void *data)
|
|||||||
break;
|
break;
|
||||||
case PROC_ASLR_CTL:
|
case PROC_ASLR_CTL:
|
||||||
case PROC_ASLR_STATUS:
|
case PROC_ASLR_STATUS:
|
||||||
|
case PROC_PROTMAX_CTL:
|
||||||
|
case PROC_PROTMAX_STATUS:
|
||||||
case PROC_TRACE_STATUS:
|
case PROC_TRACE_STATUS:
|
||||||
case PROC_TRAPCAP_STATUS:
|
case PROC_TRAPCAP_STATUS:
|
||||||
tree_locked = false;
|
tree_locked = false;
|
||||||
|
@ -777,6 +777,7 @@ typedef struct {
|
|||||||
|
|
||||||
/* NT_FREEBSD_FEATURE_CTL desc[0] bits */
|
/* NT_FREEBSD_FEATURE_CTL desc[0] bits */
|
||||||
#define NT_FREEBSD_FCTL_ASLR_DISABLE 0x00000001
|
#define NT_FREEBSD_FCTL_ASLR_DISABLE 0x00000001
|
||||||
|
#define NT_FREEBSD_FCTL_PROTMAX_DISABLE 0x00000002
|
||||||
|
|
||||||
/* Values for n_type. Used in core files. */
|
/* Values for n_type. Used in core files. */
|
||||||
#define NT_PRSTATUS 1 /* Process status. */
|
#define NT_PRSTATUS 1 /* Process status. */
|
||||||
|
@ -761,6 +761,8 @@ struct proc {
|
|||||||
#define P2_ASLR_ENABLE 0x00000040 /* Force enable ASLR. */
|
#define P2_ASLR_ENABLE 0x00000040 /* Force enable ASLR. */
|
||||||
#define P2_ASLR_DISABLE 0x00000080 /* Force disable ASLR. */
|
#define P2_ASLR_DISABLE 0x00000080 /* Force disable ASLR. */
|
||||||
#define P2_ASLR_IGNSTART 0x00000100 /* Enable ASLR to consume sbrk area. */
|
#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. */
|
/* Flags protected by proctree_lock, kept in p_treeflags. */
|
||||||
#define P_TREE_ORPHANED 0x00000001 /* Reparented, on orphan list */
|
#define P_TREE_ORPHANED 0x00000001 /* Reparented, on orphan list */
|
||||||
|
@ -59,6 +59,8 @@
|
|||||||
#define PROC_PDEATHSIG_STATUS 12 /* get parent death signal */
|
#define PROC_PDEATHSIG_STATUS 12 /* get parent death signal */
|
||||||
#define PROC_ASLR_CTL 13 /* en/dis ASLR */
|
#define PROC_ASLR_CTL 13 /* en/dis ASLR */
|
||||||
#define PROC_ASLR_STATUS 14 /* query ASLR status */
|
#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). */
|
/* Operations for PROC_SPROTECT (passed in integer arg). */
|
||||||
#define PPROT_OP(x) ((x) & 0xf)
|
#define PPROT_OP(x) ((x) & 0xf)
|
||||||
@ -127,6 +129,11 @@ struct procctl_reaper_kill {
|
|||||||
#define PROC_ASLR_NOFORCE 3
|
#define PROC_ASLR_NOFORCE 3
|
||||||
#define PROC_ASLR_ACTIVE 0x80000000
|
#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
|
#ifndef _KERNEL
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
int procctl(idtype_t, id_t, int, void *);
|
int procctl(idtype_t, id_t, int, void *);
|
||||||
|
@ -175,6 +175,7 @@ int kern_mlock(struct proc *proc, struct ucred *cred, uintptr_t addr,
|
|||||||
size_t len);
|
size_t len);
|
||||||
int kern_mmap(struct thread *td, uintptr_t addr, size_t len, int prot,
|
int kern_mmap(struct thread *td, uintptr_t addr, size_t len, int prot,
|
||||||
int flags, int fd, off_t pos);
|
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_mprotect(struct thread *td, uintptr_t addr, size_t size, int prot);
|
||||||
int kern_msgctl(struct thread *, int, int, struct msqid_ds *);
|
int kern_msgctl(struct thread *, int, int, struct msqid_ds *);
|
||||||
int kern_msgrcv(struct thread *, int, void *, size_t, long, int, long *);
|
int kern_msgrcv(struct thread *, int, void *, size_t, long, int, long *);
|
||||||
|
@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/lock.h>
|
#include <sys/lock.h>
|
||||||
#include <sys/mutex.h>
|
#include <sys/mutex.h>
|
||||||
#include <sys/sysproto.h>
|
#include <sys/sysproto.h>
|
||||||
|
#include <sys/elf.h>
|
||||||
#include <sys/filedesc.h>
|
#include <sys/filedesc.h>
|
||||||
#include <sys/priv.h>
|
#include <sys/priv.h>
|
||||||
#include <sys/proc.h>
|
#include <sys/proc.h>
|
||||||
@ -181,6 +182,19 @@ sys_mmap(struct thread *td, struct mmap_args *uap)
|
|||||||
uap->flags, uap->fd, uap->pos));
|
uap->flags, uap->fd, uap->pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
int
|
||||||
kern_mmap(struct thread *td, uintptr_t addr0, size_t len, int prot, int flags,
|
kern_mmap(struct thread *td, uintptr_t addr0, size_t len, int prot, int flags,
|
||||||
int fd, off_t pos)
|
int fd, off_t pos)
|
||||||
@ -206,12 +220,9 @@ kern_mmap(struct thread *td, uintptr_t addr0, size_t len, int prot, int flags,
|
|||||||
/*
|
/*
|
||||||
* Always honor PROT_MAX if set. If not, default to all
|
* Always honor PROT_MAX if set. If not, default to all
|
||||||
* permissions unless we're implying maximum permissions.
|
* permissions unless we're implying maximum permissions.
|
||||||
*
|
|
||||||
* XXX: should be tunable per process and ABI.
|
|
||||||
*/
|
*/
|
||||||
if (max_prot == 0)
|
if (max_prot == 0)
|
||||||
max_prot = (imply_prot_max && prot != PROT_NONE) ?
|
max_prot = kern_mmap_maxprot(p, prot);
|
||||||
prot : _PROT_ALL;
|
|
||||||
|
|
||||||
vms = p->p_vmspace;
|
vms = p->p_vmspace;
|
||||||
fp = NULL;
|
fp = NULL;
|
||||||
|
Loading…
Reference in New Issue
Block a user