Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KEYS: Add invalidation support

Add support for invalidating a key - which renders it immediately invisible to
further searches and causes the garbage collector to immediately wake up,
remove it from keyrings and then destroy it when it's no longer referenced.

It's better not to do this with keyctl_revoke() as that marks the key to start
returning -EKEYREVOKED to searches when what is actually desired is to have the
key refetched.

To invalidate a key the caller must be granted SEARCH permission by the key.
This may be too strict. It may be better to also permit invalidation if the
caller has any of READ, WRITE or SETATTR permission.

The primary use for this is to evict keys that are cached in special keyrings,
such as the DNS resolver or an ID mapper.

Signed-off-by: David Howells <dhowells@redhat.com>

+131 -28
+17
Documentation/security/keys.txt
··· 805 805 kernel and resumes executing userspace. 806 806 807 807 808 + (*) Invalidate a key. 809 + 810 + long keyctl(KEYCTL_INVALIDATE, key_serial_t key); 811 + 812 + This function marks a key as being invalidated and then wakes up the 813 + garbage collector. The garbage collector immediately removes invalidated 814 + keys from all keyrings and deletes the key when its reference count 815 + reaches zero. 816 + 817 + Keys that are marked invalidated become invisible to normal key operations 818 + immediately, though they are still visible in /proc/keys until deleted 819 + (they're marked with an 'i' flag). 820 + 821 + A process must have search permission on the key for this function to be 822 + successful. 823 + 824 + 808 825 =============== 809 826 KERNEL SERVICES 810 827 ===============
+3
include/linux/key.h
··· 160 160 #define KEY_FLAG_USER_CONSTRUCT 4 /* set if key is being constructed in userspace */ 161 161 #define KEY_FLAG_NEGATIVE 5 /* set if key is negative */ 162 162 #define KEY_FLAG_ROOT_CAN_CLEAR 6 /* set if key can be cleared by root without permission */ 163 + #define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */ 163 164 164 165 /* the description string 165 166 * - this is used to match a key against search criteria ··· 204 203 #define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */ 205 204 206 205 extern void key_revoke(struct key *key); 206 + extern void key_invalidate(struct key *key); 207 207 extern void key_put(struct key *key); 208 208 209 209 static inline struct key *key_get(struct key *key) ··· 325 323 #define key_serial(k) 0 326 324 #define key_get(k) ({ NULL; }) 327 325 #define key_revoke(k) do { } while(0) 326 + #define key_invalidate(k) do { } while(0) 328 327 #define key_put(k) do { } while(0) 329 328 #define key_ref_put(k) do { } while(0) 330 329 #define make_key_ref(k, p) NULL
+1
include/linux/keyctl.h
··· 55 55 #define KEYCTL_SESSION_TO_PARENT 18 /* apply session keyring to parent process */ 56 56 #define KEYCTL_REJECT 19 /* reject a partially constructed key */ 57 57 #define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */ 58 + #define KEYCTL_INVALIDATE 21 /* invalidate a key */ 58 59 59 60 #endif /* _LINUX_KEYCTL_H */
+3
security/keys/compat.c
··· 135 135 return compat_keyctl_instantiate_key_iov( 136 136 arg2, compat_ptr(arg3), arg4, arg5); 137 137 138 + case KEYCTL_INVALIDATE: 139 + return keyctl_invalidate_key(arg2); 140 + 138 141 default: 139 142 return -EOPNOTSUPP; 140 143 }
+14 -7
security/keys/gc.c
··· 72 72 } 73 73 74 74 /* 75 + * Schedule a dead links collection run. 76 + */ 77 + void key_schedule_gc_links(void) 78 + { 79 + set_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags); 80 + queue_work(system_nrt_wq, &key_gc_work); 81 + } 82 + 83 + /* 75 84 * Some key's cleanup time was met after it expired, so we need to get the 76 85 * reaper to go through a cycle finding expired keys. 77 86 */ ··· 88 79 { 89 80 kenter(""); 90 81 key_gc_next_run = LONG_MAX; 91 - set_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags); 92 - queue_work(system_nrt_wq, &key_gc_work); 82 + key_schedule_gc_links(); 93 83 } 94 84 95 85 /* ··· 139 131 static void key_gc_keyring(struct key *keyring, time_t limit) 140 132 { 141 133 struct keyring_list *klist; 142 - struct key *key; 143 134 int loop; 144 135 145 136 kenter("%x", key_serial(keyring)); 146 137 147 - if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) 138 + if (keyring->flags & ((1 << KEY_FLAG_INVALIDATED) | 139 + (1 << KEY_FLAG_REVOKED))) 148 140 goto dont_gc; 149 141 150 142 /* scan the keyring looking for dead keys */ ··· 156 148 loop = klist->nkeys; 157 149 smp_rmb(); 158 150 for (loop--; loop >= 0; loop--) { 159 - key = rcu_dereference(klist->keys[loop]); 160 - if (test_bit(KEY_FLAG_DEAD, &key->flags) || 161 - (key->expiry > 0 && key->expiry <= limit)) 151 + struct key *key = rcu_dereference(klist->keys[loop]); 152 + if (key_is_dead(key, limit)) 162 153 goto do_gc; 163 154 } 164 155
+14 -1
security/keys/internal.h
··· 152 152 extern struct work_struct key_gc_work; 153 153 extern unsigned key_gc_delay; 154 154 extern void keyring_gc(struct key *keyring, time_t limit); 155 - extern void key_schedule_gc(time_t expiry_at); 155 + extern void key_schedule_gc(time_t gc_at); 156 + extern void key_schedule_gc_links(void); 156 157 extern void key_gc_keytype(struct key_type *ktype); 157 158 158 159 extern int key_task_permission(const key_ref_t key_ref, ··· 198 197 extern struct key *key_get_instantiation_authkey(key_serial_t target_id); 199 198 200 199 /* 200 + * Determine whether a key is dead. 201 + */ 202 + static inline bool key_is_dead(struct key *key, time_t limit) 203 + { 204 + return 205 + key->flags & ((1 << KEY_FLAG_DEAD) | 206 + (1 << KEY_FLAG_INVALIDATED)) || 207 + (key->expiry > 0 && key->expiry <= limit); 208 + } 209 + 210 + /* 201 211 * keyctl() functions 202 212 */ 203 213 extern long keyctl_get_keyring_ID(key_serial_t, int); ··· 237 225 extern long keyctl_instantiate_key_iov(key_serial_t, 238 226 const struct iovec __user *, 239 227 unsigned, key_serial_t); 228 + extern long keyctl_invalidate_key(key_serial_t); 240 229 241 230 extern long keyctl_instantiate_key_common(key_serial_t, 242 231 const struct iovec __user *,
+22
security/keys/key.c
··· 955 955 EXPORT_SYMBOL(key_revoke); 956 956 957 957 /** 958 + * key_invalidate - Invalidate a key. 959 + * @key: The key to be invalidated. 960 + * 961 + * Mark a key as being invalidated and have it cleaned up immediately. The key 962 + * is ignored by all searches and other operations from this point. 963 + */ 964 + void key_invalidate(struct key *key) 965 + { 966 + kenter("%d", key_serial(key)); 967 + 968 + key_check(key); 969 + 970 + if (!test_bit(KEY_FLAG_INVALIDATED, &key->flags)) { 971 + down_write_nested(&key->sem, 1); 972 + if (!test_and_set_bit(KEY_FLAG_INVALIDATED, &key->flags)) 973 + key_schedule_gc_links(); 974 + up_write(&key->sem); 975 + } 976 + } 977 + EXPORT_SYMBOL(key_invalidate); 978 + 979 + /** 958 980 * register_key_type - Register a type of key. 959 981 * @ktype: The new key type. 960 982 *
+34
security/keys/keyctl.c
··· 375 375 } 376 376 377 377 /* 378 + * Invalidate a key. 379 + * 380 + * The key must be grant the caller Invalidate permission for this to work. 381 + * The key and any links to the key will be automatically garbage collected 382 + * immediately. 383 + * 384 + * If successful, 0 is returned. 385 + */ 386 + long keyctl_invalidate_key(key_serial_t id) 387 + { 388 + key_ref_t key_ref; 389 + long ret; 390 + 391 + kenter("%d", id); 392 + 393 + key_ref = lookup_user_key(id, 0, KEY_SEARCH); 394 + if (IS_ERR(key_ref)) { 395 + ret = PTR_ERR(key_ref); 396 + goto error; 397 + } 398 + 399 + key_invalidate(key_ref_to_ptr(key_ref)); 400 + ret = 0; 401 + 402 + key_ref_put(key_ref); 403 + error: 404 + kleave(" = %ld", ret); 405 + return ret; 406 + } 407 + 408 + /* 378 409 * Clear the specified keyring, creating an empty process keyring if one of the 379 410 * special keyring IDs is used. 380 411 * ··· 1652 1621 (const struct iovec __user *) arg3, 1653 1622 (unsigned) arg4, 1654 1623 (key_serial_t) arg5); 1624 + 1625 + case KEYCTL_INVALIDATE: 1626 + return keyctl_invalidate_key((key_serial_t) arg2); 1655 1627 1656 1628 default: 1657 1629 return -EOPNOTSUPP;
+11 -14
security/keys/keyring.c
··· 382 382 /* otherwise, the top keyring must not be revoked, expired, or 383 383 * negatively instantiated if we are to search it */ 384 384 key_ref = ERR_PTR(-EAGAIN); 385 - if (kflags & ((1 << KEY_FLAG_REVOKED) | (1 << KEY_FLAG_NEGATIVE)) || 385 + if (kflags & ((1 << KEY_FLAG_INVALIDATED) | 386 + (1 << KEY_FLAG_REVOKED) | 387 + (1 << KEY_FLAG_NEGATIVE)) || 386 388 (keyring->expiry && now.tv_sec >= keyring->expiry)) 387 389 goto error_2; 388 390 389 391 /* start processing a new keyring */ 390 392 descend: 391 - if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) 393 + kflags = keyring->flags; 394 + if (kflags & ((1 << KEY_FLAG_INVALIDATED) | 395 + (1 << KEY_FLAG_REVOKED))) 392 396 goto not_this_keyring; 393 397 394 398 keylist = rcu_dereference(keyring->payload.subscriptions); ··· 410 406 if (key->type != type) 411 407 continue; 412 408 413 - /* skip revoked keys and expired keys */ 409 + /* skip invalidated, revoked and expired keys */ 414 410 if (!no_state_check) { 415 - if (kflags & (1 << KEY_FLAG_REVOKED)) 411 + if (kflags & ((1 << KEY_FLAG_INVALIDATED) | 412 + (1 << KEY_FLAG_REVOKED))) 416 413 continue; 417 414 418 415 if (key->expiry && now.tv_sec >= key->expiry) ··· 564 559 key->type->match(key, description)) && 565 560 key_permission(make_key_ref(key, possessed), 566 561 perm) == 0 && 567 - !test_bit(KEY_FLAG_REVOKED, &key->flags) 562 + !(key->flags & ((1 << KEY_FLAG_INVALIDATED) | 563 + (1 << KEY_FLAG_REVOKED))) 568 564 ) 569 565 goto found; 570 566 } ··· 1180 1174 rcu_assign_pointer(keyring->payload.subscriptions, NULL); 1181 1175 call_rcu(&klist->rcu, keyring_clear_rcu_disposal); 1182 1176 } 1183 - } 1184 - 1185 - /* 1186 - * Determine whether a key is dead. 1187 - */ 1188 - static bool key_is_dead(struct key *key, time_t limit) 1189 - { 1190 - return test_bit(KEY_FLAG_DEAD, &key->flags) || 1191 - (key->expiry > 0 && key->expiry <= limit); 1192 1177 } 1193 1178 1194 1179 /*
+10 -5
security/keys/permission.c
··· 87 87 * key_validate - Validate a key. 88 88 * @key: The key to be validated. 89 89 * 90 - * Check that a key is valid, returning 0 if the key is okay, -EKEYREVOKED if 91 - * the key's type has been removed or if the key has been revoked or 92 - * -EKEYEXPIRED if the key has expired. 90 + * Check that a key is valid, returning 0 if the key is okay, -ENOKEY if the 91 + * key is invalidated, -EKEYREVOKED if the key's type has been removed or if 92 + * the key has been revoked or -EKEYEXPIRED if the key has expired. 93 93 */ 94 94 int key_validate(struct key *key) 95 95 { 96 96 struct timespec now; 97 + unsigned long flags = key->flags; 97 98 int ret = 0; 98 99 99 100 if (key) { 101 + ret = -ENOKEY; 102 + if (flags & (1 << KEY_FLAG_INVALIDATED)) 103 + goto error; 104 + 100 105 /* check it's still accessible */ 101 106 ret = -EKEYREVOKED; 102 - if (test_bit(KEY_FLAG_REVOKED, &key->flags) || 103 - test_bit(KEY_FLAG_DEAD, &key->flags)) 107 + if (flags & ((1 << KEY_FLAG_REVOKED) | 108 + (1 << KEY_FLAG_DEAD))) 104 109 goto error; 105 110 106 111 /* check it hasn't expired */
+2 -1
security/keys/proc.c
··· 242 242 #define showflag(KEY, LETTER, FLAG) \ 243 243 (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') 244 244 245 - seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ", 245 + seq_printf(m, "%08x %c%c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ", 246 246 key->serial, 247 247 showflag(key, 'I', KEY_FLAG_INSTANTIATED), 248 248 showflag(key, 'R', KEY_FLAG_REVOKED), ··· 250 250 showflag(key, 'Q', KEY_FLAG_IN_QUOTA), 251 251 showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), 252 252 showflag(key, 'N', KEY_FLAG_NEGATIVE), 253 + showflag(key, 'i', KEY_FLAG_INVALIDATED), 253 254 atomic_read(&key->usage), 254 255 xbuf, 255 256 key->perm,