regmap
regmap copied to clipboard
userfaultfd backend
regmap currently registers load-bearing SIGBUS and SIGSEGV handlers, but these have many alternative uses (stack overflow detection, core dumping/crash reporting, ON ERROR RESUME NEXT, miscellaneous PROT_NONE catching) and, unfortunately, signal disposition is hopelessly global!
userfaultd is a more general mechanism to handle page-faults in userspace (from a different thread, or from a different process). Unless disabled through /proc/sys/vm/unprivileged_userfaultfd, userfaultd can be used without privileges.
Currently it is mostly used for migration/checkpoint-restore code, and not so much for the traditional "sigaction" use-cases, so there should be less potential conflict with other libraries, and support for full userfaultd chaining/nesting is also being thought about, something impossible with signals!
Clearly, the 8086's lack of support for memory-mapping registers is a grave oversight and Rust would greatly benefit from a regmap backend that is compatible with more libraries =D
this is a compelling argument! and of course a fork or clone could inherit the fd, no one would have to sweat the ~gremlin~ thread keeping faults serviced.
it's not possible to observe or modify the faulting thread's context through uffd, that i know of. there's an under-documented flag to have linux report the faulting thread's tid and with that some clever ptrace could let the fault-handling thread update the faulter's thread context, maybe? i think that interacts poorly if someone were to try using a debugger on either the parent or child processes though.
if you know a more fitting way to get updated information into the faulter's thread context, i'm all ears!
I've read that Checkpoint/Restore in Userspace (CRIU) uses a parasite shellcode injected via ptrace to access thread context, so clever-ptracing is definitely possible, but you're right that preventing debuggers from attaching would be very unfortunate.
For pure register reads, depending on perf_event_paranoid, possibly perf_event_open with PERF_SAMPLE_REGS_USER could be used instead of a complex ptrace maneuver.
But if the process is already ptraced and we want to write, there ought to be some very reasonable & practical alternatives!
- userfaultd could be used merely as a convoluted mechanism to redirect the fault from a SIGSEGV/SIGBUS to something less likely to be clobbered by user code, like a SIGPWR or SIGSTKFLT handler
- a parasite shellcode could still potentially be injected through other means (process_vm_{read,write}v, /proc/self/mem ?) at the faulting RIP of the right thread, which might be found by looking up
proc/<pid>/stat'skstkeipfield for the undocumentedptidargument received from userfaultd - since
regmaponly needs temporary ptrace access during faults, if a debugger is already attached we can of course ptrace the debugger, walking down the chain until we reach our debugee, poke around, and then detach!- The fine people at
rr(andfakeroot-ng) even seem to have code that emulates enough of ptrace-inside-ptrace that runninggdbunder ptrace actually works (!?).- Even if mildly impractical, knowing that my program could spin up a ptrace-emulator that infects a GDB process from a userspace pagefault handler whenever I touch a memory-mapped register to increment my loop counters would just make me feel very interesting feelings =]
- The fine people at
- alternatively,
strace, another tool that normally uses ptrace, knows how to connect to a gdbserver instead of using ptrace directly. If the userfaultd handler had gdbserver support, this could be a very unsatisfying way to support attaching a debugger...
I have not thought very deeply about any of these, and I have to apologize for inflicting this 'feature request' on you, but on the off-chance any of these might work, I couldn't miss an opportunity to make this hack harmonization of micro-architectural data access patterns more terrifying widely-applicable.