On Mon, Jan 10, 2022 at 12:06:44PM +0000, Klemens Nanni wrote:
> On Fri, Dec 31, 2021 at 07:54:53PM +0300, Vitaliy Makkoveev wrote:
> > The uvm_wxabort path within uvm_wxcheck() looks not MP-safe.
>
> Right, I did not pay enough attention to W^X handling.
New diff, either alone or on top of the mmap unlocking.
> I'm not entirely sure about the sigexit() path.
We can't dump core without the kernel lock, assertions do make sure...
> There's `ps_wxcounter' as u_int64_t which needs a lock or atomic
> operations.
This could look like this. `ps_wxcounter' is not used anywhere else in
the tree; it has been like this since import in 2016.
> The kernel lock could be pushed into uvm_wxabort() but there it'd still
> be grabbed for every mmap(2) call.
This means we're only grabbing the kernel lock if `kern.wxabort=1' is
set *and* there's a W^X violation -- much better.
Index: sys/proc.h
===================================================================
RCS file: /cvs/src/sys/sys/proc.h,v
retrieving revision 1.323
diff -u -p -r1.323 proc.h
--- sys/proc.h 10 Dec 2021 05:34:42 -0000 1.323
+++ sys/proc.h 9 Jan 2022 13:42:45 -0000
@@ -197,7 +197,7 @@ struct process {
time_t ps_nextxcpu; /* when to send next SIGXCPU, */
/* in seconds of process runtime */
- u_int64_t ps_wxcounter;
+ u_int64_t ps_wxcounter; /* [a] number of W^X violations */
struct unveil *ps_uvpaths; /* unveil vnodes and names */
ssize_t ps_uvvcount; /* count of unveil vnodes held */
Index: uvm/uvm_mmap.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_mmap.c,v
retrieving revision 1.168
diff -u -p -r1.168 uvm_mmap.c
--- uvm/uvm_mmap.c 5 Jan 2022 17:53:44 -0000 1.168
+++ uvm/uvm_mmap.c 10 Jan 2022 15:48:03 -0000
@@ -184,11 +184,13 @@ uvm_wxcheck(struct proc *p, char *call)
if (uvm_wxabort) {
/* Report W^X failures */
- if (pr->ps_wxcounter++ == 0)
+ if (atomic_inc_long_nv((unsigned long *)&pr->ps_wxcounter) == 1)
log(LOG_NOTICE, "%s(%d): %s W^X violation\n",
pr->ps_comm, pr->ps_pid, call);
/* Send uncatchable SIGABRT for coredump */
+ KERNEL_LOCK();
sigexit(p, SIGABRT);
+ KERNEL_UNLOCK();
}
return ENOTSUP;