Re: Got suggestions to reduce the locks in stacker.c?

From: David Wheeler (dwheelerat_private)
Date: Tue Jul 23 2002 - 14:51:45 PDT

  • Next message: Emily Ratliff: "Why hooks in sys_iopl and sys_ioperm?"

    Crispin Cowan wrote:
    
    > In 1996, I wrote a paper describing how to do exactly that:
    > 
    >    "Fast Concurrent Dynamic Linking for an Adaptive Operating System"
    >    <ftp://cse.ogi.edu/pub/dsrg/synthetix/iccds96.ps.gz>. Crispin Cowan,
    >    Charles Krasic
    >    <http://www.cse.ogi.edu/%7Ekrasic>,
    >    Calton Pu <http://www.cse.ogi.edu/%7Ecalton>, and Jonathan Walpole
    >    <http://www.cse.ogi.edu/%7Ewalpole>. Presented at the /International
    >    conference on Configurable Distributed Systems (ICCDS'96)/, May 6-8,
    >    1996, Annapolis, MD.
    > 
    > What it provides is a funky data structure that looks kinda like a 
    > function pointer, but with asymmetric locking. Locking a function for 
    > *use* (i.e. calling the function) is relatively fast, while locking the 
    > function for *change* (changing the function pointer) is relatively 
    > slow. The fast/call path was measured to be faster than ordinary locks 
    > on the same hardware, for both HP-PA/HPUX, and for x86/Linux.
    > 
    > Recently, I asked Chris Wright to look at this algorithm precisely for 
    > the module unloading problem. Chris's conclusion was that this approach 
    > is not really feasible for mainstream Linux inclusion. The problem is 
    > that the funky Crispy Function Pointers get called from all through the 
    > kernel, and while they are faster than locks, the are a LOT slower than 
    > function calls. Linus is unlikely to accept the overhead that my funky 
    > function calls impose.
    
    This is very interesting, I'll take a look at the paper.
    Even if I don't use them THIS time, I'd want to know about
    these things.  Thanks!
    
    On architectures where writing a pointer
    isn't atomic, the problem is rather pervasive.
    It's not just that UNLOADING is a problem - LOADING _ANY_
    module is a problem.  You can't even load a module by setting
    a single pointer, because
    setting any one pointer to enable the module will race.
    (Set security_ops to the new primary module, an interrupt
    occurs halfway through, another thread tries to call a
    hook and uses a halfway written pointer).  And this would
    affect more than LSM - any module loading could be a disaster.
    
    So - if pointer-writing isn't atomic, the
    current LSM code (and I bet lots of other code!) will
    occasionally follow half a pointer.  That sounds like a problem
    for all of LSM, not just for stacking.
    
    
    >> Forcing a module to "never quite unload" also solves much. 
    > 
    > 
    > That is the approach that I favor: to the extent that unloading requires 
    > locking, don't support unloading. From discussions at Ottawa, this 
    > approach has increasing support among kernel maintainers.
    > 
    > Crispin
    
    I completely agree; I don't see unloading a security module
    as a significant requirement, and would gladly give that
    up for performance.  The current version of stacker has a
    sys_security call that disables unloading.
    
    HOWEVER, that won't help the loading race that occurs even with
    the LSM's loading of a single primary module.
    
    I actually have a race that only affects stacker.c if I remove all locks
    (e.g., needing to turn off the value of pseudo_dummy).
    If pointer writes are atomic, I can solve that by making "dummy"
    part of the list instead of using a separate boolean flag.
    
    I think there are other solutions here to the general
    locking problem for the stacker:
    * There are certainly ways to make the stacking a little more
       static (e.g., specify the list of modules at once, and
       add them as a single step) - though I think module initialization
       may be a very hard problem.  I know that the SELinux folks
       already have some concerns about initialization of the objects that
       exist before SELinux is loaded.
    * Another approach would be to sledgehammer the thing.
       Module loading is a very rare operation, so do nasty things for
       the unusual case.  E.G., suspend all but one CPU, clear interrupts,
       and do anything else necessary to completely 0wn the machine while
       writing the pointer.  This would only be needed for #%$@ chips where
       pointer writes can't be made atomic... for more rationale chips,
       that's not a problem.
    
    BTW, I'm pretty sure all x86-compatible chips
    DO have atomic writes to pointers - but is that true?
    
    Currently, I'm leaning toward writing the code to assume that it can
    atomically write pointers (possibly by sledgehammering).
    
    
    --- David A. Wheeler
         dwheelerat_private
    
    _______________________________________________
    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 : Tue Jul 23 2002 - 14:59:09 PDT