From: Greg Kroah-Hartman Date: Wed, 25 Oct 2017 09:47:54 +0000 (+0200) Subject: 4.4-stable patches X-Git-Tag: v3.18.78~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f71b73866537bb3c41f3e403c3c413398d6919f6;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches 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 --- 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 index 00000000000..83621fbfdfe --- /dev/null +++ b/queue-4.4/f2fs-crypto-add-missing-locking-for-keyring_key-access.patch @@ -0,0 +1,47 @@ +From 745e8490b1e960ad79859dd8ba6a0b5a8d3d994e Mon Sep 17 00:00:00 2001 +From: Jaegeuk Kim +Date: Fri, 5 Feb 2016 19:38:42 -0800 +Subject: f2fs crypto: add missing locking for keyring_key access + +From: Jaegeuk Kim + +commit 745e8490b1e960ad79859dd8ba6a0b5a8d3d994e upstream. + +This patch adopts: + ext4 crypto: add missing locking for keyring_key access + +Signed-off-by: Theodore Ts'o +Signed-off-by: Jaegeuk Kim +Signed-off-by: Eric Biggers +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..e5965698fd9 --- /dev/null +++ b/queue-4.4/f2fs-crypto-replace-some-bug_on-s-with-error-checks.patch @@ -0,0 +1,88 @@ +From 66aa3e1274fcf887e9d6501a68163270fc7718e7 Mon Sep 17 00:00:00 2001 +From: Jaegeuk Kim +Date: Fri, 5 Feb 2016 19:19:01 -0800 +Subject: f2fs crypto: replace some BUG_ON()'s with error checks + +From: Jaegeuk Kim + +commit 66aa3e1274fcf887e9d6501a68163270fc7718e7 upstream. + +This patch adopts: + ext4 crypto: replace some BUG_ON()'s with error checks + +Signed-off-by: Theodore Ts'o +Signed-off-by: Jaegeuk Kim +Signed-off-by: Eric Biggers +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..205c7e34d10 --- /dev/null +++ b/queue-4.4/fs-cache-fix-dereference-of-null-user_key_payload.patch @@ -0,0 +1,45 @@ +From d124b2c53c7bee6569d2a2d0b18b4a1afde00134 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Mon, 9 Oct 2017 12:40:00 -0700 +Subject: FS-Cache: fix dereference of NULL user_key_payload + +From: Eric Biggers + +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 +Signed-off-by: Eric Biggers +Signed-off-by: David Howells +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..7b0dadc604c --- /dev/null +++ b/queue-4.4/fscrypt-fix-dereference-of-null-user_key_payload.patch @@ -0,0 +1,59 @@ +From d60b5b7854c3d135b869f74fb93eaf63cbb1991a Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Mon, 9 Oct 2017 12:46:18 -0700 +Subject: fscrypt: fix dereference of NULL user_key_payload + +From: Eric Biggers + +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 +Cc: [v4.1+] +Signed-off-by: Eric Biggers +Signed-off-by: David Howells +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..b66bc55a1b4 --- /dev/null +++ b/queue-4.4/fscrypto-require-write-access-to-mount-to-set-encryption-policy.patch @@ -0,0 +1,47 @@ +From ba63f23d69a3a10e7e527a02702023da68ef8a6d Mon Sep 17 00:00:00 2001 +From: Eric Biggers +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 +Signed-off-by: Theodore Ts'o +Acked-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..e06dfcbf33b --- /dev/null +++ b/queue-4.4/keys-fix-race-between-updating-and-finding-a-negative-key.patch @@ -0,0 +1,468 @@ +From 363b02dab09b3226f3bd1420dad9c72b79a42a76 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Wed, 4 Oct 2017 16:43:25 +0100 +Subject: KEYS: Fix race between updating and finding a negative key + +From: David Howells + +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 +Signed-off-by: David Howells +Reviewed-by: Eric Biggers +Signed-off-by: Greg Kroah-Hartman +--- + 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); + } + diff --git a/queue-4.4/series b/queue-4.4/series index 1862dfdd54d..21473dfdeb0 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -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