[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20170927195047.122358-5-ebiggers3@gmail.com>
Date: Wed, 27 Sep 2017 12:50:44 -0700
From: Eric Biggers <ebiggers3@...il.com>
To: keyrings@...r.kernel.org
Cc: David Howells <dhowells@...hat.com>,
Michael Halcrow <mhalcrow@...gle.com>,
linux-security-module@...r.kernel.org,
linux-kernel@...r.kernel.org, Eric Biggers <ebiggers@...gle.com>
Subject: [PATCH v3 4/7] KEYS: load key flags and expiry time atomically in key_validate()
From: Eric Biggers <ebiggers@...gle.com>
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@...gle.com>
---
security/keys/permission.c | 7 ++++---
1 file 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;
}
--
2.14.2.822.g60be5d43e6-goog
Powered by blists - more mailing lists