How to detect application terminate in kernel extension, Mac OS X - macos

I am looking for an approach to detect application quit (e.g. cmd-q) in kernel space for processing in a network kernel extension.
More precisely:
While a process (e.g. terminal ping) is held in an IOLockSleep(... THREAD_ABORTSAFE), ctrl-c is able to release the lock.
Asking the proc_issignal(), it responses the sigmask(SIGINT).
Now I am looking for a way to detect another process quit, e.g. firefox (menu bar: Application quit (cmd-q)).
Here is what I tried:
#define FLAG(X) ((dispatch_source_get_data(src) & DISPATCH_PROC_##X) ? #X" " : "")
struct ProcessInfo {
int pid;
dispatch_source_t source;
};
// function called back on event
void process_termination_event(struct ProcessInfo* procinfo) {
dispatch_source_t src = procinfo->source;
printf("process_termination_event: %d \n", procinfo->pid);
printf("flags: %s%s\n", FLAG(EXIT), FLAG(SIGNAL));
dispatch_source_cancel(procinfo->source);
}
// function called back when the dispatch source is cancelled
void process_termination_finalize(struct ProcessInfo* procinfo) {
printf("process_termination_finalize: %d \n", procinfo->pid);
dispatch_release(procinfo->source);
}
// Monitor a process by pid, for termination
void MonitorTermination(int pid) {
struct ProcessInfo* procinfo = (struct ProcessInfo*)malloc(sizeof(struct ProcessInfo));
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t dsp = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, pid, DISPATCH_PROC_EXIT|DISPATCH_PROC_SIGNAL, queue);
procinfo->pid = pid;
procinfo->source = dsp;
dispatch_source_set_event_handler_f(procinfo->source, (dispatch_function_t)process_termination_event);
dispatch_source_set_cancel_handler_f(procinfo->source, (dispatch_function_t)process_termination_finalize);
dispatch_set_context(procinfo->source, procinfo);
dispatch_resume(procinfo->source);
}
int main(int argc, const char * argv[])
{
for (int i = 0; i < argc; ++i) {
pid_t pid = atoi(argv[i]);
printf("MonitorTermination: %d\n", pid);
fflush(stdout);
MonitorTermination(pid);
}
CFRunLoopRun();
return 0;
}
The process_termination_event will not invoke after cmd-q as explained above. Even after force quit.
The process itself is held in a loop within the network kernel extension function:
errno_t KEXT::data_out(void *cookie, socket_t so, const struct sockaddr *to, mbuf_t *data, mbuf_t *control, sflt_data_flag_t flags)
{
// at this point I would like to detect the app quit/termination signal.
while(PROCESS_IS_NOT_TEMINATING); // <-- pseudo code, actually held with IOLockSleep...
return 0;
}
I would really appreciate any help! Thanks in advance.

It may not be the way you've been thinking, but if you're in the kernel space, then I assume you're writing a kernel extension (kext). With a kernel extension, you can monitor Vnodes for executing applications. You may be able to use the File Scope instead.
In conjunction with a user-level application (daemon), the kext notifies the daemon that a process has begun execution and then monitors the termination of the launched application from the user-level daemon, using Grand Central Dispatch functions. If required, the user-application can notify the kext of the terminated app.
To monitor the termination from a user-level application, you can do something like this when you're notified of an application being executed: -
// pid and path provided from vNode scope kext...
void UserLevelApp::MonitorProcessTermination(int pid, const QString &path)
{
ProcessInfo* procinfo = new ProcessInfo;
procinfo->pid = pid;
procinfo->path = path;
procinfo->context = this;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t dsp = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, pid, DISPATCH_PROC_EXIT, queue);
dispatch_source_set_event_handler_f(dsp, (dispatch_function_t)process_termination_event);
dispatch_source_set_cancel_handler_f(dsp, (dispatch_function_t)process_termination_finalize);
procinfo->source = dsp;
dispatch_set_context(dsp, procinfo);
dispatch_resume(dsp);
}
// app terminated call-back function
void UserLevelApp::process_termination_event(struct ProcessInfo* procinfo)
{
dispatch_source_cancel(procinfo->source);
// example of how to use the context to call a class function
procinfo->context->SomeClassFunction(procinfo->pid, procinfo->path);
qDebug("App Terminated: %d, %s\n", procinfo->pid, procinfo->path.toUtf8().data());
}
// finalize callback function
void UserLevelApp::process_termination_finalize(struct ProcessInfo* procinfo)
{
dispatch_release(procinfo->source);
delete procinfo;
}
So each launched application, notified by the kext, has an event handler associated with it and when the application terminates, you get called back in the registered functions process_termination_event and process_termination_finalize
Whilst this method requires an associated user-level daemon application with the kext, that's not such a bad thing from a security and stability point of view.

Related

porting sd-bus event to libev

The sd-event is a event loop framework similar to libev, libuv, libevent, etc, I need to implement libev event loop for monitoring services. All the man pages I can find talk about the use of sd_bus_get_fd(), sd_bus_get_events() and sd_bus_get_timeout(), for example, on this page. Does anyone have a project example for using those three functions?
Don't have anything for libev but for libevent + sdbus , it goes something like this
//Global
static sd_bus *bus = NULL;
static struct event_base *base = NULL;
void bus_process(evutil_socket_t fd, short what, void *arg) {
sd_bus_process(bus, NULL);
}
void main() {
sd_bus_default_system(&bus);
sd_bus_request_name(bus, BUS_NAME, 0);
int fd = 0;
int events = 0;
uint64_t usec;
struct event *ev_read;
base = event_base_new()
fd = sd_bus_get_fd(bus);
events = sd_bus_get_events(bus);
sd_bus_get_timeout(bus, &usec);
evutil_make_socket_nonblocking(fd);
ev_read = event_new(base, fd, EV_READ|EV_PERSIST, bus_process, NULL);
event_add(ev_read, NULL);
event_base_dispatch(base);
// wont get here, loop is now running and processing
return;
}

How does linux (reboot) notifier list work?

I am testing the reboot notifier hook on Linux kernel 5.8 running on QEMU ARM64 with busybox rootfs. This is my first time using a notifier list, so I might be wrong. I have add one reboot notifier which is executed well, but I have also added a second item to the list using .next and the handler of this notifier does not execute. Here's the snippet from my dummy driver:
static int reboot_handler_first(struct notifier_block *this, unsigned long action,
void *data)
{
printk(KERN_INFO "first reboot notifier called\n");
return 0;
}
static int reboot_handler_second(struct notifier_block *this, unsigned long action,
void *data)
{
printk(KERN_INFO "second reboot notifier called\n");
return 0;
}
static struct notifier_block reboot_notifier_second = {
.notifier_call = reboot_handler_second,
.next = NULL,
.priority = INT_MAX,
};
static struct notifier_block reboot_notifier_first = {
.notifier_call = reboot_handler_first,
.next = &reboot_notifier_second,
.priority = INT_MAX,
};
Here, the reboot_handler_first() gets called but I do not see any log from reboot_handler_second(). I was expecting that reboot_notifer_first() will trigger reboot_notifier_second() but that does not seem to be the case. Am I missing anything?
Below are the logs that I see with this kernel and busybox rootfs:
/ # reboot
/ # umount: devtmpfs busy - remounted read-only
swapoff: can't open '/etc/fstab': No such file or directory
The system is going down NOW!
Sent SIGTERM to all processes
Sent SIGKILL to all processes
Requesting system reboot
[ 20.158023] first reboot notifier called
[ 20.232718] reboot: Restarting system
[ 0.000000] Booting Linux on physical CPU 0x0000000000 [0x411fd070]
EDIT
This is how my module_init(hello_init) function looks like. I have registered only the first reboot notifier reboot_notifier_first and then set its next to point to the reboot_notifier_second. Please correct me. My understanding is that I need to register the first notifier with register_reboot_notifier() and then I just need to set the .next of current notifier_block to add new nodes to the linked list. This way I will get a chain of notifier blocks.
static int __init hello_init(void)
{
int rc;
rc = register_reboot_notifier(&reboot_notifier_first);
printk(KERN_INFO "This is from init\n");
return 0;
}

Win32 C++ using HWND in separate file/thread to start timer

Background:
Application Type: Win32 Application
Language: C++ (with C functions as well)
Problem: Want to use main Window Handle in another file.
Update 1: Using a TCP server in another thread. This server receives information from a client and then needs to start a timer in the program.
Project Layout:
Main File: main.cpp/main.h which has WinMain, WndProc, etc.
Other Generated Files: Resource.h, main.rc, stdafx.h etc generated by Visual Studio
Self Made Files: functions.cpp/functions.h & calculation.cpp/calculation.h
Update 1: Server thread is in the main.cpp file and the call to start the timer is made on the server thread. I also updated some of the code to more accurately reflect what I have.
Info:
Can I call SetTimer(hwnd, TIMER_INT, TIMER_INTERVAL, NULL) in the calculation.cpp file in some way and make the TIMER_INT timer trigger in the WndProc for WM_TIMER?
So for example (of course foo is defined in calculation.h, etc. for other functions).
//calculation.cpp
void foo(HWND hwnd)
{
SetTimer(hwnd, TIMER_INT, TIMER_INTERVAL, NULL);
}
//functions.cpp
void ThreadStart()
{
/* This code initializes a working server that is visible to main.cpp */
/* The Server socket and Accept socket are extern for main.cpp */
}
//main.cpp
HWND hwnd;
int WinMain(...)
{
//... Set hwnd here
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, ...)
{
static PARAMS params; //Thread params
switch(message)
{
case WM_CREATE:
//This initializes a blocking Server (which works)
params.hwnd = hWnd;
params.bContinue = TRUE;
_beginthread(ThreadServer, 0, &params);
break;
case WM_TIMER:
case TIMER_INT:
MessageBox(NULL, L"Timer was triggered from foo", L"FOO", NULL);
//continuous messageboxes will appear based on TIMER_INTERVAL if it works...
break;
break;
}
}
void ThreadServer(PVOID pvoid)
{
ThreadStart(); //calls accept() until client connects
while(1)
{
memset(&RecvBuffer[0], 0, 512 * sizeof(RecvBuffer[0])); //Clear recv
TCPServer.iRecv = recv(AcceptSocket, RecvBuffer, iRecvBuffer, 0);
if(strlen(RecvBuffer) > 1){
memset(&SendBuffer[0], 0, 512 * sizeof(SendBuffer[0]));
//Clears SendBuffer
std::string retString = "";
retString = process(RecvBuffer); //processes RecvBuffer
if(condition == true){
foo(hwnd);
}
if(strlen(retString.c_str()) > 0){
TCPServer.iSend = send(AcceptSocket, retString.c_str(), strlen(retString.c_str()), 0);
}else{
retString = "";
TCPServer.iSend = send(AcceptSocket, retString.c_str(), strlen(retString.c_str()), 0);
}
if(TCPServer.iSend == SOCKET_ERROR){
break;
}
}
//Determine if socket fails and breaks if failure occurs
//*
memset(&SendBuffer[0], 0, 512 * sizeof(SendBuffer[0]));
TCPServer.iSend = send(AcceptSocket, SendBuffer, iSendBuffer, 0);
if(TCPServer.iSend == SOCKET_ERROR){
break;
}//*/
Sleep(1);
}
}
The issue is trying to pass a reference to hwnd to calculation.cpp from the server thread. I can pass hwnd to the function foo(HWND), but the timer does not set. Is there a way to set a timer in a separate thread or is this not possible? Is there any other workaround to this with using winsock and a server?
As the document state that you can't create a timer for a window from a different thread. For you the different thread is the server thread.
Maybe you can post WM_TIMER message (PostMessage) to the main thread from the server thread when the timer timeout.
Or you need Synchronization Objects for threads synchronicity.

Linux device driver for a Smart Card IC module

I have a smart card IC module, and I want to create a Linux device driver for it. This module is using SPI as the controlling line and has an interrupt line to indicate whether a card is ready. I know how to create a SPI device in Linux kernel and how to read data in the kernel when the interruption happens. But I have no idea on how to transfer the data to the user space (maybe need to create a device node for it), and how to give the user space a interruption to notify it. Does anyone have some suggestion?
One way you can go about this is by creating a devfs entry and then having the interested process open that device and receive asynchronous notification from the device driver using fasync.
Once you have the notification in user space you can notify other interested processes by any means you deem fit.
I am writing a small trimmed down example illustrating this feature.
On the driver side
/* Appropriate headers */
static int myfasync(int fd, struct file *fp, int on);
static struct fasync_struct *fasyncQueue;
static struct file_operations fops =
{
.open = charDriverOpen,
.release = charDriverClose,
.read = charDriverRead,
.write = charDriverWrite,
.unlocked_ioctl = charDriverCtrl,
// This will be called when the FASYNC flag is set
.fasync = myfasync,
};
static int __init charDriverEntry()
{
// Appropriate init for the driver
// Nothing specific needs to be done here with respect to
// fasync feature.
}
static int myfasync(int fd, struct file *fp, int on)
{
// Register the process pointed to by fp to the list
// of processes to be notified when any event occurs
return fasync_helper(fd, fp, 1, &fasyncQueue);
}
// Now to the part where we want to notify the processes listed
// in fasyncQueue when something happens. Here in this example I had
// implemented the timer. Not getting in to the details of timer func
// here
static void send_signal_timerfn(unsigned long data)
{
...
printk(KERN_INFO "timer expired \n");
kill_fasync(&fasyncQueue, SIGIO, POLL_OUT);
...
}
On the user land process side
void my_notifier(int signo, siginfo_t *sigInfo, void *data)
{
printf("Signal received from the driver expected %d got %d \n",SIGIO,signo);
}
int main()
{
struct sigaction signalInfo;
int flagInfo;
signalInfo.sa_sigaction = my_notifier;
signalInfo.sa_flags = SA_SIGINFO;
sigemptyset(&signalInfo.sa_mask);
sigaction(SIGIO, &signalInfo, NULL);
int fp,i;
fp = open("/dev/myCharDevice",O_RDWR);
if (fp<0)
printf("Failed to open\n");
/*New we will own the device so that we can get the signal from the device*/
// Own the process
fcntl(fp, F_SETOWN, getpid());
flagInfo = fcntl(fp, F_GETFL);
// Set the FASYNC flag this triggers the fasync fops
fcntl(fp, F_SETFL, flagInfo|FASYNC);
...
}
Hope this clears things up.
For more detailed reading I suggest you read this

Hooking into message pump of STA Apartment COM object activated in DllHost by DllSurrogate

I have a fairly complex requirement. My STA COM object is implemented in a DLL (can't move it to out-of-process EXE). By the means of DllSurrogate I am hosting my object in a dllhost.exe process. My object has an UI attached to it (a plain modeless dialog) but I need the PreTranslateAccelerator mechanism in order for some shortcuts to work, etc. Since COM activates my object and hosts it in the default dllhost.com, I am obviously not controlling the message pump.
Is there still a way to pre-translate messages in this scenario? I doubt COM has foreseen such a specific scenario but maybe I am missing something.
Okay here it is. I hope I didn't leave out anything important. Basically, I have created a custom CMyComCreator instead of the default one. Instead of just creating a COM object and returning an interface pointer, I spin a worker UiThread. I use MyData structure to pass data across threads. Once the worker thread has finished setting up, I use the CComGITPtr to transfer the marshalled interface pointer from the UiThread back to the main. The consumers (out-of-process) end up with interface pointers that talk directly to the UiThread bypassing the main thread. You may think of CMyDialog as a modeless dialog which sends a PostQuitMessage on destruction to terminate the message loop. That's all. May look cumbersome but it works good.
struct MyData
{
ATL::CComGITPtr<IUnknown> Unk;
ATL::CEvent Event;
HRESULT hr;
MyData() : hr(E_OUTOFMEMORY), Event(FALSE, FALSE) { }
};
static CMessageLoop * MessageLoop;
class CMyComCreator
{
public:
static HRESULT WINAPI CreateInstance(
_In_opt_ void* pv,
_In_ REFIID riid,
_COM_Outptr_ LPVOID* ppv)
{
ATLASSERT(ppv != NULL);
if (ppv == NULL)
return E_POINTER;
*ppv = NULL;
HRESULT hRes = E_OUTOFMEMORY;
MyData* data = NULL;
ATLPREFAST_SUPPRESS(6014 28197)
/* prefast noise VSW 489981 */
ATLTRY(data = _ATL_NEW MyData)
ATLPREFAST_UNSUPPRESS()
if (data != NULL)
{
HANDLE thread = (HANDLE)_beginthreadex(NULL, 0, UiThread, (void *)data, 0, NULL);
if (thread)
{
WaitForSingleObject(data->Event, INFINITE);
CloseHandle(thread);
hRes = data->hr;
if (SUCCEEDED(hRes))
{
ATL::CComPtr<IUnknown> unk;
hRes = data->Unk.CopyTo(&unk);
if (SUCCEEDED(hRes))
{
hRes = unk->QueryInterface(riid, ppv);
}
}
}
delete data;
}
return hRes;
}
};
typedef CMyComCreator _CreatorClass;
static unsigned __stdcall UiThread(void * param)
{
CoInitializeEx(0, COINIT_APARTMENTTHREADED);
MyData * data = (MyData *)param;
ATL::CComObject<CMyDialog> * bb;
data->hr = ATL::CComObject<CMyDialog>::CreateInstance(&bb);
ATL::CComPtr<IUnknown> unk((IDispatch *) bb);
data->Unk = unk;
unk.Release();
data->Event.Set();
if (SUCCEEDED(data->hr))
{
CMessageLoop theLoop;
MessageLoop = &theLoop;
int nRet = theLoop.Run();
MessageLoop = NULL;
}
CoUninitialize();
return 0;
}
I needed to pack everything in a single DLL.
In which case, DllSurrogate is not the only way of doing this. There's also Rundll32:
INFO: Windows Rundll and Rundll32 Interface
This would allow you to run your own message loop inside the DLL's EntryPoint and have complete control over message processing, including PreTranslateMessage. You can copy the message loop logic from an ATL EXE server.
Bear in mind, there's still 32-bit and 64-bit version of "RunDll32.exe" in every 64-bit Windows OS. Use the one which matches the bit-ness of your DLL.

Resources