Pull key handling fixes from James Morris: "This includes a fix for the capabilities code from Colin King, and a set of further fixes for the keys subsystem. From David: - Fix a bunch of places where kernel drivers may access revoked user-type keys and don't do it correctly. - Fix some ecryptfs bits. - Fix big_key to require CONFIG_CRYPTO. - Fix a couple of bugs in the asymmetric key type. - Fix a race between updating and finding negative keys. - Prevent add_key() from updating uninstantiated keys. - Make loading of key flags and expiry time atomic when not holding locks" * 'fixes-v4.14-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: commoncap: move assignment of fs_ns to avoid null pointer dereference pkcs7: Prevent NULL pointer dereference, since sinfo is not always set. KEYS: load key flags and expiry time atomically in proc_keys_show() KEYS: Load key expiry time atomically in keyring_search_iterator() KEYS: load key flags and expiry time atomically in key_validate() KEYS: don't let add_key() update an uninstantiated key KEYS: Fix race between updating and finding a negative key KEYS: checking the input id parameters before finding asymmetric key KEYS: Fix the wrong index when checking the existence of second id security/keys: BIG_KEY requires CONFIG_CRYPTO ecryptfs: fix dereference of NULL user_key_payload fscrypt: fix dereference of NULL user_key_payload lib/digsig: fix dereference of NULL user_key_payload FS-Cache: fix dereference of NULL user_key_payload KEYS: encrypted: fix dereference of NULL user_key_payload
Unified · Split
| @@ -57,6 +57,8 @@ struct key *find_asymmetric_key(struct key *keyring, · 56 unmodified lines | ||
| 57 | 57 | char *req, *p; |
| 58 | 58 | int len; |
| 59 | 59 | |
| 60 | + BUG_ON(!id_0 && !id_1); | |
| 61 | + | |
| 60 | 62 | if (id_0) { |
| 61 | 63 | lookup = id_0->data; |
| 62 | 64 | len = id_0->len; |
| @@ -105,7 +107,7 @@ struct key *find_asymmetric_key(struct key *keyring, · 42 unmodified lines | ||
| 105 | 107 | if (id_0 && id_1) { |
| 106 | 108 | const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); |
| 107 | 109 | |
| 108 | − if (!kids->id[0]) { | |
| 110 | + if (!kids->id[1]) { | |
| 109 | 111 | pr_debug("First ID matches, but second is missing\n"); |
| 110 | 112 | goto reject; |
| 111 | 113 | } |
| @@ -88,6 +88,9 @@ static int pkcs7_check_authattrs(struct pkcs7_message *msg) · 87 unmodified lines | ||
| 88 | 88 | bool want = false; |
| 89 | 89 | |
| 90 | 90 | sinfo = msg->signed_infos; |
| 91 | + if (!sinfo) | |
| 92 | + goto inconsistent; | |
| 93 | + | |
| 91 | 94 | if (sinfo->authattrs) { |
| 92 | 95 | want = true; |
| 93 | 96 | msg->have_authattrs = true; |
| @@ -109,6 +109,11 @@ static int validate_user_key(struct fscrypt_info *crypt_info, · 108 unmodified lines | ||
| 109 | 109 | goto out; |
| 110 | 110 | } |
| 111 | 111 | ukp = user_key_payload_locked(keyring_key); |
| 112 | + if (!ukp) { | |
| 113 | + /* key was revoked before we acquired its semaphore */ | |
| 114 | + res = -EKEYREVOKED; | |
| 115 | + goto out; | |
| 116 | + } | |
| 112 | 117 | if (ukp->datalen != sizeof(struct fscrypt_key)) { |
| 113 | 118 | res = -EINVAL; |
| 114 | 119 | goto out; |
| @@ -84,11 +84,16 @@ struct ecryptfs_page_crypt_context { · 83 unmodified lines | ||
| 84 | 84 | static inline struct ecryptfs_auth_tok * |
| 85 | 85 | ecryptfs_get_encrypted_key_payload_data(struct key *key) |
| 86 | 86 | { |
| 87 | − if (key->type == &key_type_encrypted) | |
| 88 | − return (struct ecryptfs_auth_tok *) | |
| 89 | − (&((struct encrypted_key_payload *)key->payload.data[0])->payload_data); | |
| 90 | − else | |
| 87 | + struct encrypted_key_payload *payload; | |
| 88 | + | |
| 89 | + if (key->type != &key_type_encrypted) | |
| 91 | 90 | return NULL; |
| 91 | + | |
| 92 | + payload = key->payload.data[0]; | |
| 93 | + if (!payload) | |
| 94 | + return ERR_PTR(-EKEYREVOKED); | |
| 95 | + | |
| 96 | + return (struct ecryptfs_auth_tok *)payload->payload_data; | |
| 92 | 97 | } |
| 93 | 98 | |
| 94 | 99 | static inline struct key *ecryptfs_get_encrypted_key(char *sig) |
| @@ -114,12 +119,17 @@ static inline struct ecryptfs_auth_tok * · 19 unmodified lines | ||
| 114 | 119 | ecryptfs_get_key_payload_data(struct key *key) |
| 115 | 120 | { |
| 116 | 121 | struct ecryptfs_auth_tok *auth_tok; |
| 122 | + struct user_key_payload *ukp; | |
| 117 | 123 | |
| 118 | 124 | auth_tok = ecryptfs_get_encrypted_key_payload_data(key); |
| 119 | − if (!auth_tok) | |
| 120 | − return (struct ecryptfs_auth_tok *)user_key_payload_locked(key)->data; | |
| 121 | − else | |
| 125 | + if (auth_tok) | |
| 122 | 126 | return auth_tok; |
| 127 | + | |
| 128 | + ukp = user_key_payload_locked(key); | |
| 129 | + if (!ukp) | |
| 130 | + return ERR_PTR(-EKEYREVOKED); | |
| 131 | + | |
| 132 | + return (struct ecryptfs_auth_tok *)ukp->data; | |
| 123 | 133 | } |
| 124 | 134 | |
| 125 | 135 | #define ECRYPTFS_MAX_KEYSET_SIZE 1024 |
| @@ -459,7 +459,8 @@ out: · 458 unmodified lines | ||
| 459 | 459 | * @auth_tok_key: key containing the authentication token |
| 460 | 460 | * @auth_tok: authentication token |
| 461 | 461 | * |
| 462 | − * Returns zero on valid auth tok; -EINVAL otherwise | |
| 462 | + * Returns zero on valid auth tok; -EINVAL if the payload is invalid; or | |
| 463 | + * -EKEYREVOKED if the key was revoked before we acquired its semaphore. | |
| 463 | 464 | */ |
| 464 | 465 | static int |
| 465 | 466 | ecryptfs_verify_auth_tok_from_key(struct key *auth_tok_key, |
| @@ -468,6 +469,12 @@ ecryptfs_verify_auth_tok_from_key(struct key *auth_tok_key, · 2 unmodified lines | ||
| 468 | 469 | int rc = 0; |
| 469 | 470 | |
| 470 | 471 | (*auth_tok) = ecryptfs_get_key_payload_data(auth_tok_key); |
| 472 | + if (IS_ERR(*auth_tok)) { | |
| 473 | + rc = PTR_ERR(*auth_tok); | |
| 474 | + *auth_tok = NULL; | |
| 475 | + goto out; | |
| 476 | + } | |
| 477 | + | |
| 471 | 478 | if (ecryptfs_verify_version((*auth_tok)->version)) { |
| 472 | 479 | printk(KERN_ERR "Data structure version mismatch. Userspace " |
| 473 | 480 | "tools must match eCryptfs kernel module with major " |
| @@ -331,6 +331,13 @@ static void fscache_objlist_config(struct fscache_objlist_data *data) · 330 unmodified lines | ||
| 331 | 331 | rcu_read_lock(); |
| 332 | 332 | |
| 333 | 333 | confkey = user_key_payload_rcu(key); |
| 334 | + if (!confkey) { | |
| 335 | + /* key was revoked */ | |
| 336 | + rcu_read_unlock(); | |
| 337 | + key_put(key); | |
| 338 | + goto no_config; | |
| 339 | + } | |
| 340 | + | |
| 334 | 341 | buf = confkey->data; |
| 335 | 342 | |
| 336 | 343 | for (len = confkey->datalen - 1; len >= 0; len--) { |
| @@ -138,6 +138,11 @@ struct key_restriction { · 137 unmodified lines | ||
| 138 | 138 | struct key_type *keytype; |
| 139 | 139 | }; |
| 140 | 140 | |
| 141 | +enum key_state { | |
| 142 | + KEY_IS_UNINSTANTIATED, | |
| 143 | + KEY_IS_POSITIVE, /* Positively instantiated */ | |
| 144 | +}; | |
| 145 | + | |
| 141 | 146 | /*****************************************************************************/ |
| 142 | 147 | /* |
| 143 | 148 | * authentication token / access credential / keyring |
| @@ -169,6 +174,7 @@ struct key { · 25 unmodified lines | ||
| 169 | 174 | * - may not match RCU dereferenced payload |
| 170 | 175 | * - payload should contain own length |
| 171 | 176 | */ |
| 177 | + short state; /* Key state (+) or rejection error (-) */ | |
| 172 | 178 | |
| 173 | 179 | #ifdef KEY_DEBUGGING |
| 174 | 180 | unsigned magic; |
| @@ -176,18 +182,16 @@ struct key { · 1 unmodified line | ||
| 176 | 182 | #endif |
| 177 | 183 | |
| 178 | 184 | unsigned long flags; /* status flags (change with bitops) */ |
| 179 | −#define KEY_FLAG_INSTANTIATED 0 /* set if key has been instantiated */ | |
| 180 | −#define KEY_FLAG_DEAD 1 /* set if key type has been deleted */ | |
| 181 | −#define KEY_FLAG_REVOKED 2 /* set if key had been revoked */ | |
| 182 | −#define KEY_FLAG_IN_QUOTA 3 /* set if key consumes quota */ | |
| 183 | −#define KEY_FLAG_USER_CONSTRUCT 4 /* set if key is being constructed in userspace */ | |
| 184 | −#define KEY_FLAG_NEGATIVE 5 /* set if key is negative */ | |
| 185 | −#define KEY_FLAG_ROOT_CAN_CLEAR 6 /* set if key can be cleared by root without permission */ | |
| 186 | −#define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */ | |
| 187 | −#define KEY_FLAG_BUILTIN 8 /* set if key is built in to the kernel */ | |
| 188 | −#define KEY_FLAG_ROOT_CAN_INVAL 9 /* set if key can be invalidated by root without permission */ | |
| 189 | −#define KEY_FLAG_KEEP 10 /* set if key should not be removed */ | |
| 190 | −#define KEY_FLAG_UID_KEYRING 11 /* set if key is a user or user session keyring */ | |
| 185 | +#define KEY_FLAG_DEAD 0 /* set if key type has been deleted */ | |
| 186 | +#define KEY_FLAG_REVOKED 1 /* set if key had been revoked */ | |
| 187 | +#define KEY_FLAG_IN_QUOTA 2 /* set if key consumes quota */ | |
| 188 | +#define KEY_FLAG_USER_CONSTRUCT 3 /* set if key is being constructed in userspace */ | |
| 189 | +#define KEY_FLAG_ROOT_CAN_CLEAR 4 /* set if key can be cleared by root without permission */ | |
| 190 | +#define KEY_FLAG_INVALIDATED 5 /* set if key has been invalidated */ | |
| 191 | +#define KEY_FLAG_BUILTIN 6 /* set if key is built in to the kernel */ | |
| 192 | +#define KEY_FLAG_ROOT_CAN_INVAL 7 /* set if key can be invalidated by root without permission */ | |
| 193 | +#define KEY_FLAG_KEEP 8 /* set if key should not be removed */ | |
| 194 | +#define KEY_FLAG_UID_KEYRING 9 /* set if key is a user or user session keyring */ | |
| 191 | 195 | |
| 192 | 196 | /* the key type and key description string |
| 193 | 197 | * - the desc is used to match a key against search criteria |
| @@ -213,7 +217,6 @@ struct key { · 19 unmodified lines | ||
| 213 | 217 | struct list_head name_link; |
| 214 | 218 | struct assoc_array keys; |
| 215 | 219 | }; |
| 216 | − int reject_error; | |
| 217 | 220 | }; |
| 218 | 221 | |
| 219 | 222 | /* This is set on a keyring to restrict the addition of a link to a key |
| @@ -353,17 +356,27 @@ extern void key_set_timeout(struct key *, unsigned); · 133 unmodified lines | ||
| 353 | 356 | #define KEY_NEED_SETATTR 0x20 /* Require permission to change attributes */ |
| 354 | 357 | #define KEY_NEED_ALL 0x3f /* All the above permissions */ |
| 355 | 358 | |
| 359 | +static inline short key_read_state(const struct key *key) | |
| 360 | +{ | |
| 361 | + /* Barrier versus mark_key_instantiated(). */ | |
| 362 | + return smp_load_acquire(&key->state); | |
| 363 | +} | |
| 364 | + | |
| 356 | 365 | /** |
| 357 | − * key_is_instantiated - Determine if a key has been positively instantiated | |
| 366 | + * key_is_positive - Determine if a key has been positively instantiated | |
| 358 | 367 | * @key: The key to check. |
| 359 | 368 | * |
| 360 | 369 | * Return true if the specified key has been positively instantiated, false |
| 361 | 370 | * otherwise. |
| 362 | 371 | */ |
| 363 | −static inline bool key_is_instantiated(const struct key *key) | |
| 372 | +static inline bool key_is_positive(const struct key *key) | |
| 373 | +{ | |
| 374 | + return key_read_state(key) == KEY_IS_POSITIVE; | |
| 375 | +} | |
| 376 | + | |
| 377 | +static inline bool key_is_negative(const struct key *key) | |
| 364 | 378 | { |
| 365 | − return test_bit(KEY_FLAG_INSTANTIATED, &key->flags) && | |
| 366 | − !test_bit(KEY_FLAG_NEGATIVE, &key->flags); | |
| 379 | + return key_read_state(key) < 0; | |
| 367 | 380 | } |
| 368 | 381 | |
| 369 | 382 | #define dereference_key_rcu(KEY) \ |
| @@ -87,6 +87,12 @@ static int digsig_verify_rsa(struct key *key, · 86 unmodified lines | ||
| 87 | 87 | down_read(&key->sem); |
| 88 | 88 | ukp = user_key_payload_locked(key); |
| 89 | 89 | |
| 90 | + if (!ukp) { | |
| 91 | + /* key was revoked before we acquired its semaphore */ | |
| 92 | + err = -EKEYREVOKED; | |
| 93 | + goto err1; | |
| 94 | + } | |
| 95 | + | |
| 90 | 96 | if (ukp->datalen < sizeof(*pkh)) |
| 91 | 97 | goto err1; |
| 92 | 98 | |
| @@ -224,7 +224,7 @@ static int dns_resolver_match_preparse(struct key_match_data *match_data) · 223 unmodified lines | ||
| 224 | 224 | static void dns_resolver_describe(const struct key *key, struct seq_file *m) |
| 225 | 225 | { |
| 226 | 226 | seq_puts(m, key->description); |
| 227 | − if (key_is_instantiated(key)) { | |
| 227 | + if (key_is_positive(key)) { | |
| 228 | 228 | int err = PTR_ERR(key->payload.data[dns_key_error]); |
| 229 | 229 | |
| 230 | 230 | if (err) |
| @@ -585,13 +585,14 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data · 584 unmodified lines | ||
| 585 | 585 | struct vfs_ns_cap_data data, *nscaps = &data; |
| 586 | 586 | struct vfs_cap_data *caps = (struct vfs_cap_data *) &data; |
| 587 | 587 | kuid_t rootkuid; |
| 588 | − struct user_namespace *fs_ns = inode->i_sb->s_user_ns; | |
| 588 | + struct user_namespace *fs_ns; | |
| 589 | 589 | |
| 590 | 590 | memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data)); |
| 591 | 591 | |
| 592 | 592 | if (!inode) |
| 593 | 593 | return -ENODATA; |
| 594 | 594 | |
| 595 | + fs_ns = inode->i_sb->s_user_ns; | |
| 595 | 596 | size = __vfs_getxattr((struct dentry *)dentry, inode, |
| 596 | 597 | XATTR_NAME_CAPS, &data, XATTR_CAPS_SZ); |
| 597 | 598 | if (size == -ENODATA || size == -EOPNOTSUPP) |
| @@ -45,6 +45,7 @@ config BIG_KEYS · 44 unmodified lines | ||
| 45 | 45 | bool "Large payload keys" |
| 46 | 46 | depends on KEYS |
| 47 | 47 | depends on TMPFS |
| 48 | + select CRYPTO | |
| 48 | 49 | select CRYPTO_AES |
| 49 | 50 | select CRYPTO_GCM |
| 50 | 51 | help |
| @@ -247,7 +247,7 @@ void big_key_revoke(struct key *key) · 246 unmodified lines | ||
| 247 | 247 | |
| 248 | 248 | /* clear the quota */ |
| 249 | 249 | key_payload_reserve(key, 0); |
| 250 | − if (key_is_instantiated(key) && | |
| 250 | + if (key_is_positive(key) && | |
| 251 | 251 | (size_t)key->payload.data[big_key_len] > BIG_KEY_FILE_THRESHOLD) |
| 252 | 252 | vfs_truncate(path, 0); |
| 253 | 253 | } |
| @@ -279,7 +279,7 @@ void big_key_describe(const struct key *key, struct seq_file *m) · 25 unmodified lines | ||
| 279 | 279 | |
| 280 | 280 | seq_puts(m, key->description); |
| 281 | 281 | |
| 282 | − if (key_is_instantiated(key)) | |
| 282 | + if (key_is_positive(key)) | |
| 283 | 283 | seq_printf(m, ": %zu [%s]", |
| 284 | 284 | datalen, |
| 285 | 285 | datalen > BIG_KEY_FILE_THRESHOLD ? "file" : "buff"); |
| @@ -309,6 +309,13 @@ static struct key *request_user_key(const char *master_desc, const u8 **master_k · 308 unmodified lines | ||
| 309 | 309 | |
| 310 | 310 | down_read(&ukey->sem); |
| 311 | 311 | upayload = user_key_payload_locked(ukey); |
| 312 | + if (!upayload) { | |
| 313 | + /* key was revoked before we acquired its semaphore */ | |
| 314 | + up_read(&ukey->sem); | |
| 315 | + key_put(ukey); | |
| 316 | + ukey = ERR_PTR(-EKEYREVOKED); | |
| 317 | + goto error; | |
| 318 | + } | |
| 312 | 319 | *master_key = upayload->data; |
| 313 | 320 | *master_keylen = upayload->datalen; |
| 314 | 321 | error: |
| @@ -847,7 +854,7 @@ static int encrypted_update(struct key *key, struct key_preparsed_payload *prep) · 532 unmodified lines | ||
| 847 | 854 | size_t datalen = prep->datalen; |
| 848 | 855 | int ret = 0; |
| 849 | 856 | |
| 850 | − if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) | |
| 857 | + if (key_is_negative(key)) | |
| 851 | 858 | return -ENOKEY; |
| 852 | 859 | if (datalen <= 0 || datalen > 32767 || !prep->data) |
| 853 | 860 | return -EINVAL; |
| @@ -129,15 +129,15 @@ static noinline void key_gc_unused_keys(struct list_head *keys) · 128 unmodified lines | ||
| 129 | 129 | while (!list_empty(keys)) { |
| 130 | 130 | struct key *key = |
| 131 | 131 | list_entry(keys->next, struct key, graveyard_link); |
| 132 | + short state = key->state; | |
| 133 | + | |
| 132 | 134 | list_del(&key->graveyard_link); |
| 133 | 135 | |
| 134 | 136 | kdebug("- %u", key->serial); |
| 135 | 137 | key_check(key); |
| 136 | 138 | |
| 137 | 139 | /* Throw away the key data if the key is instantiated */ |
| 138 | − if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags) && | |
| 139 | − !test_bit(KEY_FLAG_NEGATIVE, &key->flags) && | |
| 140 | − key->type->destroy) | |
| 140 | + if (state == KEY_IS_POSITIVE && key->type->destroy) | |
| 141 | 141 | key->type->destroy(key); |
| 142 | 142 | |
| 143 | 143 | security_key_free(key); |
| @@ -151,7 +151,7 @@ static noinline void key_gc_unused_keys(struct list_head *keys) · 7 unmodified lines | ||
| 151 | 151 | } |
| 152 | 152 | |
| 153 | 153 | atomic_dec(&key->user->nkeys); |
| 154 | − if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) | |
| 154 | + if (state != KEY_IS_UNINSTANTIATED) | |
| 155 | 155 | atomic_dec(&key->user->nikeys); |
| 156 | 156 | |
| 157 | 157 | key_user_put(key->user); |
| @@ -401,6 +401,18 @@ int key_payload_reserve(struct key *key, size_t datalen) · 400 unmodified lines | ||
| 401 | 401 | } |
| 402 | 402 | EXPORT_SYMBOL(key_payload_reserve); |
| 403 | 403 | |
| 404 | +/* | |
| 405 | + * Change the key state to being instantiated. | |
| 406 | + */ | |
| 407 | +static void mark_key_instantiated(struct key *key, int reject_error) | |
| 408 | +{ | |
| 409 | + /* Commit the payload before setting the state; barrier versus | |
| 410 | + * key_read_state(). | |
| 411 | + */ | |
| 412 | + smp_store_release(&key->state, | |
| 413 | + (reject_error < 0) ? reject_error : KEY_IS_POSITIVE); | |
| 414 | +} | |
| 415 | + | |
| 404 | 416 | /* |
| 405 | 417 | * Instantiate a key and link it into the target keyring atomically. Must be |
| 406 | 418 | * called with the target keyring's semaphore writelocked. The target key's |
| @@ -424,14 +436,14 @@ static int __key_instantiate_and_link(struct key *key, · 17 unmodified lines | ||
| 424 | 436 | mutex_lock(&key_construction_mutex); |
| 425 | 437 | |
| 426 | 438 | /* can't instantiate twice */ |
| 427 | − if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { | |
| 439 | + if (key->state == KEY_IS_UNINSTANTIATED) { | |
| 428 | 440 | /* instantiate the key */ |
| 429 | 441 | ret = key->type->instantiate(key, prep); |
| 430 | 442 | |
| 431 | 443 | if (ret == 0) { |
| 432 | 444 | /* mark the key as being instantiated */ |
| 433 | 445 | atomic_inc(&key->user->nikeys); |
| 434 | − set_bit(KEY_FLAG_INSTANTIATED, &key->flags); | |
| 446 | + mark_key_instantiated(key, 0); | |
| 435 | 447 | |
| 436 | 448 | if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) |
| 437 | 449 | awaken = 1; |
| @@ -577,13 +589,10 @@ int key_reject_and_link(struct key *key, · 139 unmodified lines | ||
| 577 | 589 | mutex_lock(&key_construction_mutex); |
| 578 | 590 | |
| 579 | 591 | /* can't instantiate twice */ |
| 580 | − if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { | |
| 592 | + if (key->state == KEY_IS_UNINSTANTIATED) { | |
| 581 | 593 | /* mark the key as being negatively instantiated */ |
| 582 | 594 | atomic_inc(&key->user->nikeys); |
| 583 | − key->reject_error = -error; | |
| 584 | − smp_wmb(); | |
| 585 | − set_bit(KEY_FLAG_NEGATIVE, &key->flags); | |
| 586 | − set_bit(KEY_FLAG_INSTANTIATED, &key->flags); | |
| 595 | + mark_key_instantiated(key, -error); | |
| 587 | 596 | now = current_kernel_time(); |
| 588 | 597 | key->expiry = now.tv_sec + timeout; |
| 589 | 598 | key_schedule_gc(key->expiry + key_gc_delay); |
| @@ -752,8 +761,8 @@ static inline key_ref_t __key_update(key_ref_t key_ref, · 162 unmodified lines | ||
| 752 | 761 | |
| 753 | 762 | ret = key->type->update(key, prep); |
| 754 | 763 | if (ret == 0) |
| 755 | − /* updating a negative key instantiates it */ | |
| 756 | − clear_bit(KEY_FLAG_NEGATIVE, &key->flags); | |
| 764 | + /* Updating a negative key positively instantiates it */ | |
| 765 | + mark_key_instantiated(key, 0); | |
| 757 | 766 | |
| 758 | 767 | up_write(&key->sem); |
| 759 | 768 | |
| @@ -936,6 +945,16 @@ error: · 176 unmodified lines | ||
| 936 | 945 | */ |
| 937 | 946 | __key_link_end(keyring, &index_key, edit); |
| 938 | 947 | |
| 948 | + key = key_ref_to_ptr(key_ref); | |
| 949 | + if (test_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) { | |
| 950 | + ret = wait_for_key_construction(key, true); | |
| 951 | + if (ret < 0) { | |
| 952 | + key_ref_put(key_ref); | |
| 953 | + key_ref = ERR_PTR(ret); | |
| 954 | + goto error_free_prep; | |
| 955 | + } | |
| 956 | + } | |
| 957 | + | |
| 939 | 958 | key_ref = __key_update(key_ref, &prep); |
| 940 | 959 | goto error_free_prep; |
| 941 | 960 | } |
| @@ -986,8 +1005,8 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) · 44 unmodified lines | ||
| 986 | 1005 | |
| 987 | 1006 | ret = key->type->update(key, &prep); |
| 988 | 1007 | if (ret == 0) |
| 989 | − /* updating a negative key instantiates it */ | |
| 990 | − clear_bit(KEY_FLAG_NEGATIVE, &key->flags); | |
| 1008 | + /* Updating a negative key positively instantiates it */ | |
| 1009 | + mark_key_instantiated(key, 0); | |
| 991 | 1010 | |
| 992 | 1011 | up_write(&key->sem); |
| 993 | 1012 | |
| @@ -766,10 +766,9 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) · 765 unmodified lines | ||
| 766 | 766 | |
| 767 | 767 | key = key_ref_to_ptr(key_ref); |
| 768 | 768 | |
| 769 | − if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { | |
| 770 | − ret = -ENOKEY; | |
| 771 | − goto error2; | |
| 772 | − } | |
| 769 | + ret = key_read_state(key); | |
| 770 | + if (ret < 0) | |
| 771 | + goto error2; /* Negatively instantiated */ | |
| 773 | 772 | |
| 774 | 773 | /* see if we can read it directly */ |
| 775 | 774 | ret = key_permission(key_ref, KEY_NEED_READ); |
| @@ -901,7 +900,7 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group) · 125 unmodified lines | ||
| 901 | 900 | atomic_dec(&key->user->nkeys); |
| 902 | 901 | atomic_inc(&newowner->nkeys); |
| 903 | 902 | |
| 904 | − if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { | |
| 903 | + if (key->state != KEY_IS_UNINSTANTIATED) { | |
| 905 | 904 | atomic_dec(&key->user->nikeys); |
| 906 | 905 | atomic_inc(&newowner->nikeys); |
| 907 | 906 | } |
| @@ -414,7 +414,7 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m) · 413 unmodified lines | ||
| 414 | 414 | else |
| 415 | 415 | seq_puts(m, "[anon]"); |
| 416 | 416 | |
| 417 | − if (key_is_instantiated(keyring)) { | |
| 417 | + if (key_is_positive(keyring)) { | |
| 418 | 418 | if (keyring->keys.nr_leaves_on_tree != 0) |
| 419 | 419 | seq_printf(m, ": %lu", keyring->keys.nr_leaves_on_tree); |
| 420 | 420 | else |
| @@ -553,7 +553,8 @@ static int keyring_search_iterator(const void *object, void *iterator_data) · 132 unmodified lines | ||
| 553 | 553 | { |
| 554 | 554 | struct keyring_search_context *ctx = iterator_data; |
| 555 | 555 | const struct key *key = keyring_ptr_to_key(object); |
| 556 | − unsigned long kflags = key->flags; | |
| 556 | + unsigned long kflags = READ_ONCE(key->flags); | |
| 557 | + short state = READ_ONCE(key->state); | |
| 557 | 558 | |
| 558 | 559 | kenter("{%d}", key->serial); |
| 559 | 560 | |
| @@ -565,6 +566,8 @@ static int keyring_search_iterator(const void *object, void *iterator_data) · 5 unmodified lines | ||
| 565 | 566 | |
| 566 | 567 | /* skip invalidated, revoked and expired keys */ |
| 567 | 568 | if (ctx->flags & KEYRING_SEARCH_DO_STATE_CHECK) { |
| 569 | + time_t expiry = READ_ONCE(key->expiry); | |
| 570 | + | |
| 568 | 571 | if (kflags & ((1 << KEY_FLAG_INVALIDATED) | |
| 569 | 572 | (1 << KEY_FLAG_REVOKED))) { |
| 570 | 573 | ctx->result = ERR_PTR(-EKEYREVOKED); |
| @@ -572,7 +575,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data) · 1 unmodified line | ||
| 572 | 575 | goto skipped; |
| 573 | 576 | } |
| 574 | 577 | |
| 575 | − if (key->expiry && ctx->now.tv_sec >= key->expiry) { | |
| 578 | + if (expiry && ctx->now.tv_sec >= expiry) { | |
| 576 | 579 | if (!(ctx->flags & KEYRING_SEARCH_SKIP_EXPIRED)) |
| 577 | 580 | ctx->result = ERR_PTR(-EKEYEXPIRED); |
| 578 | 581 | kleave(" = %d [expire]", ctx->skipped_ret); |
| @@ -597,9 +600,8 @@ static int keyring_search_iterator(const void *object, void *iterator_data) · 18 unmodified lines | ||
| 597 | 600 | |
| 598 | 601 | if (ctx->flags & KEYRING_SEARCH_DO_STATE_CHECK) { |
| 599 | 602 | /* we set a different error code if we pass a negative key */ |
| 600 | − if (kflags & (1 << KEY_FLAG_NEGATIVE)) { | |
| 601 | − smp_rmb(); | |
| 602 | − ctx->result = ERR_PTR(key->reject_error); | |
| 603 | + if (state < 0) { | |
| 604 | + ctx->result = ERR_PTR(state); | |
| 603 | 605 | kleave(" = %d [neg]", ctx->skipped_ret); |
| 604 | 606 | goto skipped; |
| 605 | 607 | } |
| @@ -88,7 +88,8 @@ EXPORT_SYMBOL(key_task_permission); · 87 unmodified lines | ||
| 88 | 88 | */ |
| 89 | 89 | int key_validate(const struct key *key) |
| 90 | 90 | { |
| 91 | − unsigned long flags = key->flags; | |
| 91 | + unsigned long flags = READ_ONCE(key->flags); | |
| 92 | + time_t expiry = READ_ONCE(key->expiry); | |
| 92 | 93 | |
| 93 | 94 | if (flags & (1 << KEY_FLAG_INVALIDATED)) |
| 94 | 95 | return -ENOKEY; |
| @@ -99,9 +100,9 @@ int key_validate(const struct key *key) · 4 unmodified lines | ||
| 99 | 100 | return -EKEYREVOKED; |
| 100 | 101 | |
| 101 | 102 | /* check it hasn't expired */ |
| 102 | − if (key->expiry) { | |
| 103 | + if (expiry) { | |
| 103 | 104 | struct timespec now = current_kernel_time(); |
| 104 | − if (now.tv_sec >= key->expiry) | |
| 105 | + if (now.tv_sec >= expiry) | |
| 105 | 106 | return -EKEYEXPIRED; |
| 106 | 107 | } |
| 107 | 108 | |
| @@ -179,9 +179,12 @@ static int proc_keys_show(struct seq_file *m, void *v) · 178 unmodified lines | ||
| 179 | 179 | struct rb_node *_p = v; |
| 180 | 180 | struct key *key = rb_entry(_p, struct key, serial_node); |
| 181 | 181 | struct timespec now; |
| 182 | + time_t expiry; | |
| 182 | 183 | unsigned long timo; |
| 184 | + unsigned long flags; | |
| 183 | 185 | key_ref_t key_ref, skey_ref; |
| 184 | 186 | char xbuf[16]; |
| 187 | + short state; | |
| 185 | 188 | int rc; |
| 186 | 189 | |
| 187 | 190 | struct keyring_search_context ctx = { |
| @@ -217,12 +220,13 @@ static int proc_keys_show(struct seq_file *m, void *v) · 29 unmodified lines | ||
| 217 | 220 | rcu_read_lock(); |
| 218 | 221 | |
| 219 | 222 | /* come up with a suitable timeout value */ |
| 220 | − if (key->expiry == 0) { | |
| 223 | + expiry = READ_ONCE(key->expiry); | |
| 224 | + if (expiry == 0) { | |
| 221 | 225 | memcpy(xbuf, "perm", 5); |
| 222 | − } else if (now.tv_sec >= key->expiry) { | |
| 226 | + } else if (now.tv_sec >= expiry) { | |
| 223 | 227 | memcpy(xbuf, "expd", 5); |
| 224 | 228 | } else { |
| 225 | − timo = key->expiry - now.tv_sec; | |
| 229 | + timo = expiry - now.tv_sec; | |
| 226 | 230 | |
| 227 | 231 | if (timo < 60) |
| 228 | 232 | sprintf(xbuf, "%lus", timo); |
| @@ -236,18 +240,21 @@ static int proc_keys_show(struct seq_file *m, void *v) · 7 unmodified lines | ||
| 236 | 240 | sprintf(xbuf, "%luw", timo / (60*60*24*7)); |
| 237 | 241 | } |
| 238 | 242 | |
| 239 | −#define showflag(KEY, LETTER, FLAG) \ | |
| 240 | − (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') | |
| 243 | + state = key_read_state(key); | |
| 241 | 244 | |
| 245 | +#define showflag(FLAGS, LETTER, FLAG) \ | |
| 246 | + ((FLAGS & (1 << FLAG)) ? LETTER : '-') | |
| 247 | + | |
| 248 | + flags = READ_ONCE(key->flags); | |
| 242 | 249 | seq_printf(m, "%08x %c%c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ", |
| 243 | 250 | key->serial, |
| 244 | − showflag(key, 'I', KEY_FLAG_INSTANTIATED), | |
| 245 | − showflag(key, 'R', KEY_FLAG_REVOKED), | |
| 246 | − showflag(key, 'D', KEY_FLAG_DEAD), | |
| 247 | − showflag(key, 'Q', KEY_FLAG_IN_QUOTA), | |
| 248 | − showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), | |
| 249 | − showflag(key, 'N', KEY_FLAG_NEGATIVE), | |
| 250 | − showflag(key, 'i', KEY_FLAG_INVALIDATED), | |
| 251 | + state != KEY_IS_UNINSTANTIATED ? 'I' : '-', | |
| 252 | + showflag(flags, 'R', KEY_FLAG_REVOKED), | |
| 253 | + showflag(flags, 'D', KEY_FLAG_DEAD), | |
| 254 | + showflag(flags, 'Q', KEY_FLAG_IN_QUOTA), | |
| 255 | + showflag(flags, 'U', KEY_FLAG_USER_CONSTRUCT), | |
| 256 | + state < 0 ? 'N' : '-', | |
| 257 | + showflag(flags, 'i', KEY_FLAG_INVALIDATED), | |
| 251 | 258 | refcount_read(&key->usage), |
| 252 | 259 | xbuf, |
| 253 | 260 | key->perm, |
| @@ -730,7 +730,7 @@ try_again: · 729 unmodified lines | ||
| 730 | 730 | |
| 731 | 731 | ret = -EIO; |
| 732 | 732 | if (!(lflags & KEY_LOOKUP_PARTIAL) && |
| 733 | − !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) | |
| 733 | + key_read_state(key) == KEY_IS_UNINSTANTIATED) | |
| 734 | 734 | goto invalid_key; |
| 735 | 735 | |
| 736 | 736 | /* check the permissions */ |
| @@ -595,10 +595,9 @@ int wait_for_key_construction(struct key *key, bool intr) · 594 unmodified lines | ||
| 595 | 595 | intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); |
| 596 | 596 | if (ret) |
| 597 | 597 | return -ERESTARTSYS; |
| 598 | − if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { | |
| 599 | − smp_rmb(); | |
| 600 | − return key->reject_error; | |
| 601 | − } | |
| 598 | + ret = key_read_state(key); | |
| 599 | + if (ret < 0) | |
| 600 | + return ret; | |
| 602 | 601 | return key_validate(key); |
| 603 | 602 | } |
| 604 | 603 | EXPORT_SYMBOL(wait_for_key_construction); |
| @@ -73,7 +73,7 @@ static void request_key_auth_describe(const struct key *key, · 72 unmodified lines | ||
| 73 | 73 | |
| 74 | 74 | seq_puts(m, "key:"); |
| 75 | 75 | seq_puts(m, key->description); |
| 76 | − if (key_is_instantiated(key)) | |
| 76 | + if (key_is_positive(key)) | |
| 77 | 77 | seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len); |
| 78 | 78 | } |
| 79 | 79 | |
| @@ -1066,7 +1066,7 @@ static int trusted_update(struct key *key, struct key_preparsed_payload *prep) · 1065 unmodified lines | ||
| 1066 | 1066 | char *datablob; |
| 1067 | 1067 | int ret = 0; |
| 1068 | 1068 | |
| 1069 | − if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) | |
| 1069 | + if (key_is_negative(key)) | |
| 1070 | 1070 | return -ENOKEY; |
| 1071 | 1071 | p = key->payload.data[0]; |
| 1072 | 1072 | if (!p->migratable) |
| @@ -114,7 +114,7 @@ int user_update(struct key *key, struct key_preparsed_payload *prep) · 113 unmodified lines | ||
| 114 | 114 | |
| 115 | 115 | /* attach the new data, displacing the old */ |
| 116 | 116 | key->expiry = prep->expiry; |
| 117 | − if (!test_bit(KEY_FLAG_NEGATIVE, &key->flags)) | |
| 117 | + if (key_is_positive(key)) | |
| 118 | 118 | zap = dereference_key_locked(key); |
| 119 | 119 | rcu_assign_keypointer(key, prep->payload.data[0]); |
| 120 | 120 | prep->payload.data[0] = NULL; |
| @@ -162,7 +162,7 @@ EXPORT_SYMBOL_GPL(user_destroy); · 41 unmodified lines | ||
| 162 | 162 | void user_describe(const struct key *key, struct seq_file *m) |
| 163 | 163 | { |
| 164 | 164 | seq_puts(m, key->description); |
| 165 | − if (key_is_instantiated(key)) | |
| 165 | + if (key_is_positive(key)) | |
| 166 | 166 | seq_printf(m, ": %u", key->datalen); |
| 167 | 167 | } |
| 168 | 168 | |