Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

userfaultfd backend #1

Open
tux3 opened this issue Mar 13, 2021 · 2 comments
Open

userfaultfd backend #1

tux3 opened this issue Mar 13, 2021 · 2 comments

Comments

@tux3
Copy link

tux3 commented Mar 13, 2021

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

@iximeow
Copy link
Owner

iximeow commented Mar 13, 2021

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!

@tux3
Copy link
Author

tux3 commented Mar 14, 2021

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's kstkeip field for the undocumented ptid argument received from userfaultd
  • since regmap only 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 (and fakeroot-ng) even seem to have code that emulates enough of ptrace-inside-ptrace that running gdb under 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 =]
  • 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants