⬢ DragonFlyBSD Kernel Audit
DF-2985 / fix.diff
← back to finding ↓ download raw
--- a/sys/kern/kern_syscalls.c
+++ b/sys/kern/kern_syscalls.c
@@ -65,15 +65,31 @@
                return EEXIST;
 
        *old_sysent = sysent[*offset];
-       sysent[*offset] = *new_sysent;
+       /*
+        * Publish in a defined order (sy_narg first, sy_call last) so a
+        * racing dispatcher never sees the new sy_call with a stale narg.
+        * (Full in-flight quiesce still requires a dispatch epoch.)
+        */
+       sysent[*offset].sy_narg = new_sysent->sy_narg;
+       sysent[*offset].sy_rsize = new_sysent->sy_rsize;
+       cpu_ccfence();
+       sysent[*offset].sy_abort = new_sysent->sy_abort;
+       cpu_ccfence();
+       sysent[*offset].sy_call = new_sysent->sy_call;
        return 0;
 }
 
 int
 syscall_deregister(int *offset, struct sysent *old_sysent)
 {
-       if (*offset)
-               sysent[*offset] = *old_sysent;
+       if (*offset) {
+               /* Retract sy_call FIRST so no new dispatch enters it. */
+               sysent[*offset].sy_call = (sy_call_t *)sys_lkmnosys;
+               cpu_ccfence();
+               sysent[*offset].sy_narg = old_sysent->sy_narg;
+               sysent[*offset].sy_rsize = old_sysent->sy_rsize;
+               sysent[*offset].sy_abort = old_sysent->sy_abort;
+       }
        return 0;
 }