• David Howells's avatar
    KEYS: request_key() should reget expired keys rather than give EKEYEXPIRED · 0b0a8415
    David Howells authored
    Since the keyring facility can be viewed as a cache (at least in some
    applications), the local expiration time on the key should probably be viewed
    as a 'needs updating after this time' property rather than an absolute 'anyone
    now wanting to use this object is out of luck' property.
    
    Since request_key() is the main interface for the usage of keys, this should
    update or replace an expired key rather than issuing EKEYEXPIRED if the local
    expiration has been reached (ie. it should refresh the cache).
    
    For absolute conditions where refreshing the cache probably doesn't help, the
    key can be negatively instantiated using KEYCTL_REJECT_KEY with EKEYEXPIRED
    given as the error to issue.  This will still cause request_key() to return
    EKEYEXPIRED as that was explicitly set.
    
    In the future, if the key type has an update op available, we might want to
    upcall with the expired key and allow the upcall to update it.  We would pass
    a different operation name (the first column in /etc/request-key.conf) to the
    request-key program.
    
    request_key() returning EKEYEXPIRED is causing an NFS problem which Chuck
    Lever describes thusly:
    
    	After about 10 minutes, my NFSv4 functional tests fail because the
    	ownership of the test files goes to "-2". Looking at /proc/keys
    	shows that the id_resolv keys that map to my test user ID have
    	expired. The ownership problem persists until the expired keys are
    	purged from the keyring, and fresh keys are obtained.
    
    	I bisected the problem to 3.13 commit b2a4df20 ("KEYS: Expand
    	the capacity of a keyring"). This commit inadvertantly changes the
    	API contract of the internal function keyring_search_aux().
    
    	The root cause appears to be that b2a4df20 made "no state check"
    	the default behavior. "No state check" means the keyring search
    	iterator function skips checking the key's expiry timeout, and
    	returns expired keys.  request_key_and_link() depends on getting
    	an -EAGAIN result code to know when to perform an upcall to refresh
    	an expired key.
    
    This patch can be tested directly by:
    
    	keyctl request2 user debug:fred a @s
    	keyctl timeout %user:debug:fred 3
    	sleep 4
    	keyctl request2 user debug:fred a @s
    
    Without the patch, the last command gives error EKEYEXPIRED, but with the
    command it gives a new key.
    Reported-by: default avatarCarl Hetherington <cth@carlh.net>
    Reported-by: default avatarChuck Lever <chuck.lever@oracle.com>
    Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
    Tested-by: default avatarChuck Lever <chuck.lever@oracle.com>
    0b0a8415
keyring.c 36.9 KB