Skip to content
  • David Howells's avatar
    KEYS: Fix multiple key add into associative array · 23fd78d7
    David Howells authored
    
    
    If sufficient keys (or keyrings) are added into a keyring such that a node in
    the associative array's tree overflows (each node has a capacity N, currently
    16) and such that all N+1 keys have the same index key segment for that level
    of the tree (the level'th nibble of the index key), then assoc_array_insert()
    calls ops->diff_objects() to indicate at which bit position the two index keys
    vary.
    
    However, __key_link_begin() passes a NULL object to assoc_array_insert() with
    the intention of supplying the correct pointer later before we commit the
    change.  This means that keyring_diff_objects() is given a NULL pointer as one
    of its arguments which it does not expect.  This results in an oops like the
    attached.
    
    With the previous patch to fix the keyring hash function, this can be forced
    much more easily by creating a keyring and only adding keyrings to it.  Add any
    other sort of key and a different insertion path is taken - all 16+1 objects
    must want to cluster in the same node slot.
    
    This can be tested by:
    
    	r=`keyctl newring sandbox @s`
    	for ((i=0; i<=16; i++)); do keyctl newring ring$i $r; done
    
    This should work fine, but oopses when the 17th keyring is added.
    
    Since ops->diff_objects() is always called with the first pointer pointing to
    the object to be inserted (ie. the NULL pointer), we can fix the problem by
    changing the to-be-inserted object pointer to point to the index key passed
    into assoc_array_insert() instead.
    
    Whilst we're at it, we also switch the arguments so that they are the same as
    for ->compare_object().
    
    BUG: unable to handle kernel NULL pointer dereference at 0000000000000088
    IP: [<ffffffff81191ee4>] hash_key_type_and_desc+0x18/0xb0
    ...
    RIP: 0010:[<ffffffff81191ee4>] hash_key_type_and_desc+0x18/0xb0
    ...
    Call Trace:
     [<ffffffff81191f9d>] keyring_diff_objects+0x21/0xd2
     [<ffffffff811f09ef>] assoc_array_insert+0x3b6/0x908
     [<ffffffff811929a7>] __key_link_begin+0x78/0xe5
     [<ffffffff81191a2e>] key_create_or_update+0x17d/0x36a
     [<ffffffff81192e0a>] SyS_add_key+0x123/0x183
     [<ffffffff81400ddb>] tracesys+0xdd/0xe2
    
    Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
    Tested-by: default avatarStephen Gallagher <sgallagh@redhat.com>
    23fd78d7