Karym Yaghmour alerted me to this discussion and I'm grateful to him as I believe many of the issues being discussed for a hooking mechanism have been addressed by the Generalised Kernel Hooks Interface (GKHI) we have been developing. The terminology I'm using here is that a hook is the location in the kernel where a hook exit may optionally receive control. Some of the particular issues that have arisen in these discussions, which GKHI addresses, are: 1) The ability to make a decision on return from the hook exit. 2) Minimal performance overhead for both dormant and active hooks. 3) Minimal overhead for the co-existence of large numbers hooks. 4) Use of a code-patching implementation as opposed to a bit-mask approach. 5) Ability to have multiple exits driven from any given hook - for security that means multiple co-existing security implementers. The particular features of GKHI which seem to address these concerns are: 1) There is a dispatching mechanism per hook that is coded in the same routine as the hook but out of line to minimise cache impact to dormant hooks. It's also implemented as a single macro to keep the code looking reasonably clean. 2) The dispatching overhead is independent of the number of hooks because there is a dispatcher per hook and the dispatcher is essentially a for loop with a subroutine call. 3) The hook adds two consecutive jumps instructions to the existing code path. Hook activation, which happens when at least one exit for that hook is armed, amounts to no-oping the first of the two jump instructions. However we no-op by a single byte store (of zero) to alter the jump target to the next instruction. This makes it atomic under MP and avoids inter-processor serialisation overheads. The execution overhead for an inactive hook is one addition jump instruction. 4) Parameters in the form of local and global variables may be passed from the hooked code to the hook exits and back to the hooked code. This allows mainline processing to be modified based on the actions of the exit. 5) Multiple hook exits may exist for a given hook. Each time that hook's dispatcher is invoked it will conditionally continue dispatching exists for that hook based on the return code from the previous exit. 6) We are working on an extension to the hook dispatcher that will allow the hook exit to specify whether the hooked subroutine should return immediately. This will avoid the need to envelope the hook macros with conditional logic to achieve the same thing. 7) Hook exits are activated as a two-stage process: Registration - which makes the hooking mechanism aware of the existence of a hook exit address and establishes a dispatching priority for that exit. Exits can specify first, last, only or don't care where in the dispatching order. Arming - which enables the exit to be dispatched. Multiple hook exits may be armed atomically. The reverse of these operations is supported: disarming and deregistration. Also disarming may be done automatically by the exit when it returns to the dispatcher. 8) There's a hook interface module that provides the registration, arming, disarming and deregistration services. There's no reason why that function should not become embedded in the kernel since it would be advantageous where early hook exit registration is required. 9) The interface module can be notified of the presence of a hook via an API. This allows kernel modules to identify the existence of a hook at some point when they choose. 10) Adding hooks to kernel modules requires no recompilation of the kernel or the hook interface module. 11) Adding new hook locations to the kernel requires only that the kernel is updated with a one-line hook macro at that location. There's no need to recompile the kernel when new kernel modules have a need to register for existing hooks. 12) We had conceived this generic mechanism initially to allow serviceability tools to be added dynamically with minimum overhead, and as such this seems to be a very similar requirement to those of security extensions to the kernel. 13) An example of coding a hook macro could be: int do_execve(...) { struct file_struct *file; : : GKHOOK_1VAR(EXECVE_HOOK, file); : : } Note that hooks are currently identified by a number, the next version will have names for hook identification. Now, the security module does: gkhookrec hookstruct; : init_module { int rc; : hookstruct.hkExit = & execve_handler; gkh_register(EXECVE_HOOK, &hookstruct); : rc= GKH_arm(&hookstruct); : } and implements the function: int execve_handler(struct file_struct *file) If in addition this hook needs to be implemented with the ability to terminate do_execve() for certain policy reasons, it can be done by using the conditional return version of the hook macro: GKHOOK_1VAR_RET(EXECVE_HOOK, file); int execve_handler(int *retcode, struct file_struct *file) { return GKH_RETURN; } The possible return values from a hook handler of this type are: #define GKH_CONTINUE 0 /* execute remaining handlers */ #define GKH_TERMINATE 1 /* don't execute remaining handlers */ #define GKH_RETURN -1 /* return from the hooked routine, do_execve, with retcode */ 14) What we have currently on our web site is an early version which we have refined considerably and hope to release during the next month. If this seems to be the right approach for security we would be happy to work with the security community to adapt GKHI to your needs. Richard Moore - RAS Project Lead - Linux Technology Centre (ATS-PIC). http://oss.software.ibm.com/developerworks/opensource/linux Office: (+44) (0)1962-817072, Mobile: (+44) (0)7768-298183 IBM UK Ltd, MP135 Galileo Centre, Hursley Park, Winchester, SO21 2JN, UK _______________________________________________ linux-security-module mailing list linux-security-moduleat_private http://mail.wirex.com/mailman/listinfo/linux-security-module
This archive was generated by hypermail 2b30 : Thu Apr 26 2001 - 02:27:51 PDT