What dose the error code meaning of mac kernel-extension? - macos

I was program a kernel extension about tun on mac, I use a API proto_register_plumber like follows:
err = proto_register_plumber(PF_INET, IFNET_FAMILY_TUN, method_attach, method_detach);
if (err) {
printf("error code is : %d\n", err);
}
On one mac(10.13), it return 17, what it means? how can i fix it?
I read about the API doc on https://developer.apple.com/documentation/kernel/1532491-proto_register_plumber?language=objc, but i do not found anything about what the error code means.

17 is almost certainly an errno, especially as this is from the BSD portion of the KPI. If you look in errno.h you will find that it corresponds to EEXIST:
#define EEXIST 17 /* File exists */
In the context of your API call, this probably means there already is something registered for the thing you're trying to register. I'm not familiar with the proto_register_plumber() function, but a very quick look at its source code reveals the following check near the start of the function, which appears to confirm my suspicion:
lck_mtx_lock(proto_family_mutex);
TAILQ_FOREACH(proto_family, &proto_family_head, proto_fam_next) {
if (proto_family->proto_family == protocol_family &&
proto_family->if_family == interface_family) {
lck_mtx_unlock(proto_family_mutex);
return (EEXIST);
}
}
Could it be that:
You have previously registered the handler, unloaded your kext, which did not unregister it, and then you have reloaded your kext, trying to register it again? In this case, a reboot (and fixing your kext stop function!) should fix it.
Another loaded kext already registers its own handler? If so, try unloading the likely candidates.
The xnu kernel already provides a default handler for this protocol family? Maybe you need to go about what you're trying to do in a different way.

Related

IRQ 8 request_irq, Operation not permitted

I'm new to kernel modules development and in my study process, I moved to the interrupts. My task is to write an interrupt handler module for IRQ 8, which will simply count the number of interrupts that occurred on this line and store the value in the kobject. The task sounds relatively easy at a first glance, but I've encountered strange behaviour. I wrote a handler function that simply increments the counter and returns interrupt as handled
static int ir=0;
static irq_handler_t my_handler(int irq_no, void *dev_id, struct pt_regs *regs)
{
ir++;
return (irq_handler_t) IRQ_HANDLED;
}
To hook the interrupt handler I call the request_irq() function inside my __init with the first argument being 8, so the IRQ 8 (which is reserved by rtc) line interrupts are handled
#define RTC_IRQ 8
[...]
int err;
err = request_irq(RTC_IRQ, (irq_handler_t) my_handler,IRQF_SHARED,"rtc0",NULL);
if (err != 0)
return -1;
With the implementation shown above, loading a kernel module gives me err equal to -22, which is EINVAL. After googling I discovered that for the IRQF_SHARED flag last parameter can't be assigned as NULL. I tried to find a method to obtain rtc->dev_id within the module, but in some of the examples they just typecasted the handler into (void *) so I tried passing (void *) my_handler. This gives me a flag mismatch warning on insmod
genirq: Flags mismatch irq 8. 00000080 (rtc0) vs. 00000000 (rtc0)
And err value set to -16, what I read from some sources means "busy". While trying to find a way to obtain a device-id I found out that interrupt is sent by the rtc0 device which is "inherited" from the rtc-cmos parent.
There are different controversial clues I found in different sources across the internet on this matter. Some state that the kernel disables rtc after the synchronization of the software clock, but this can't be the case, since the use of sudo bash -c ' echo +20 > /sys/class/rtc/rtc0/wakealarm ' and read of /proc/interrupts on the IRQ 8 line shows that interrupts are working as intended
Other sources state that all the request_irqs directed to the line must have the IRQF_SHARED flag installed to be able to share the interrupt line. Reading the source file for rtc-cmos gave me nothing since they are setting up interrupts via reading-writing CMOS directly
I spent a lot of time trying to figure out the solution to the problem, but it seems like the RTC interrupts aren't commonly used in a kernel modules development, so finding relevant and recent information on the case is difficult, most of the discussions and examples are related to the implementation when SA_SHIRQ-like flags were used and /drivers/examples folder was present in the kernel source files which is something around kernel version 2.6. And both interrupts and rtc kernel implementation were changed since those times
Any hints/suggestions that may help resolve this issue will be greatly appreciated. This is my first StackOverflow question, so if anything in its format is wrong or disturbing you are welcome to point it out in the comments as well
Thanks in advance for any help
I solved the problem quite a while ago now, but here's some explanation for newbies like me. #stark provided a good hint for the problem.
The main thing to understand is that irresponsible actions in the kernel space quickly lead to a "disaster" of sorts. Seemingly, this is the main reason Linux developers are closing more and more regions from the users/developers.
Read here for the solution
So, in modern kernel versions, you don't randomly tie the handler to a line and mark interrupts as resolved. But you still can "listen" to them using the IRQF_SHARED flag and at the end of your handler you let the interrupt untouched by returning IRQ_NONE, so you are not breaking the correct operation of the rest of the kernel if the interrupt is crucial for something else.
End of the solution, some extra advice on kernel development next
At the very start, it is important to understand that this is not a Userspace where your actions at most will lead to a memory leakage or corruption of some files. Here your actions will easily damage your kernel. If a similar scenario happened to Windows, you'll have no other choice than completely reinstalling the entire OS, but in GNU/Linux this is not really the case. You can swap to a different kernel without the need to go through a tedious process of recovering everything as was before, so if you are a hardcore enthusiast that's too lazy to use VMs, learning to swap kernels, will come in handy real soon:)

Crash while accessing Address passed via ioctl in linux kernel

I am passing pointer to below structure through ioctl.
typedef struct myparam_t {
int i;
char *myname;
}myparam;
I allocate memory for myname in the user space before passing the argument.
In the ioctl implementation at kernel space I use copy_from_user() to copy the argument in kspace variable (say kval). call is like copy_from_user(kval,uval,sizeof(myparam)); kval & uval are of myparam * type.
Now in ioctl function I have check like -
if (uval->myname != NULL) {
}
I thought this will result in to kernel crash or panic due to page fault.
However I see different behaviour with different version of kernel.
With 4.1.21 kernel I see no issue with NULL check, But with 4.10.17 kernel I see a page fault that results in to kernel panic.
My question is what might make NULL check working in kernel 4.1.21 ?
Is there a way I can make same code working for 4.10.17 as well ?
Note that I am facing this issue as part of kernel migration. We are trying to migrate from version 4.1.21 to 4.10.17. There may be many instance of such usage in our code base. Hence, if possible, I'd prefer to put a patch in kernel to fix the issue, rather than fixing all such instance.
Thanks
Dipak.

Regarding msgrcv in android-kernel?

I was running a test suite for testing IPC related functionality in android kernel. while I was testing msgrcv system call , it return error function not implemented.
So is it true msgrcv() system call not implemented in android-kernel, if so why and which system call in android kernel serve purpose of msgrcv() system call.
I got related statement which says System V IPCs (including message queues) are not implemented on Bionic. but not sure what does it mean.
Update : I am able to find definition of msgrcv in android kernel , but not sure why it is returning error function not implemented.
Below code snippet :
SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
long, msgtyp, int, msgflg)
{
return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill);
}
Please comment if information seems incomplete or vague ,Help is appreciated.
System V IPC may be available in the kernel but system call interfaces are not implemented in Bionic lib C. For Example, /bionic/libc/arch-arm/syscalls/ contains all system call implementations with respect to ARM.

Shutting down Windows from kernel mode?

I'm trying to create a driver that will intercept a certain key sequence and perform a reboot from kernel mode in Windows, similarly to the REISUB key sequence in Linux.
I've created a keyboard hook just like Ctrl2Cap does, and I've tried calling NtShutdownSystem to reboot the system.
The handler does detect the key press, but the problem is that when it actually calls NtShutdownSystem, I get a BSOD with the ATTEMPTED_SWITCH_FROM_DPC error code.
I'm assuming this is because I can't shut down the system from an executing DPC, so I probably need to execute my code from somewhere else.
But I don't know where.
So the question is:
How can I shut down the system upon detecting the key sequence in kernel mode?
Ah, I figured out the answer....
Seems like ExQueueWorkItem does the trick:
VOID NTAPI MyShutdownSystem(PVOID) { NtShutdownSystem(1); }
// ... [code] ...
PWORK_QUEUE_ITEM pWorkItem =
(PWORK_QUEUE_ITEM)ExAllocatePool(NonPagedPool, sizeof(WORK_QUEUE_ITEM));
if (pWorkItem != NULL) {
ExInitializeWorkItem(pWorkItem, &MyShutdownSystem, NULL);
ExQueueWorkItem(pWorkItem, DelayedWorkQueue);
}

Problem with .release behavior in file_operations

I'm dealing with a problem in a kernel module that get data from userspace using a /proc entry.
I set open/write/release entries for my own defined /proc entry, and manage well to use it to get data from userspace.
I handle errors in open/write functions well, and they are visible to user as open/fopen or write/fwrite/fprintf errors.
But some of the errors can only be checked at close (because it's the time all the data is available). In these cases I return something different than 0, which I supposed to be in some way the value 'close' or 'fclose' will return to user.
But whatever the value I return my close behave like if all is fine.
To be sure I replaced all the release() code by a simple 'return(-1);' and wrote a program that open/write/close the /proc entry, and prints the close return value (and the errno). It always return '0' whatever the value I give.
Behavior is the same with 'fclose', or by using shell mechanism (echo "..." >/proc/my/entry).
Any clue about this strange behavior that is not the one claimed in many tutorials I found?
BTW I'm using RHEL5 kernel (2.6.18, redhat modified), on a 64bit system.
Thanks.
Regards,
Yannick
The release() isn't allowed to cause the close() to fail.
You could require your userspace programs to call fsync() on the file descriptor before close(), if they want to find out about all possible errors; then implement your final error checking in the fsync() handler.

Resources