Commit 1823d475 authored by Eric Biggers's avatar Eric Biggers Committed by David Howells

KEYS: load key flags and expiry time atomically in key_validate()

In key_validate(), load the flags and expiry time once atomically, since
these can change concurrently if key_validate() is called without the
key semaphore held.  And we don't want to get inconsistent results if a
variable is referenced multiple times.  For example, key->expiry was
referenced in both 'if (key->expiry)' and in 'if (now.tv_sec >=
key->expiry)', making it theoretically possible to see a spurious
EKEYEXPIRED while the expiration time was being removed, i.e. set to 0.
Signed-off-by: default avatarEric Biggers <ebiggers@google.com>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent 60ff5b2f
...@@ -88,7 +88,8 @@ EXPORT_SYMBOL(key_task_permission); ...@@ -88,7 +88,8 @@ EXPORT_SYMBOL(key_task_permission);
*/ */
int key_validate(const struct key *key) int key_validate(const struct key *key)
{ {
unsigned long flags = key->flags; unsigned long flags = READ_ONCE(key->flags);
time_t expiry = READ_ONCE(key->expiry);
if (flags & (1 << KEY_FLAG_INVALIDATED)) if (flags & (1 << KEY_FLAG_INVALIDATED))
return -ENOKEY; return -ENOKEY;
...@@ -99,9 +100,9 @@ int key_validate(const struct key *key) ...@@ -99,9 +100,9 @@ int key_validate(const struct key *key)
return -EKEYREVOKED; return -EKEYREVOKED;
/* check it hasn't expired */ /* check it hasn't expired */
if (key->expiry) { if (expiry) {
struct timespec now = current_kernel_time(); struct timespec now = current_kernel_time();
if (now.tv_sec >= key->expiry) if (now.tv_sec >= expiry)
return -EKEYEXPIRED; return -EKEYEXPIRED;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment