Domanda

I have to write LKM, that intercepts some syscalls. Solution is to:

  1. Find address of sys_call_table symbol, check if address is correct(checking for example that sys_call_table[__NR_close] points to address of sys_close)
  2. Disable interrupts
  3. Disable WP bit in CR0
  4. Change sys_call_table[__NR_close] to my own function
  5. Enable WP bit
  6. Enable interrupts. Loading of module works fine.

But, what about safe unloading of module?

Consider situation when I restore sys_call_table to it's original state and module is unloaded - what if kernel is still executing code from my module in context of syscall of other process on other CPU? I will get page fault in kernel mode(because pages with code segment of module are no more available, as module was unloaded). The shared resource is entry in sys_call_table. If I can made access to this entry protected by locks - then I can safely unload my module.

But, since kernel system call handler doesn't have any of this locks(e.g.arch/x86/kernel/entry_32.S) - it means that there is no safe way of unloading my module? Is it true?

UPDATE1

I need to get information about file accesses on old kernels(where fanotify(2) is not available), starting from 2.4 kernel version. I need this information to perform on access scanning through antivirus engine.

È stato utile?

Soluzione

You're correct that there is no safe way to unload your module once you've done this. This is one reason why replacing/wrapping system call table entries this way is frowned upon.

In most recent versions, sys_call_table is not an exported symbol -- at least in part to discourage this very thing.

It would be possible in theory to support a more robust system call replacement mechanism but the kernel maintainers believe that the whole concept is so fraught with the potential for errors and confusion that they have declined to support it. (A web search will show several long-ago debates about this subject on the linux kernel mailing list.)

(Speaking here as one who used exactly the same technique several years ago.)

You can of course do it anyway. Then, you can either "just risk" unloading your module - and hence potentially causing a kernel panic (but of course it will likely work 99% of the time). Or you can not allow your module to be unloaded at all (requiring a reboot in order to upgrade or uninstall).

Altri suggerimenti

At the end of the uninit function in your kernel module, you can wait till all your custom hooks end. This can be achieved using counters. Increment the counter when your custom hook is hit, decrement it right before it returns. When the counter hits zero, only then return from the uninit function. You will also need locking on the counter variable.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top