I agree with Andrew Morgan <morganat_private>'s proposal to use C preprocessor macros to implement hook insertions and returns. That way, you can optimize differently for different processor types and implement rival designs. In addition, Linus has previously stated that he does NOT want code littered with #ifdef's.. if you need multiple #ifdefs that do the same thing, he'd prefer to have it hidden in a macro call. That way, the #ifdef is confined to a single location (the macro definition). The main reason to do this, however, would be so that you can separate HOW hooks are implemented from the decision on WHERE to put them. And frankly, it appears that there are LOTS of ways to implement hooks, and which is better is almost certainly architecture-dependent. For many pipelined systems, any insertion of a branch is likely to cause a stall... unless it does speculative execution & has the resources to do it... unless, unless, unless. Here are a few implementation possibilities that I see for hooks (there are probably more), which argues for encapsulating the hook mechanism to permit compile-time selection the best mechanism: Option 1: ALWAYS call a function, which may just return. err = security_ops->ioperm(); Option 2: Call the function only if non-null err = security_ops->ioperm ? security_ops->ioperm() : 0; /* If resulting branch causes a stall, this could be worse, but by avoiding the call setup & execution, this may be better. The compiler should optimize this so retrieval of "security_ops->ioperm" will actually occur only once, though I haven't checked this. */ Option 3: Replace with NOPs at load time. /* For each hook, on start-up replace with NOPs and store "original" values; when a hook is invoked, re-insert the original code. */ Option 4: Replace JSR with uninteresting operation. /* For each hook, replace the CPU's "jump to subroutine" call with an operation that does something worthless. Advantage: don't need to store original values or subroutine setup/destruction in a separate area. Disadvantage: probably not as fast as a NOP */ Option 5: Insert a jump to another location. /* When the hook is enabled, copy the relevant operation elsewhere, add the relevant subroutine calls, and insert a jump. This would be the absolute fastest for unused hooks -- literally absolutely NO performance hit -- but the hit for _used_ hooks would be higher, since jumps usually flush instruction caches & that would happen on both call and return. */ The nice thing about encapsulating the hook implementation is that you can start work with something simple (#1 or #2), then move to more complex approaches if desirable. Makes benchmarking more realistic too, and benchmarks would be needed for a decision (for a given architecture). > Crispin Cowan wrote: > > > > I think that the self-modifying-code approach is likely to bounce, as it > > completely breaks on ROM'd systems. With Linux's current momentum into embedded > > space, I suspect that self-modifying code would be rejected out of hand. That's a valid point. I would say, then, that a non-self-modifying approach would at least need to be available. However, it's my understanding that few systems actually _RUN_ out of their ROMs. So, if you separate the hook _implementation_ from the hook placement, you can have various hook implementation options. _______________________________________________ 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 19 2001 - 08:22:15 PDT