Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F150484129
D31779.id94568.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D31779.id94568.diff
View Options
diff --git a/lib/libc/sys/procctl.2 b/lib/libc/sys/procctl.2
--- a/lib/libc/sys/procctl.2
+++ b/lib/libc/sys/procctl.2
@@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 1, 2021
+.Dd September 2, 2021
.Dt PROCCTL 2
.Os
.Sh NAME
@@ -599,6 +599,62 @@
.It Dv PROC_NO_NEW_PRIVS_ENABLE
.It Dv PROC_NO_NEW_PRIVS_DISABLE
.El
+.It Dv PROC_WXORX_CTL
+Controls the 'write exclusive against execution' permissions for the
+mappings in the process address space.
+It overrides the global settings established by the
+.Dv kern.elf{32/64}.allow_wx
+sysctl,
+and corresponding bit in the elf control note, see
+.Xr elfctl 1 .
+.Pp
+The
+.Fa data
+parameter must point to the integer variable holding one of the
+following values:
+.Bl -tag -width PROC_WXORX_ENABLE_ON_EXEC
+.It Dv PROC_WXORX_DISABLE
+Enable creation of mappings that have both write and execute
+protection attributes, in the specified process' address space.
+.It Dv PROC_WXORX_ENABLE_ON_EXEC
+In the new address space created by
+.Xr execve 2 ,
+disallow creation of mappings that have both write and execute
+permissions.
+.El
+.Pp
+Once creation of writeable and executable mappings is allowed,
+it is impossible (and pointless) to disallow it.
+The only way to ensure the absence of such mappings after they
+were enabled in a given process, is to set the
+.Dv PROC_WXORX_ENABLE_ON_EXEC
+flag and
+.Xr execve 2
+an image.
+.It Dv PROC_WXORX_STATUS
+Returns the current status of the 'write exclusive against execution'
+enforcement for the specified process.
+The
+.Dv data
+parameter must point to the integer variable, where one of the
+following values is written:
+.Bl -tag -width PROC_WXORX_ENABLE_ON_EXEC
+.It Dv PROC_WXORX_DISABLE
+Creation of simultaneously writable and executable mapping is permitted,
+otherwise the process cannot create such mappings.
+.It Dv PROC_WXORX_ENABLE_ON_EXEC
+After
+.Xr execve 2 ,
+the new address space should disallow creation of simultaneously
+writable and executable mappings.
+.El
+.Pp
+Additionally, if the address space of the process disallows
+creation of simultaneously writable and executable mappings and
+it is guaranteed that no such mapping was created since address space
+creation, the
+.Dv PROC_WXORX_ENFORCE
+flag is set in the returned value.
.El
.Sh x86 MACHINE-SPECIFIC REQUESTS
.Bl -tag -width PROC_KPTI_STATUS
@@ -648,6 +704,12 @@
and via other system mechanisms.
As such, it should not be utilized to reliably protect cryptographic
keying material or other confidential data.
+.Pp
+Note that processes can trivially bypass the 'no simultaneously
+writable and executable mappings' policy by first marking some mapping
+as writeable and write code to it, then removing write and adding
+execute permission.
+This may be legitimately required by some programs, such as JIT compilers.
.Sh RETURN VALUES
If an error occurs, a value of -1 is returned and
.Va errno
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -3643,6 +3643,7 @@
case PROC_TRACE_CTL:
case PROC_TRAPCAP_CTL:
case PROC_NO_NEW_PRIVS_CTL:
+ case PROC_WXORX_CTL:
error = copyin(PTRIN(uap->data), &flags, sizeof(flags));
if (error != 0)
return (error);
@@ -3677,6 +3678,7 @@
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
case PROC_NO_NEW_PRIVS_STATUS:
+ case PROC_WXORX_STATUS:
data = &flags;
break;
case PROC_PDEATHSIG_CTL:
@@ -3709,6 +3711,7 @@
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
case PROC_NO_NEW_PRIVS_STATUS:
+ case PROC_WXORX_STATUS:
if (error == 0)
error = copyout(&flags, uap->data, sizeof(flags));
break;
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -1216,7 +1216,8 @@
*/
if (imgp->credential_setid) {
PROC_LOCK(imgp->proc);
- imgp->proc->p_flag2 &= ~(P2_ASLR_ENABLE | P2_ASLR_DISABLE);
+ imgp->proc->p_flag2 &= ~(P2_ASLR_ENABLE | P2_ASLR_DISABLE |
+ P2_WXORX_DISABLE | P2_WXORX_ENABLE_EXEC);
PROC_UNLOCK(imgp->proc);
}
if ((sv->sv_flags & SV_ASLR) == 0 ||
@@ -1239,7 +1240,9 @@
imgp->map_flags |= MAP_ASLR_IGNSTART;
}
- if (!__elfN(allow_wx) && (fctl0 & NT_FREEBSD_FCTL_WXNEEDED) == 0)
+ if ((!__elfN(allow_wx) && (fctl0 & NT_FREEBSD_FCTL_WXNEEDED) == 0 &&
+ (imgp->proc->p_flag2 & P2_WXORX_DISABLE) == 0) ||
+ (imgp->proc->p_flag2 & P2_WXORX_ENABLE_EXEC) != 0)
imgp->map_flags |= MAP_WXORX;
error = exec_new_vmspace(imgp, sv);
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -493,7 +493,8 @@
p2->p_flag2 = p1->p_flag2 & (P2_ASLR_DISABLE | P2_ASLR_ENABLE |
P2_ASLR_IGNSTART | P2_NOTRACE | P2_NOTRACE_EXEC |
P2_PROTMAX_ENABLE | P2_PROTMAX_DISABLE | P2_TRAPCAP |
- P2_STKGAP_DISABLE | P2_STKGAP_DISABLE_EXEC | P2_NO_NEW_PRIVS);
+ P2_STKGAP_DISABLE | P2_STKGAP_DISABLE_EXEC | P2_NO_NEW_PRIVS |
+ P2_WXORX_DISABLE | P2_WXORX_ENABLE_EXEC);
p2->p_swtick = ticks;
if (p1->p_flag & P_PROFIL)
startprofclock(p2);
diff --git a/sys/kern/kern_procctl.c b/sys/kern/kern_procctl.c
--- a/sys/kern/kern_procctl.c
+++ b/sys/kern/kern_procctl.c
@@ -591,6 +591,71 @@
return (0);
}
+static int
+wxorx_ctl(struct thread *td, struct proc *p, int state)
+{
+ struct vmspace *vm;
+ vm_map_t map;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ if ((p->p_flag & P_WEXIT) != 0)
+ return (ESRCH);
+
+ switch (state) {
+ case PROC_WXORX_DISABLE:
+ p->p_flag2 |= P2_WXORX_DISABLE;
+ _PHOLD(p);
+ PROC_UNLOCK(p);
+ vm = vmspace_acquire_ref(p);
+ if (vm != NULL) {
+ map = &vm->vm_map;
+ vm_map_lock(map);
+ map->flags &= ~MAP_WXORX;
+ vm_map_unlock(map);
+ vmspace_free(vm);
+ }
+ PROC_LOCK(p);
+ _PRELE(p);
+ break;
+ case PROC_WXORX_ENABLE_ON_EXEC:
+ p->p_flag2 |= P2_WXORX_ENABLE_EXEC;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+static int
+wxorx_status(struct thread *td, struct proc *p, int *data)
+{
+ struct vmspace *vm;
+ int d;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ if ((p->p_flag & P_WEXIT) != 0)
+ return (ESRCH);
+
+ d = 0;
+ if ((p->p_flag2 & P2_WXORX_DISABLE) != 0)
+ d |= PROC_WXORX_DISABLE;
+ if ((p->p_flag2 & P2_WXORX_ENABLE_EXEC) != 0)
+ d |= PROC_WXORX_ENABLE_ON_EXEC;
+ _PHOLD(p);
+ PROC_UNLOCK(p);
+ vm = vmspace_acquire_ref(p);
+ if (vm != NULL) {
+ if ((vm->vm_map.flags & MAP_WXORX) != 0)
+ d |= PROC_WXORX_ENFORCE;
+ vmspace_free(vm);
+ }
+ PROC_LOCK(p);
+ _PRELE(p);
+ *data = d;
+ return (0);
+}
+
#ifndef _SYS_SYSPROTO_H_
struct procctl_args {
idtype_t idtype;
@@ -623,6 +688,7 @@
case PROC_TRACE_CTL:
case PROC_TRAPCAP_CTL:
case PROC_NO_NEW_PRIVS_CTL:
+ case PROC_WXORX_CTL:
error = copyin(uap->data, &flags, sizeof(flags));
if (error != 0)
return (error);
@@ -655,6 +721,7 @@
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
case PROC_NO_NEW_PRIVS_STATUS:
+ case PROC_WXORX_STATUS:
data = &flags;
break;
case PROC_PDEATHSIG_CTL:
@@ -686,6 +753,7 @@
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
case PROC_NO_NEW_PRIVS_STATUS:
+ case PROC_WXORX_STATUS:
if (error == 0)
error = copyout(&flags, uap->data, sizeof(flags));
break;
@@ -739,6 +807,10 @@
return (no_new_privs_ctl(td, p, *(int *)data));
case PROC_NO_NEW_PRIVS_STATUS:
return (no_new_privs_status(td, p, data));
+ case PROC_WXORX_CTL:
+ return (wxorx_ctl(td, p, *(int *)data));
+ case PROC_WXORX_STATUS:
+ return (wxorx_status(td, p, data));
default:
return (EINVAL);
}
@@ -771,6 +843,8 @@
case PROC_PDEATHSIG_STATUS:
case PROC_NO_NEW_PRIVS_CTL:
case PROC_NO_NEW_PRIVS_STATUS:
+ case PROC_WXORX_CTL:
+ case PROC_WXORX_STATUS:
if (idtype != P_PID)
return (EINVAL);
}
@@ -821,6 +895,8 @@
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
case PROC_NO_NEW_PRIVS_STATUS:
+ case PROC_WXORX_CTL:
+ case PROC_WXORX_STATUS:
tree_locked = false;
break;
default:
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -838,6 +838,8 @@
#define P2_ITSTOPPED 0x00002000
#define P2_PTRACEREQ 0x00004000 /* Active ptrace req */
#define P2_NO_NEW_PRIVS 0x00008000 /* Ignore setuid */
+#define P2_WXORX_DISABLE 0x00010000 /* WX mappings enabled */
+#define P2_WXORX_ENABLE_EXEC 0x00020000 /* WXORX enabled after exec */
/* Flags protected by proctree_lock, kept in p_treeflags. */
#define P_TREE_ORPHANED 0x00000001 /* Reparented, on orphan list */
diff --git a/sys/sys/procctl.h b/sys/sys/procctl.h
--- a/sys/sys/procctl.h
+++ b/sys/sys/procctl.h
@@ -65,6 +65,8 @@
#define PROC_STACKGAP_STATUS 18 /* query stack gap */
#define PROC_NO_NEW_PRIVS_CTL 19 /* disable setuid/setgid */
#define PROC_NO_NEW_PRIVS_STATUS 20 /* query suid/sgid disabled status */
+#define PROC_WXORX_CTL 21 /* control W^X */
+#define PROC_WXORX_STATUS 22 /* query W^X */
/* Operations for PROC_SPROTECT (passed in integer arg). */
#define PPROT_OP(x) ((x) & 0xf)
@@ -146,6 +148,10 @@
#define PROC_NO_NEW_PRIVS_ENABLE 1
#define PROC_NO_NEW_PRIVS_DISABLE 2
+#define PROC_WXORX_DISABLE 0x0001
+#define PROC_WXORX_ENABLE_ON_EXEC 0x0002
+#define PROC_WXORX_ENFORCE 0x80000000
+
#ifndef _KERNEL
__BEGIN_DECLS
int procctl(idtype_t, id_t, int, void *);
diff --git a/usr.bin/proccontrol/proccontrol.1 b/usr.bin/proccontrol/proccontrol.1
--- a/usr.bin/proccontrol/proccontrol.1
+++ b/usr.bin/proccontrol/proccontrol.1
@@ -28,7 +28,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 2, 2021
+.Dd September 2, 2021
.Dt PROCCONTROL 1
.Os
.Sh NAME
@@ -72,6 +72,8 @@
.It Ar nonewprivs
Controls disabling the setuid and sgid bits for
.Xr execve 2 .
+.It Ar wxorx
+Controls the write exclusive execute mode for mappings.
.It Ar kpti
Controls the KPTI enable, AMD64 only.
.It Ar la48
diff --git a/usr.bin/proccontrol/proccontrol.c b/usr.bin/proccontrol/proccontrol.c
--- a/usr.bin/proccontrol/proccontrol.c
+++ b/usr.bin/proccontrol/proccontrol.c
@@ -46,6 +46,7 @@
MODE_PROTMAX,
MODE_STACKGAP,
MODE_NO_NEW_PRIVS,
+ MODE_WXORX,
#ifdef PROC_KPTI_CTL
MODE_KPTI,
#endif
@@ -85,7 +86,7 @@
{
fprintf(stderr, "Usage: proccontrol -m (aslr|protmax|trace|trapcap|"
- "stackgap|nonewprivs"KPTI_USAGE LA_USAGE") [-q] "
+ "stackgap|nonewprivs|wxorx"KPTI_USAGE LA_USAGE") [-q] "
"[-s (enable|disable)] [-p pid | command]\n");
exit(1);
}
@@ -116,6 +117,8 @@
mode = MODE_STACKGAP;
else if (strcmp(optarg, "nonewprivs") == 0)
mode = MODE_NO_NEW_PRIVS;
+ else if (strcmp(optarg, "wxorx") == 0)
+ mode = MODE_WXORX;
#ifdef PROC_KPTI_CTL
else if (strcmp(optarg, "kpti") == 0)
mode = MODE_KPTI;
@@ -178,7 +181,11 @@
error = procctl(P_PID, pid, PROC_STACKGAP_STATUS, &arg);
break;
case MODE_NO_NEW_PRIVS:
- error = procctl(P_PID, pid, PROC_NO_NEW_PRIVS_STATUS, &arg);
+ error = procctl(P_PID, pid, PROC_NO_NEW_PRIVS_STATUS,
+ &arg);
+ break;
+ case MODE_WXORX:
+ error = procctl(P_PID, pid, PROC_WXORX_STATUS, &arg);
break;
#ifdef PROC_KPTI_CTL
case MODE_KPTI:
@@ -280,6 +287,17 @@
break;
}
break;
+ case MODE_WXORX:
+ if ((arg & PROC_WXORX_DISABLE) != 0)
+ printf("disabled");
+ else
+ printf("enabled");
+ if ((arg & PROC_WXORX_ENABLE_ON_EXEC) != 0)
+ printf(", enabled on exec");
+ if ((arg & PROC_WXORX_ENFORCE) != 0)
+ printf(", enforced");
+ printf("\n");
+ break;
#ifdef PROC_KPTI_CTL
case MODE_KPTI:
switch (arg & ~PROC_KPTI_STATUS_ACTIVE) {
@@ -349,7 +367,13 @@
case MODE_NO_NEW_PRIVS:
arg = enable ? PROC_NO_NEW_PRIVS_ENABLE :
PROC_NO_NEW_PRIVS_DISABLE;
- error = procctl(P_PID, pid, PROC_NO_NEW_PRIVS_CTL, &arg);
+ error = procctl(P_PID, pid, PROC_NO_NEW_PRIVS_CTL,
+ &arg);
+ break;
+ case MODE_WXORX:
+ arg = enable ? PROC_WXORX_ENABLE_ON_EXEC :
+ PROC_WXORX_DISABLE;
+ error = procctl(P_PID, pid, PROC_WXORX_CTL, &arg);
break;
#ifdef PROC_KPTI_CTL
case MODE_KPTI:
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Apr 2, 3:12 PM (8 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
30727127
Default Alt Text
D31779.id94568.diff (11 KB)
Attached To
Mode
D31779: procctl(2) and proccontrol(1): add W^X control
Attached
Detach File
Event Timeline
Log In to Comment