catch SIGKILL in MacOS driver - macos

I'm currently debugging my daemon that supposedly die due to SIGKILL.
I'd like to catch that signal that is intended for my process and add a printout that this process got .
I'm aware that SIGKILL cannot be caught in process level signal handler, so I've decided to use kext.
I've looked in xnu source code and saw that psignal is the method that passes the signal to the target process. However, so I've tried to use trampoline to patch it, but this method is only calls another static method named psignal_internal that is static, and it's probably eliminated by compiler optimization.
perhaps there are other ways to get some sort of mechanism that may help catching this event of sigkill and maybe provide option to set a proper callback function in this case?
thanks

Related

Detect when my Mac app is crashing, then go ahead and crash normally

Normally, when a Mac app gets a crashing signal such as SIGSEGV or SIGILL, the process stops and a few seconds later the OS somehow creates a crash report file and tells the user about it. But if I intercept the signal with a sigaction handler, that normal behavior does not happen. What I would like to do is detect when the crash is happening, do a little work using the few functions that are documented as safe to call in a signal handler, but then go ahead and crash in the normal way. Is there a way to do that? I tried re-raising the signal within the signal handler, but that didn't do the right thing.
I was able to get pretty much the behavior I wanted by ending the signal handler like so, re-sending the signal with default handling:
signal( inSignal, SIG_DFL );
pthread_kill( pthread_self(), inSignal );
usleep( 10000 ); /* give time for signal to happen */
Looking at Apple's source code for abort() help me figure this out.

Interrupt a kernel module when a user process terminates/receives a signal?

I am working on a kernel module where I need to be "aware" that a given process has crashed.
Right now my approach is to set up a periodic timer interrupt in the kernel module; on every timer interrupt, I check the task_struct.state and task_struct.exitstate values for that process.
I am wondering if there's a way to set up an interrupt in the kernel module that would go off when the process terminates, or, when the process receives a given signal (e.g., SIGINT or SIGHUP).
Thanks!
EDIT: A catch here is that I can't modify the user application. Or at least, it would be a much tougher sell to the customer if I place additional requirements/constraints on s/w from another vendor...
You could have your module create a character device node and then open that node from your userspace process. It's only about a dozen lines of boilerplate to register a simple cdev in your module. Your cdev's open method will get called when the process opens the device node and the release method will be called when the device node is closed. If a process exits, either intentionally or because of a signal, all open file descriptors are closed by the kernel. So you can be certain that release will be called. This avoids any need to poll the process status and you can avoid modifying any kernel code outside of your module.
You could also setup a watchdog style system, where your process must write one byte to the device every so often. Have the write method of the cdev reset a timer. If too much time passes without a write and the timer expires, it is assumed the process has somehow failed, even if it hasn't crashed and terminated. For instance a programming bug that allowed for a mutex deadlock or placed the process into an infinite loop.
There is a point in the kernel code where signals are delivered to user processes. You could patch that, check the process name, and signal a condition variable if it matches. This would just catch signals, not intentional process exits. IMHO, this is much uglier and you'll need to deal with maintaining a kernel patch. But it's not that hard, there's a single point, I don't recall what function, sorry, where one can insert the necessary code and it will catch all signals.

ERESTART_RESTARTBLOCK and restart_syscall confusion

It would appear from the source of nanosleep() in kernel/time/hrtimer.c and the manpage of restart_syscall() that to enable nanosleep() to be restarted with the correct timeout after a signal, it saves some state into current_thread_info()->restart_block, returns ERESTART_RESTARTBLOCK and that the signal delivery code would arrange for restart_syscall() to be called after the signal handler returns to do this. However:
There is only space in current_thread_info()->restart_block for one syscall, so what happens in case of recursive signals?
The ARM and x86 signal delivery code resets current_thread_info()->restart_block before a signal handler is called.
The ARM signal delivery code does not arrange for restart_syscall() to be called, instead it sets the return code to -EINTR.
Where is my mistake in the purpose or functioning of this code?
I've worked out that this it to allow a debugger attached using ptrace examine signals and alter the state of the process, and such syscalls return EINTR when interuppted by a signal handler.

linux kernel check if process is still running

I'm working in kernel space and I want to find out when an application has stopped or crashed.
When I receive an ioctl call, I can get the struct task_struct where I have a lot of information regarding the process of the application.
My problem is that I want to periodically check if the process is still alive or better yet, to have some asynchronous call when the process is killed.
My test environment was on QEMU and after a while in the application I've run a system("kill -9 pid"). Meanwhile in the kernel I've had a periodical check on task_struct with:
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
static inline int pid_alive(struct task_struct *p)
The problem is that my task_struct pointer seems to be unmodified. Normally I would say that each process has a task_struct and of course it is corespondent with the process state. Otherwise I don't see the point of "volatile long state"
What am I missing? Is it that I'm testing on QEMU, it is that I've tested checking the task_struct in a while(1) with an msleep of 100? Any help would be appreciated.
I would be partially happy if I could receive the pid of the application when the app is closing the file descriptor of the module ("/dev/driver").
Thanks!
You cannot hive off the task_struct pointer and refer to it later. If the process has been killed, the pointer is no longer valid - that task_struct is gone. You also should not be using PID values within the kernel to refer to processes. PID values are re-used, so you might not even be talking about the same process.
Your driver can supply a .release callback, which will be called when your driver file is closed, including if the process is terminated or killed. You can access current from this callback. Note that if a process opens your file and then forks, the process calling .release could well be different from the process that called .open. Your driver must be able to handle this.
It has been a long time since I mucked around inside the kernel. It seems to me if your process actually dies, then your best bet would be to put hooks into the code that tears down processes. If it doesn't die but gets caught in a non-responsive loop, you'd probably be better off causing an application level core dump.
A solution that worked beautifully in my operating systems homework is to use a kprobe to detect when do_exit is called. What's beautiful is that do_exit will always be called, no matter how the process is closed. I think even in the case of a kernel oops this one will still be called.
You should also hook into _do_fork, just in case.
Oh, and look at the .release callback mentioned in the other answer (do note that dup2 and fork will cause unexpected behavior -- you will only be notified when the last of the copies created by these two is closed).

Best way to handle SIGKILL in Linux kernel

I'm writing a syscall in Linux 3.0, and while I wait for some event to occur (using a waitqueue), I would like to check for a pending SIGKILL and if one occurs, I would like for the current task to die as soon as possible. As far as I can tell, as soon as I return from the syscall (well, really: as soon as the process is to enter into user mode) returns, the kernel checks for pending signals and upon seeing the SIGKILL, the kernel will kill current before it returns to user mode.
Question: Is my above assumption correct about how SIGKILL works? My other option is to see that the fatal SIGKILL is pending, and instead of returning from the syscall, I just perform a do_exit(). I'd like to be as consistent as possible with other Linux use cases...and it appears that simply returning from the syscall is what other code does. I just want to ensure that the above assumption about how SIGKILL kills the task is correct.
Signal checking happens after system call exit, yes.
See e.g. ret_from_sys_call at arch/x86/kernel/entry_64.S.

Resources