aboutsummaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
authorEric Biggers2017-09-27 12:50:44 -0700
committerDavid Howells2017-10-18 09:12:41 +0100
commit1823d475a5eeaa0f52789b1b7e2d31a592ae92ea (patch)
tree0cc97d27ac4815b342887b85d5b8f274dd3d4095 /security
parent60ff5b2f547af3828aebafd54daded44cfb0807a (diff)
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: Eric Biggers <ebiggers@google.com> Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'security')
-rw-r--r--security/keys/permission.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/security/keys/permission.c b/security/keys/permission.c
index 732cc0beffdf..a72b4dd70c8a 100644
--- a/security/keys/permission.c
+++ b/security/keys/permission.c
@@ -88,7 +88,8 @@ EXPORT_SYMBOL(key_task_permission);
*/
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))
return -ENOKEY;
@@ -99,9 +100,9 @@ int key_validate(const struct key *key)
return -EKEYREVOKED;
/* check it hasn't expired */
- if (key->expiry) {
+ if (expiry) {
struct timespec now = current_kernel_time();
- if (now.tv_sec >= key->expiry)
+ if (now.tv_sec >= expiry)
return -EKEYEXPIRED;
}