]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 25 Oct 2017 09:47:54 +0000 (11:47 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 25 Oct 2017 09:47:54 +0000 (11:47 +0200)
added patches:
f2fs-crypto-add-missing-locking-for-keyring_key-access.patch
f2fs-crypto-replace-some-bug_on-s-with-error-checks.patch
fs-cache-fix-dereference-of-null-user_key_payload.patch
fscrypt-fix-dereference-of-null-user_key_payload.patch
fscrypto-require-write-access-to-mount-to-set-encryption-policy.patch
keys-fix-race-between-updating-and-finding-a-negative-key.patch

queue-4.4/f2fs-crypto-add-missing-locking-for-keyring_key-access.patch [new file with mode: 0644]
queue-4.4/f2fs-crypto-replace-some-bug_on-s-with-error-checks.patch [new file with mode: 0644]
queue-4.4/fs-cache-fix-dereference-of-null-user_key_payload.patch [new file with mode: 0644]
queue-4.4/fscrypt-fix-dereference-of-null-user_key_payload.patch [new file with mode: 0644]
queue-4.4/fscrypto-require-write-access-to-mount-to-set-encryption-policy.patch [new file with mode: 0644]
queue-4.4/keys-fix-race-between-updating-and-finding-a-negative-key.patch [new file with mode: 0644]
queue-4.4/series

diff --git a/queue-4.4/f2fs-crypto-add-missing-locking-for-keyring_key-access.patch b/queue-4.4/f2fs-crypto-add-missing-locking-for-keyring_key-access.patch
new file mode 100644 (file)
index 0000000..83621fb
--- /dev/null
@@ -0,0 +1,47 @@
+From 745e8490b1e960ad79859dd8ba6a0b5a8d3d994e Mon Sep 17 00:00:00 2001
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+Date: Fri, 5 Feb 2016 19:38:42 -0800
+Subject: f2fs crypto: add missing locking for keyring_key access
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+commit 745e8490b1e960ad79859dd8ba6a0b5a8d3d994e upstream.
+
+This patch adopts:
+       ext4 crypto: add missing locking for keyring_key access
+
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/crypto_key.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/fs/f2fs/crypto_key.c
++++ b/fs/f2fs/crypto_key.c
+@@ -193,9 +193,11 @@ int f2fs_get_encryption_info(struct inod
+               res = -ENOKEY;
+               goto out;
+       }
++      down_read(&keyring_key->sem);
+       ukp = user_key_payload(keyring_key);
+       if (ukp->datalen != sizeof(struct f2fs_encryption_key)) {
+               res = -EINVAL;
++              up_read(&keyring_key->sem);
+               goto out;
+       }
+       master_key = (struct f2fs_encryption_key *)ukp->data;
+@@ -206,10 +208,12 @@ int f2fs_get_encryption_info(struct inod
+                               "f2fs: key size incorrect: %d\n",
+                               master_key->size);
+               res = -ENOKEY;
++              up_read(&keyring_key->sem);
+               goto out;
+       }
+       res = f2fs_derive_key_aes(ctx.nonce, master_key->raw,
+                                 raw_key);
++      up_read(&keyring_key->sem);
+       if (res)
+               goto out;
diff --git a/queue-4.4/f2fs-crypto-replace-some-bug_on-s-with-error-checks.patch b/queue-4.4/f2fs-crypto-replace-some-bug_on-s-with-error-checks.patch
new file mode 100644 (file)
index 0000000..e596569
--- /dev/null
@@ -0,0 +1,88 @@
+From 66aa3e1274fcf887e9d6501a68163270fc7718e7 Mon Sep 17 00:00:00 2001
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+Date: Fri, 5 Feb 2016 19:19:01 -0800
+Subject: f2fs crypto: replace some BUG_ON()'s with error checks
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+commit 66aa3e1274fcf887e9d6501a68163270fc7718e7 upstream.
+
+This patch adopts:
+       ext4 crypto: replace some BUG_ON()'s with error checks
+
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/crypto.c       |    1 -
+ fs/f2fs/crypto_fname.c |    2 --
+ fs/f2fs/crypto_key.c   |   15 ++++++++++++---
+ 3 files changed, 12 insertions(+), 6 deletions(-)
+
+--- a/fs/f2fs/crypto.c
++++ b/fs/f2fs/crypto.c
+@@ -362,7 +362,6 @@ static int f2fs_page_crypto(struct f2fs_
+       else
+               res = crypto_ablkcipher_encrypt(req);
+       if (res == -EINPROGRESS || res == -EBUSY) {
+-              BUG_ON(req->base.data != &ecr);
+               wait_for_completion(&ecr.completion);
+               res = ecr.res;
+       }
+--- a/fs/f2fs/crypto_fname.c
++++ b/fs/f2fs/crypto_fname.c
+@@ -124,7 +124,6 @@ static int f2fs_fname_encrypt(struct ino
+       ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, ciphertext_len, iv);
+       res = crypto_ablkcipher_encrypt(req);
+       if (res == -EINPROGRESS || res == -EBUSY) {
+-              BUG_ON(req->base.data != &ecr);
+               wait_for_completion(&ecr.completion);
+               res = ecr.res;
+       }
+@@ -180,7 +179,6 @@ static int f2fs_fname_decrypt(struct ino
+       ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, iv);
+       res = crypto_ablkcipher_decrypt(req);
+       if (res == -EINPROGRESS || res == -EBUSY) {
+-              BUG_ON(req->base.data != &ecr);
+               wait_for_completion(&ecr.completion);
+               res = ecr.res;
+       }
+--- a/fs/f2fs/crypto_key.c
++++ b/fs/f2fs/crypto_key.c
+@@ -75,7 +75,6 @@ static int f2fs_derive_key_aes(char deri
+                                       F2FS_AES_256_XTS_KEY_SIZE, NULL);
+       res = crypto_ablkcipher_encrypt(req);
+       if (res == -EINPROGRESS || res == -EBUSY) {
+-              BUG_ON(req->base.data != &ecr);
+               wait_for_completion(&ecr.completion);
+               res = ecr.res;
+       }
+@@ -189,7 +188,11 @@ int f2fs_get_encryption_info(struct inod
+               keyring_key = NULL;
+               goto out;
+       }
+-      BUG_ON(keyring_key->type != &key_type_logon);
++      if (keyring_key->type != &key_type_logon) {
++              printk_once(KERN_WARNING "f2fs: key type must be logon\n");
++              res = -ENOKEY;
++              goto out;
++      }
+       ukp = user_key_payload(keyring_key);
+       if (ukp->datalen != sizeof(struct f2fs_encryption_key)) {
+               res = -EINVAL;
+@@ -198,7 +201,13 @@ int f2fs_get_encryption_info(struct inod
+       master_key = (struct f2fs_encryption_key *)ukp->data;
+       BUILD_BUG_ON(F2FS_AES_128_ECB_KEY_SIZE !=
+                               F2FS_KEY_DERIVATION_NONCE_SIZE);
+-      BUG_ON(master_key->size != F2FS_AES_256_XTS_KEY_SIZE);
++      if (master_key->size != F2FS_AES_256_XTS_KEY_SIZE) {
++              printk_once(KERN_WARNING
++                              "f2fs: key size incorrect: %d\n",
++                              master_key->size);
++              res = -ENOKEY;
++              goto out;
++      }
+       res = f2fs_derive_key_aes(ctx.nonce, master_key->raw,
+                                 raw_key);
+       if (res)
diff --git a/queue-4.4/fs-cache-fix-dereference-of-null-user_key_payload.patch b/queue-4.4/fs-cache-fix-dereference-of-null-user_key_payload.patch
new file mode 100644 (file)
index 0000000..205c7e3
--- /dev/null
@@ -0,0 +1,45 @@
+From d124b2c53c7bee6569d2a2d0b18b4a1afde00134 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@google.com>
+Date: Mon, 9 Oct 2017 12:40:00 -0700
+Subject: FS-Cache: fix dereference of NULL user_key_payload
+
+From: Eric Biggers <ebiggers@google.com>
+
+commit d124b2c53c7bee6569d2a2d0b18b4a1afde00134 upstream.
+
+When the file /proc/fs/fscache/objects (available with
+CONFIG_FSCACHE_OBJECT_LIST=y) is opened, we request a user key with
+description "fscache:objlist", then access its payload.  However, a
+revoked key has a NULL payload, and we failed to check for this.
+request_key() *does* skip revoked keys, but there is still a window
+where the key can be revoked before we access its payload.
+
+Fix it by checking for a NULL payload, treating it like a key which was
+already revoked at the time it was requested.
+
+Fixes: 4fbf4291aa15 ("FS-Cache: Allow the current state of all objects to be dumped")
+Reviewed-by: James Morris <james.l.morris@oracle.com>
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/fscache/object-list.c |    7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/fs/fscache/object-list.c
++++ b/fs/fscache/object-list.c
+@@ -330,6 +330,13 @@ static void fscache_objlist_config(struc
+       rcu_read_lock();
+       confkey = user_key_payload(key);
++      if (!confkey) {
++              /* key was revoked */
++              rcu_read_unlock();
++              key_put(key);
++              goto no_config;
++      }
++
+       buf = confkey->data;
+       for (len = confkey->datalen - 1; len >= 0; len--) {
diff --git a/queue-4.4/fscrypt-fix-dereference-of-null-user_key_payload.patch b/queue-4.4/fscrypt-fix-dereference-of-null-user_key_payload.patch
new file mode 100644 (file)
index 0000000..7b0dadc
--- /dev/null
@@ -0,0 +1,59 @@
+From d60b5b7854c3d135b869f74fb93eaf63cbb1991a Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@google.com>
+Date: Mon, 9 Oct 2017 12:46:18 -0700
+Subject: fscrypt: fix dereference of NULL user_key_payload
+
+From: Eric Biggers <ebiggers@google.com>
+
+commit d60b5b7854c3d135b869f74fb93eaf63cbb1991a upstream.
+
+When an fscrypt-encrypted file is opened, we request the file's master
+key from the keyrings service as a logon key, then access its payload.
+However, a revoked key has a NULL payload, and we failed to check for
+this.  request_key() *does* skip revoked keys, but there is still a
+window where the key can be revoked before we acquire its semaphore.
+
+Fix it by checking for a NULL payload, treating it like a key which was
+already revoked at the time it was requested.
+
+Fixes: 88bd6ccdcdd6 ("ext4 crypto: add encryption key management facilities")
+Reviewed-by: James Morris <james.l.morris@oracle.com>
+Cc: <stable@vger.kernel.org>    [v4.1+]
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ext4/crypto_key.c |    6 ++++++
+ fs/f2fs/crypto_key.c |    6 ++++++
+ 2 files changed, 12 insertions(+)
+
+--- a/fs/ext4/crypto_key.c
++++ b/fs/ext4/crypto_key.c
+@@ -204,6 +204,12 @@ int ext4_get_encryption_info(struct inod
+       }
+       down_read(&keyring_key->sem);
+       ukp = user_key_payload(keyring_key);
++      if (!ukp) {
++              /* key was revoked before we acquired its semaphore */
++              res = -EKEYREVOKED;
++              up_read(&keyring_key->sem);
++              goto out;
++      }
+       if (ukp->datalen != sizeof(struct ext4_encryption_key)) {
+               res = -EINVAL;
+               up_read(&keyring_key->sem);
+--- a/fs/f2fs/crypto_key.c
++++ b/fs/f2fs/crypto_key.c
+@@ -195,6 +195,12 @@ int f2fs_get_encryption_info(struct inod
+       }
+       down_read(&keyring_key->sem);
+       ukp = user_key_payload(keyring_key);
++      if (!ukp) {
++              /* key was revoked before we acquired its semaphore */
++              res = -EKEYREVOKED;
++              up_read(&keyring_key->sem);
++              goto out;
++      }
+       if (ukp->datalen != sizeof(struct f2fs_encryption_key)) {
+               res = -EINVAL;
+               up_read(&keyring_key->sem);
diff --git a/queue-4.4/fscrypto-require-write-access-to-mount-to-set-encryption-policy.patch b/queue-4.4/fscrypto-require-write-access-to-mount-to-set-encryption-policy.patch
new file mode 100644 (file)
index 0000000..b66bc55
--- /dev/null
@@ -0,0 +1,47 @@
+From ba63f23d69a3a10e7e527a02702023da68ef8a6d Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@google.com>
+Date: Thu, 8 Sep 2016 14:20:38 -0700
+Subject: fscrypto: require write access to mount to set encryption policy
+
+commit ba63f23d69a3a10e7e527a02702023da68ef8a6d upstream.
+
+[Please apply to 4.4-stable.  Note: this was already backported, but
+only to ext4; it was missed that it should go to f2fs as well.  This is
+needed to make xfstest generic/395 pass on f2fs.]
+
+Since setting an encryption policy requires writing metadata to the
+filesystem, it should be guarded by mnt_want_write/mnt_drop_write.
+Otherwise, a user could cause a write to a frozen or readonly
+filesystem.  This was handled correctly by f2fs but not by ext4.  Make
+fscrypt_process_policy() handle it rather than relying on the filesystem
+to get it right.
+
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Acked-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/file.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/fs/f2fs/file.c
++++ b/fs/f2fs/file.c
+@@ -1541,12 +1541,18 @@ static int f2fs_ioc_set_encryption_polic
+                               sizeof(policy)))
+               return -EFAULT;
++      err = mnt_want_write_file(filp);
++      if (err)
++              return err;
++
+       mutex_lock(&inode->i_mutex);
+       err = f2fs_process_policy(&policy, inode);
+       mutex_unlock(&inode->i_mutex);
++      mnt_drop_write_file(filp);
++
+       return err;
+ #else
+       return -EOPNOTSUPP;
diff --git a/queue-4.4/keys-fix-race-between-updating-and-finding-a-negative-key.patch b/queue-4.4/keys-fix-race-between-updating-and-finding-a-negative-key.patch
new file mode 100644 (file)
index 0000000..e06dfcb
--- /dev/null
@@ -0,0 +1,468 @@
+From 363b02dab09b3226f3bd1420dad9c72b79a42a76 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Wed, 4 Oct 2017 16:43:25 +0100
+Subject: KEYS: Fix race between updating and finding a negative key
+
+From: David Howells <dhowells@redhat.com>
+
+commit 363b02dab09b3226f3bd1420dad9c72b79a42a76 upstream.
+
+Consolidate KEY_FLAG_INSTANTIATED, KEY_FLAG_NEGATIVE and the rejection
+error into one field such that:
+
+ (1) The instantiation state can be modified/read atomically.
+
+ (2) The error can be accessed atomically with the state.
+
+ (3) The error isn't stored unioned with the payload pointers.
+
+This deals with the problem that the state is spread over three different
+objects (two bits and a separate variable) and reading or updating them
+atomically isn't practical, given that not only can uninstantiated keys
+change into instantiated or rejected keys, but rejected keys can also turn
+into instantiated keys - and someone accessing the key might not be using
+any locking.
+
+The main side effect of this problem is that what was held in the payload
+may change, depending on the state.  For instance, you might observe the
+key to be in the rejected state.  You then read the cached error, but if
+the key semaphore wasn't locked, the key might've become instantiated
+between the two reads - and you might now have something in hand that isn't
+actually an error code.
+
+The state is now KEY_IS_UNINSTANTIATED, KEY_IS_POSITIVE or a negative error
+code if the key is negatively instantiated.  The key_is_instantiated()
+function is replaced with key_is_positive() to avoid confusion as negative
+keys are also 'instantiated'.
+
+Additionally, barriering is included:
+
+ (1) Order payload-set before state-set during instantiation.
+
+ (2) Order state-read before payload-read when using the key.
+
+Further separate barriering is necessary if RCU is being used to access the
+payload content after reading the payload pointers.
+
+Fixes: 146aa8b1453b ("KEYS: Merge the type-specific data with the payload data")
+Reported-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/key.h                      |   49 +++++++++++++++++++------------
+ net/dns_resolver/dns_key.c               |    2 -
+ security/keys/big_key.c                  |    4 +-
+ security/keys/encrypted-keys/encrypted.c |    2 -
+ security/keys/gc.c                       |    8 ++---
+ security/keys/key.c                      |   31 ++++++++++++-------
+ security/keys/keyctl.c                   |    9 ++---
+ security/keys/keyring.c                  |   10 +++---
+ security/keys/proc.c                     |    7 +++-
+ security/keys/process_keys.c             |    2 -
+ security/keys/request_key.c              |    7 +---
+ security/keys/request_key_auth.c         |    2 -
+ security/keys/trusted.c                  |    2 -
+ security/keys/user_defined.c             |    4 +-
+ 14 files changed, 81 insertions(+), 58 deletions(-)
+
+--- a/include/linux/key.h
++++ b/include/linux/key.h
+@@ -126,6 +126,11 @@ static inline bool is_key_possessed(cons
+       return (unsigned long) key_ref & 1UL;
+ }
++enum key_state {
++      KEY_IS_UNINSTANTIATED,
++      KEY_IS_POSITIVE,                /* Positively instantiated */
++};
++
+ /*****************************************************************************/
+ /*
+  * authentication token / access credential / keyring
+@@ -157,6 +162,7 @@ struct key {
+                                                * - may not match RCU dereferenced payload
+                                                * - payload should contain own length
+                                                */
++      short                   state;          /* Key state (+) or rejection error (-) */
+ #ifdef KEY_DEBUGGING
+       unsigned                magic;
+@@ -165,19 +171,17 @@ struct key {
+ #endif
+       unsigned long           flags;          /* status flags (change with bitops) */
+-#define KEY_FLAG_INSTANTIATED 0       /* set if key has been instantiated */
+-#define KEY_FLAG_DEAD         1       /* set if key type has been deleted */
+-#define KEY_FLAG_REVOKED      2       /* set if key had been revoked */
+-#define KEY_FLAG_IN_QUOTA     3       /* set if key consumes quota */
+-#define KEY_FLAG_USER_CONSTRUCT       4       /* set if key is being constructed in userspace */
+-#define KEY_FLAG_NEGATIVE     5       /* set if key is negative */
+-#define KEY_FLAG_ROOT_CAN_CLEAR       6       /* set if key can be cleared by root without permission */
+-#define KEY_FLAG_INVALIDATED  7       /* set if key has been invalidated */
+-#define KEY_FLAG_TRUSTED      8       /* set if key is trusted */
+-#define KEY_FLAG_TRUSTED_ONLY 9       /* set if keyring only accepts links to trusted keys */
+-#define KEY_FLAG_BUILTIN      10      /* set if key is builtin */
+-#define KEY_FLAG_ROOT_CAN_INVAL       11      /* set if key can be invalidated by root without permission */
+-#define KEY_FLAG_UID_KEYRING  12      /* set if key is a user or user session keyring */
++#define KEY_FLAG_DEAD         0       /* set if key type has been deleted */
++#define KEY_FLAG_REVOKED      1       /* set if key had been revoked */
++#define KEY_FLAG_IN_QUOTA     2       /* set if key consumes quota */
++#define KEY_FLAG_USER_CONSTRUCT       3       /* set if key is being constructed in userspace */
++#define KEY_FLAG_ROOT_CAN_CLEAR       4       /* set if key can be cleared by root without permission */
++#define KEY_FLAG_INVALIDATED  5       /* set if key has been invalidated */
++#define KEY_FLAG_TRUSTED      6       /* set if key is trusted */
++#define KEY_FLAG_TRUSTED_ONLY 7       /* set if keyring only accepts links to trusted keys */
++#define KEY_FLAG_BUILTIN      8       /* set if key is builtin */
++#define KEY_FLAG_ROOT_CAN_INVAL       9       /* set if key can be invalidated by root without permission */
++#define KEY_FLAG_UID_KEYRING  10      /* set if key is a user or user session keyring */
+       /* the key type and key description string
+        * - the desc is used to match a key against search criteria
+@@ -203,7 +207,6 @@ struct key {
+                       struct list_head name_link;
+                       struct assoc_array keys;
+               };
+-              int reject_error;
+       };
+ };
+@@ -319,17 +322,27 @@ extern void key_set_timeout(struct key *
+ #define       KEY_NEED_SETATTR 0x20   /* Require permission to change attributes */
+ #define       KEY_NEED_ALL    0x3f    /* All the above permissions */
++static inline short key_read_state(const struct key *key)
++{
++      /* Barrier versus mark_key_instantiated(). */
++      return smp_load_acquire(&key->state);
++}
++
+ /**
+- * key_is_instantiated - Determine if a key has been positively instantiated
++ * key_is_positive - Determine if a key has been positively instantiated
+  * @key: The key to check.
+  *
+  * Return true if the specified key has been positively instantiated, false
+  * otherwise.
+  */
+-static inline bool key_is_instantiated(const struct key *key)
++static inline bool key_is_positive(const struct key *key)
++{
++      return key_read_state(key) == KEY_IS_POSITIVE;
++}
++
++static inline bool key_is_negative(const struct key *key)
+ {
+-      return test_bit(KEY_FLAG_INSTANTIATED, &key->flags) &&
+-              !test_bit(KEY_FLAG_NEGATIVE, &key->flags);
++      return key_read_state(key) < 0;
+ }
+ #define rcu_dereference_key(KEY)                                      \
+--- a/net/dns_resolver/dns_key.c
++++ b/net/dns_resolver/dns_key.c
+@@ -224,7 +224,7 @@ static int dns_resolver_match_preparse(s
+ static void dns_resolver_describe(const struct key *key, struct seq_file *m)
+ {
+       seq_puts(m, key->description);
+-      if (key_is_instantiated(key)) {
++      if (key_is_positive(key)) {
+               int err = PTR_ERR(key->payload.data[dns_key_error]);
+               if (err)
+--- a/security/keys/big_key.c
++++ b/security/keys/big_key.c
+@@ -138,7 +138,7 @@ void big_key_revoke(struct key *key)
+       /* clear the quota */
+       key_payload_reserve(key, 0);
+-      if (key_is_instantiated(key) &&
++      if (key_is_positive(key) &&
+           (size_t)key->payload.data[big_key_len] > BIG_KEY_FILE_THRESHOLD)
+               vfs_truncate(path, 0);
+ }
+@@ -170,7 +170,7 @@ void big_key_describe(const struct key *
+       seq_puts(m, key->description);
+-      if (key_is_instantiated(key))
++      if (key_is_positive(key))
+               seq_printf(m, ": %zu [%s]",
+                          datalen,
+                          datalen > BIG_KEY_FILE_THRESHOLD ? "file" : "buff");
+--- a/security/keys/encrypted-keys/encrypted.c
++++ b/security/keys/encrypted-keys/encrypted.c
+@@ -852,7 +852,7 @@ static int encrypted_update(struct key *
+       size_t datalen = prep->datalen;
+       int ret = 0;
+-      if (test_bit(KEY_FLAG_NEGATIVE, &key->flags))
++      if (key_is_negative(key))
+               return -ENOKEY;
+       if (datalen <= 0 || datalen > 32767 || !prep->data)
+               return -EINVAL;
+--- a/security/keys/gc.c
++++ b/security/keys/gc.c
+@@ -129,15 +129,15 @@ static noinline void key_gc_unused_keys(
+       while (!list_empty(keys)) {
+               struct key *key =
+                       list_entry(keys->next, struct key, graveyard_link);
++              short state = key->state;
++
+               list_del(&key->graveyard_link);
+               kdebug("- %u", key->serial);
+               key_check(key);
+               /* Throw away the key data if the key is instantiated */
+-              if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags) &&
+-                  !test_bit(KEY_FLAG_NEGATIVE, &key->flags) &&
+-                  key->type->destroy)
++              if (state == KEY_IS_POSITIVE && key->type->destroy)
+                       key->type->destroy(key);
+               security_key_free(key);
+@@ -151,7 +151,7 @@ static noinline void key_gc_unused_keys(
+               }
+               atomic_dec(&key->user->nkeys);
+-              if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
++              if (state != KEY_IS_UNINSTANTIATED)
+                       atomic_dec(&key->user->nikeys);
+               key_user_put(key->user);
+--- a/security/keys/key.c
++++ b/security/keys/key.c
+@@ -396,6 +396,18 @@ int key_payload_reserve(struct key *key,
+ EXPORT_SYMBOL(key_payload_reserve);
+ /*
++ * Change the key state to being instantiated.
++ */
++static void mark_key_instantiated(struct key *key, int reject_error)
++{
++      /* Commit the payload before setting the state; barrier versus
++       * key_read_state().
++       */
++      smp_store_release(&key->state,
++                        (reject_error < 0) ? reject_error : KEY_IS_POSITIVE);
++}
++
++/*
+  * Instantiate a key and link it into the target keyring atomically.  Must be
+  * called with the target keyring's semaphore writelocked.  The target key's
+  * semaphore need not be locked as instantiation is serialised by
+@@ -418,14 +430,14 @@ static int __key_instantiate_and_link(st
+       mutex_lock(&key_construction_mutex);
+       /* can't instantiate twice */
+-      if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
++      if (key->state == KEY_IS_UNINSTANTIATED) {
+               /* instantiate the key */
+               ret = key->type->instantiate(key, prep);
+               if (ret == 0) {
+                       /* mark the key as being instantiated */
+                       atomic_inc(&key->user->nikeys);
+-                      set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
++                      mark_key_instantiated(key, 0);
+                       if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
+                               awaken = 1;
+@@ -553,13 +565,10 @@ int key_reject_and_link(struct key *key,
+       mutex_lock(&key_construction_mutex);
+       /* can't instantiate twice */
+-      if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
++      if (key->state == KEY_IS_UNINSTANTIATED) {
+               /* mark the key as being negatively instantiated */
+               atomic_inc(&key->user->nikeys);
+-              key->reject_error = -error;
+-              smp_wmb();
+-              set_bit(KEY_FLAG_NEGATIVE, &key->flags);
+-              set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
++              mark_key_instantiated(key, -error);
+               now = current_kernel_time();
+               key->expiry = now.tv_sec + timeout;
+               key_schedule_gc(key->expiry + key_gc_delay);
+@@ -731,8 +740,8 @@ static inline key_ref_t __key_update(key
+       ret = key->type->update(key, prep);
+       if (ret == 0)
+-              /* updating a negative key instantiates it */
+-              clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
++              /* Updating a negative key positively instantiates it */
++              mark_key_instantiated(key, 0);
+       up_write(&key->sem);
+@@ -967,8 +976,8 @@ int key_update(key_ref_t key_ref, const
+       ret = key->type->update(key, &prep);
+       if (ret == 0)
+-              /* updating a negative key instantiates it */
+-              clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
++              /* Updating a negative key positively instantiates it */
++              mark_key_instantiated(key, 0);
+       up_write(&key->sem);
+--- a/security/keys/keyctl.c
++++ b/security/keys/keyctl.c
+@@ -738,10 +738,9 @@ long keyctl_read_key(key_serial_t keyid,
+       key = key_ref_to_ptr(key_ref);
+-      if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
+-              ret = -ENOKEY;
+-              goto error2;
+-      }
++      ret = key_read_state(key);
++      if (ret < 0)
++              goto error2; /* Negatively instantiated */
+       /* see if we can read it directly */
+       ret = key_permission(key_ref, KEY_NEED_READ);
+@@ -873,7 +872,7 @@ long keyctl_chown_key(key_serial_t id, u
+               atomic_dec(&key->user->nkeys);
+               atomic_inc(&newowner->nkeys);
+-              if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
++              if (key->state != KEY_IS_UNINSTANTIATED) {
+                       atomic_dec(&key->user->nikeys);
+                       atomic_inc(&newowner->nikeys);
+               }
+--- a/security/keys/keyring.c
++++ b/security/keys/keyring.c
+@@ -407,7 +407,7 @@ static void keyring_describe(const struc
+       else
+               seq_puts(m, "[anon]");
+-      if (key_is_instantiated(keyring)) {
++      if (key_is_positive(keyring)) {
+               if (keyring->keys.nr_leaves_on_tree != 0)
+                       seq_printf(m, ": %lu", keyring->keys.nr_leaves_on_tree);
+               else
+@@ -522,7 +522,8 @@ static int keyring_search_iterator(const
+ {
+       struct keyring_search_context *ctx = iterator_data;
+       const struct key *key = keyring_ptr_to_key(object);
+-      unsigned long kflags = key->flags;
++      unsigned long kflags = READ_ONCE(key->flags);
++      short state = READ_ONCE(key->state);
+       kenter("{%d}", key->serial);
+@@ -566,9 +567,8 @@ static int keyring_search_iterator(const
+       if (ctx->flags & KEYRING_SEARCH_DO_STATE_CHECK) {
+               /* we set a different error code if we pass a negative key */
+-              if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
+-                      smp_rmb();
+-                      ctx->result = ERR_PTR(key->reject_error);
++              if (state < 0) {
++                      ctx->result = ERR_PTR(state);
+                       kleave(" = %d [neg]", ctx->skipped_ret);
+                       goto skipped;
+               }
+--- a/security/keys/proc.c
++++ b/security/keys/proc.c
+@@ -182,6 +182,7 @@ static int proc_keys_show(struct seq_fil
+       unsigned long timo;
+       key_ref_t key_ref, skey_ref;
+       char xbuf[16];
++      short state;
+       int rc;
+       struct keyring_search_context ctx = {
+@@ -240,17 +241,19 @@ static int proc_keys_show(struct seq_fil
+                       sprintf(xbuf, "%luw", timo / (60*60*24*7));
+       }
++      state = key_read_state(key);
++
+ #define showflag(KEY, LETTER, FLAG) \
+       (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-')
+       seq_printf(m, "%08x %c%c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ",
+                  key->serial,
+-                 showflag(key, 'I', KEY_FLAG_INSTANTIATED),
++                 state != KEY_IS_UNINSTANTIATED ? 'I' : '-',
+                  showflag(key, 'R', KEY_FLAG_REVOKED),
+                  showflag(key, 'D', KEY_FLAG_DEAD),
+                  showflag(key, 'Q', KEY_FLAG_IN_QUOTA),
+                  showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT),
+-                 showflag(key, 'N', KEY_FLAG_NEGATIVE),
++                 state < 0 ? 'N' : '-',
+                  showflag(key, 'i', KEY_FLAG_INVALIDATED),
+                  atomic_read(&key->usage),
+                  xbuf,
+--- a/security/keys/process_keys.c
++++ b/security/keys/process_keys.c
+@@ -727,7 +727,7 @@ try_again:
+       ret = -EIO;
+       if (!(lflags & KEY_LOOKUP_PARTIAL) &&
+-          !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
++          key_read_state(key) == KEY_IS_UNINSTANTIATED)
+               goto invalid_key;
+       /* check the permissions */
+--- a/security/keys/request_key.c
++++ b/security/keys/request_key.c
+@@ -594,10 +594,9 @@ int wait_for_key_construction(struct key
+                         intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
+       if (ret)
+               return -ERESTARTSYS;
+-      if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
+-              smp_rmb();
+-              return key->reject_error;
+-      }
++      ret = key_read_state(key);
++      if (ret < 0)
++              return ret;
+       return key_validate(key);
+ }
+ EXPORT_SYMBOL(wait_for_key_construction);
+--- a/security/keys/request_key_auth.c
++++ b/security/keys/request_key_auth.c
+@@ -73,7 +73,7 @@ static void request_key_auth_describe(co
+       seq_puts(m, "key:");
+       seq_puts(m, key->description);
+-      if (key_is_instantiated(key))
++      if (key_is_positive(key))
+               seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len);
+ }
+--- a/security/keys/trusted.c
++++ b/security/keys/trusted.c
+@@ -1014,7 +1014,7 @@ static int trusted_update(struct key *ke
+       char *datablob;
+       int ret = 0;
+-      if (test_bit(KEY_FLAG_NEGATIVE, &key->flags))
++      if (key_is_negative(key))
+               return -ENOKEY;
+       p = key->payload.data[0];
+       if (!p->migratable)
+--- a/security/keys/user_defined.c
++++ b/security/keys/user_defined.c
+@@ -120,7 +120,7 @@ int user_update(struct key *key, struct
+       if (ret == 0) {
+               /* attach the new data, displacing the old */
+-              if (!test_bit(KEY_FLAG_NEGATIVE, &key->flags))
++              if (key_is_positive(key))
+                       zap = key->payload.data[0];
+               else
+                       zap = NULL;
+@@ -174,7 +174,7 @@ EXPORT_SYMBOL_GPL(user_destroy);
+ void user_describe(const struct key *key, struct seq_file *m)
+ {
+       seq_puts(m, key->description);
+-      if (key_is_instantiated(key))
++      if (key_is_positive(key))
+               seq_printf(m, ": %u", key->datalen);
+ }
index 1862dfdd54d93c5148569c78c1e41b7075104238..21473dfdeb05a61bfbef8a40a73fba47efd68a62 100644 (file)
@@ -25,3 +25,9 @@ pkcs7-prevent-null-pointer-dereference-since-sinfo-is-not-always-set.patch
 parisc-avoid-trashing-sr2-and-sr3-in-lws-code.patch
 parisc-fix-double-word-compare-and-exchange-in-lws-code-on-32-bit-kernels.patch
 sched-autogroup-fix-autogroup_move_group-to-never-skip-sched_move_task.patch
+f2fs-crypto-replace-some-bug_on-s-with-error-checks.patch
+f2fs-crypto-add-missing-locking-for-keyring_key-access.patch
+fscrypt-fix-dereference-of-null-user_key_payload.patch
+keys-fix-race-between-updating-and-finding-a-negative-key.patch
+fscrypto-require-write-access-to-mount-to-set-encryption-policy.patch
+fs-cache-fix-dereference-of-null-user_key_payload.patch