1. 14 Sep, 2011 10 commits
  2. 13 Sep, 2011 5 commits
  3. 09 Sep, 2011 18 commits
  4. 23 Aug, 2011 2 commits
  5. 22 Aug, 2011 5 commits
    • David Howells's avatar
      KEYS: Correctly destroy key payloads when their keytype is removed · 0c061b57
      David Howells authored
      unregister_key_type() has code to mark a key as dead and make it unavailable in
      one loop and then destroy all those unavailable key payloads in the next loop.
      However, the loop to mark keys dead renders the key undetectable to the second
      loop by changing the key type pointer also.
      
      Fix this by the following means:
      
       (1) The key code has two garbage collectors: one deletes unreferenced keys and
           the other alters keyrings to delete links to old dead, revoked and expired
           keys.  They can end up holding each other up as both want to scan the key
           serial tree under spinlock.  Combine these into a single routine.
      
       (2) Move the dead key marking, dead link removal and dead key removal into the
           garbage collector as a three phase process running over the three cycles
           of the normal garbage collection procedure.  This is tracked by the
           KEY_GC_REAPING_DEAD_1, _2 and _3 state flags.
      
           unregister_key_type() then just unlinks the key type from the list, wakes
           up the garbage collector and waits for the third phase to complete.
      
       (3) Downgrade the key types sem in unregister_key_type() once it has deleted
           the key type from the list so that it doesn't block the keyctl() syscall.
      
       (4) Dead keys that cannot be simply removed in the third phase have their
           payloads destroyed with the key's semaphore write-locked to prevent
           interference by the keyctl() syscall.  There should be no in-kernel users
           of dead keys of that type by the point of unregistration, though keyctl()
           may be holding a reference.
      
       (5) Only perform timer recalculation in the GC if the timer actually expired.
           If it didn't, we'll get another cycle when it goes off - and if the key
           that actually triggered it has been removed, it's not a problem.
      
       (6) Only garbage collect link if the timer expired or if we're doing dead key
           clean up phase 2.
      
       (7) As only key_garbage_collector() is permitted to use rb_erase() on the key
           serial tree, it doesn't need to revalidate its cursor after dropping the
           spinlock as the node the cursor points to must still exist in the tree.
      
       (8) Drop the spinlock in the GC if there is contention on it or if we need to
           reschedule.  After dealing with that, get the spinlock again and resume
           scanning.
      
      This has been tested in the following ways:
      
       (1) Run the keyutils testsuite against it.
      
       (2) Using the AF_RXRPC and RxKAD modules to test keytype removal:
      
           Load the rxrpc_s key type:
      
      	# insmod /tmp/af-rxrpc.ko
      	# insmod /tmp/rxkad.ko
      
           Create a key (http://people.redhat.com/~dhowells/rxrpc/listen.c):
      
      	# /tmp/listen &
      	[1] 8173
      
           Find the key:
      
      	# grep rxrpc_s /proc/keys
      	091086e1 I--Q--     1 perm 39390000     0     0 rxrpc_s   52:2
      
           Link it to a session keyring, preferably one with a higher serial number:
      
      	# keyctl link 0x20e36251 @s
      
           Kill the process (the key should remain as it's linked to another place):
      
      	# fg
      	/tmp/listen
      	^C
      
           Remove the key type:
      
      	rmmod rxkad
      	rmmod af-rxrpc
      
           This can be made a more effective test by altering the following part of
           the patch:
      
      	if (unlikely(gc_state & KEY_GC_REAPING_DEAD_2)) {
      		/* Make sure everyone revalidates their keys if we marked a
      		 * bunch as being dead and make sure all keyring ex-payloads
      		 * are destroyed.
      		 */
      		kdebug("dead sync");
      		synchronize_rcu();
      
           To call synchronize_rcu() in GC phase 1 instead.  That causes that the
           keyring's old payload content to hang around longer until it's RCU
           destroyed - which usually happens after GC phase 3 is complete.  This
           allows the destroy_dead_key branch to be tested.
      Reported-by: default avatarBenjamin Coddington <bcodding@gmail.com>
      Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
      Signed-off-by: default avatarJames Morris <jmorris@namei.org>
      0c061b57
    • David Howells's avatar
      KEYS: The dead key link reaper should be non-reentrant · d199798b
      David Howells authored
      The dead key link reaper should be non-reentrant as it relies on global state
      to keep track of where it's got to when it returns to the work queue manager to
      give it some air.
      Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
      Signed-off-by: default avatarJames Morris <jmorris@namei.org>
      d199798b
    • David Howells's avatar
      KEYS: Make the key reaper non-reentrant · b072e9bc
      David Howells authored
      Make the key reaper non-reentrant by sticking it on the appropriate system work
      queue when we queue it.  This will allow it to have global state and drop
      locks.  It should probably be non-reentrant already as it may spend a long time
      holding the key serial spinlock, and so multiple entrants can spend long
      periods of time just sitting there spinning, waiting to get the lock.
      Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
      Signed-off-by: default avatarJames Morris <jmorris@namei.org>
      b072e9bc
    • David Howells's avatar
      KEYS: Move the unreferenced key reaper to the keys garbage collector file · 8bc16dea
      David Howells authored
      Move the unreferenced key reaper function to the keys garbage collector file
      as that's a more appropriate place with the dead key link reaper.
      Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
      Signed-off-by: default avatarJames Morris <jmorris@namei.org>
      8bc16dea
    • David Howells's avatar
      CRED: Fix prepare_kernel_cred() to provide a new thread_group_cred struct · 012146d0
      David Howells authored
      Fix prepare_kernel_cred() to provide a new, separate thread_group_cred struct
      otherwise when using request_key() ____call_usermodehelper() calls
      umh_keys_init() with the new creds pointing to init_tgcred, which
      umh_keys_init() then blithely alters.
      
      The problem can be demonstrated by:
      
      	# keyctl request2 user a debug:a @s
      	249681132
      	# grep req /proc/keys
      	079906a5 I--Q--     1 perm 1f3f0000     0     0 keyring   _req.249681132: 1/4
      	38ef1626 IR----     1 expd 0b010000     0     0 .request_ key:ee1d4ec pid:4371 ci:1
      
      The keyring _req.XXXX should have gone away, but something (init_tgcred) is
      pinning it.
      
      That key actually requested can then be removed and a new one created:
      
      	# keyctl unlink 249681132
      	1 links removed
      	[root@andromeda ~]# grep req /proc/keys
      	116cecac IR----     1 expd 0b010000     0     0 .request_ key:eeb4911 pid:4379 ci:1
      	36d1cbf8 I--Q--     1 perm 1f3f0000     0     0 keyring   _req.250300689: 1/4
      
      which causes the old _req keyring to go away and a new one to take its place.
      
      This is a consequence of the changes in:
      
      	commit 87966996
      	Author: David Howells <dhowells@redhat.com>
      	Date:   Fri Jun 17 11:25:59 2011 +0100
      	KEYS/DNS: Fix ____call_usermodehelper() to not lose the session keyring
      
      and:
      
      	commit 17f60a7d
      	Author: Eric Paris <eparis@redhat.com>
      	Date:   Fri Apr 1 17:07:50 2011 -0400
      	capabilites: allow the application of capability limits to usermode helpers
      
      After this patch is applied, the _req keyring and the .request_key key are
      cleaned up.
      Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
      cc: Eric Paris <eparis@redhat.com>
      Signed-off-by: default avatarJames Morris <jmorris@namei.org>
      012146d0