diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/keys/compat.c | 3 | ||||
-rw-r--r-- | security/keys/gc.c | 21 | ||||
-rw-r--r-- | security/keys/internal.h | 15 | ||||
-rw-r--r-- | security/keys/key.c | 22 | ||||
-rw-r--r-- | security/keys/keyctl.c | 34 | ||||
-rw-r--r-- | security/keys/keyring.c | 25 | ||||
-rw-r--r-- | security/keys/permission.c | 15 | ||||
-rw-r--r-- | security/keys/proc.c | 3 |
8 files changed, 110 insertions, 28 deletions
diff --git a/security/keys/compat.c b/security/keys/compat.c index 4c48e13448f8..fab4f8dda6c6 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c | |||
@@ -135,6 +135,9 @@ asmlinkage long compat_sys_keyctl(u32 option, | |||
135 | return compat_keyctl_instantiate_key_iov( | 135 | return compat_keyctl_instantiate_key_iov( |
136 | arg2, compat_ptr(arg3), arg4, arg5); | 136 | arg2, compat_ptr(arg3), arg4, arg5); |
137 | 137 | ||
138 | case KEYCTL_INVALIDATE: | ||
139 | return keyctl_invalidate_key(arg2); | ||
140 | |||
138 | default: | 141 | default: |
139 | return -EOPNOTSUPP; | 142 | return -EOPNOTSUPP; |
140 | } | 143 | } |
diff --git a/security/keys/gc.c b/security/keys/gc.c index adddaa258d50..61ab7c82ebb1 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c | |||
@@ -72,6 +72,15 @@ void key_schedule_gc(time_t gc_at) | |||
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 | * Some key's cleanup time was met after it expired, so we need to get the | 84 | * Some key's cleanup time was met after it expired, so we need to get the |
76 | * reaper to go through a cycle finding expired keys. | 85 | * reaper to go through a cycle finding expired keys. |
77 | */ | 86 | */ |
@@ -79,8 +88,7 @@ static void key_gc_timer_func(unsigned long data) | |||
79 | { | 88 | { |
80 | kenter(""); | 89 | kenter(""); |
81 | key_gc_next_run = LONG_MAX; | 90 | key_gc_next_run = LONG_MAX; |
82 | set_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags); | 91 | key_schedule_gc_links(); |
83 | queue_work(system_nrt_wq, &key_gc_work); | ||
84 | } | 92 | } |
85 | 93 | ||
86 | /* | 94 | /* |
@@ -131,12 +139,12 @@ void key_gc_keytype(struct key_type *ktype) | |||
131 | static void key_gc_keyring(struct key *keyring, time_t limit) | 139 | static void key_gc_keyring(struct key *keyring, time_t limit) |
132 | { | 140 | { |
133 | struct keyring_list *klist; | 141 | struct keyring_list *klist; |
134 | struct key *key; | ||
135 | int loop; | 142 | int loop; |
136 | 143 | ||
137 | kenter("%x", key_serial(keyring)); | 144 | kenter("%x", key_serial(keyring)); |
138 | 145 | ||
139 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) | 146 | if (keyring->flags & ((1 << KEY_FLAG_INVALIDATED) | |
147 | (1 << KEY_FLAG_REVOKED))) | ||
140 | goto dont_gc; | 148 | goto dont_gc; |
141 | 149 | ||
142 | /* scan the keyring looking for dead keys */ | 150 | /* scan the keyring looking for dead keys */ |
@@ -148,9 +156,8 @@ static void key_gc_keyring(struct key *keyring, time_t limit) | |||
148 | loop = klist->nkeys; | 156 | loop = klist->nkeys; |
149 | smp_rmb(); | 157 | smp_rmb(); |
150 | for (loop--; loop >= 0; loop--) { | 158 | for (loop--; loop >= 0; loop--) { |
151 | key = rcu_dereference(klist->keys[loop]); | 159 | struct key *key = rcu_dereference(klist->keys[loop]); |
152 | if (test_bit(KEY_FLAG_DEAD, &key->flags) || | 160 | if (key_is_dead(key, limit)) |
153 | (key->expiry > 0 && key->expiry <= limit)) | ||
154 | goto do_gc; | 161 | goto do_gc; |
155 | } | 162 | } |
156 | 163 | ||
diff --git a/security/keys/internal.h b/security/keys/internal.h index 65647f825584..f711b094ed41 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
@@ -152,7 +152,8 @@ extern long join_session_keyring(const char *name); | |||
152 | extern struct work_struct key_gc_work; | 152 | extern struct work_struct key_gc_work; |
153 | extern unsigned key_gc_delay; | 153 | extern unsigned key_gc_delay; |
154 | extern void keyring_gc(struct key *keyring, time_t limit); | 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 | extern void key_gc_keytype(struct key_type *ktype); | 157 | extern void key_gc_keytype(struct key_type *ktype); |
157 | 158 | ||
158 | extern int key_task_permission(const key_ref_t key_ref, | 159 | extern int key_task_permission(const key_ref_t key_ref, |
@@ -197,6 +198,17 @@ extern struct key *request_key_auth_new(struct key *target, | |||
197 | extern struct key *key_get_instantiation_authkey(key_serial_t target_id); | 198 | extern struct key *key_get_instantiation_authkey(key_serial_t target_id); |
198 | 199 | ||
199 | /* | 200 | /* |
201 | * Determine whether a key is dead. | ||
202 | */ | ||
203 | static inline bool key_is_dead(struct key *key, time_t limit) | ||
204 | { | ||
205 | return | ||
206 | key->flags & ((1 << KEY_FLAG_DEAD) | | ||
207 | (1 << KEY_FLAG_INVALIDATED)) || | ||
208 | (key->expiry > 0 && key->expiry <= limit); | ||
209 | } | ||
210 | |||
211 | /* | ||
200 | * keyctl() functions | 212 | * keyctl() functions |
201 | */ | 213 | */ |
202 | extern long keyctl_get_keyring_ID(key_serial_t, int); | 214 | extern long keyctl_get_keyring_ID(key_serial_t, int); |
@@ -225,6 +237,7 @@ extern long keyctl_reject_key(key_serial_t, unsigned, unsigned, key_serial_t); | |||
225 | extern long keyctl_instantiate_key_iov(key_serial_t, | 237 | extern long keyctl_instantiate_key_iov(key_serial_t, |
226 | const struct iovec __user *, | 238 | const struct iovec __user *, |
227 | unsigned, key_serial_t); | 239 | unsigned, key_serial_t); |
240 | extern long keyctl_invalidate_key(key_serial_t); | ||
228 | 241 | ||
229 | extern long keyctl_instantiate_key_common(key_serial_t, | 242 | extern long keyctl_instantiate_key_common(key_serial_t, |
230 | const struct iovec __user *, | 243 | const struct iovec __user *, |
diff --git a/security/keys/key.c b/security/keys/key.c index dc628941ecd3..c9bf66ac36e0 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -955,6 +955,28 @@ void key_revoke(struct key *key) | |||
955 | EXPORT_SYMBOL(key_revoke); | 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 | * register_key_type - Register a type of key. | 980 | * register_key_type - Register a type of key. |
959 | * @ktype: The new key type. | 981 | * @ktype: The new key type. |
960 | * | 982 | * |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index fb767c6cd99f..ddb3e05bc5fc 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -375,6 +375,37 @@ error: | |||
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 | * Clear the specified keyring, creating an empty process keyring if one of the | 409 | * Clear the specified keyring, creating an empty process keyring if one of the |
379 | * special keyring IDs is used. | 410 | * special keyring IDs is used. |
380 | * | 411 | * |
@@ -1622,6 +1653,9 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
1622 | (unsigned) arg4, | 1653 | (unsigned) arg4, |
1623 | (key_serial_t) arg5); | 1654 | (key_serial_t) arg5); |
1624 | 1655 | ||
1656 | case KEYCTL_INVALIDATE: | ||
1657 | return keyctl_invalidate_key((key_serial_t) arg2); | ||
1658 | |||
1625 | default: | 1659 | default: |
1626 | return -EOPNOTSUPP; | 1660 | return -EOPNOTSUPP; |
1627 | } | 1661 | } |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 89d02cfb00c2..7445875f6818 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -382,13 +382,17 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, | |||
382 | /* otherwise, the top keyring must not be revoked, expired, or | 382 | /* otherwise, the top keyring must not be revoked, expired, or |
383 | * negatively instantiated if we are to search it */ | 383 | * negatively instantiated if we are to search it */ |
384 | key_ref = ERR_PTR(-EAGAIN); | 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 | (keyring->expiry && now.tv_sec >= keyring->expiry)) | 388 | (keyring->expiry && now.tv_sec >= keyring->expiry)) |
387 | goto error_2; | 389 | goto error_2; |
388 | 390 | ||
389 | /* start processing a new keyring */ | 391 | /* start processing a new keyring */ |
390 | descend: | 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 | goto not_this_keyring; | 396 | goto not_this_keyring; |
393 | 397 | ||
394 | keylist = rcu_dereference(keyring->payload.subscriptions); | 398 | keylist = rcu_dereference(keyring->payload.subscriptions); |
@@ -406,9 +410,10 @@ descend: | |||
406 | if (key->type != type) | 410 | if (key->type != type) |
407 | continue; | 411 | continue; |
408 | 412 | ||
409 | /* skip revoked keys and expired keys */ | 413 | /* skip invalidated, revoked and expired keys */ |
410 | if (!no_state_check) { | 414 | if (!no_state_check) { |
411 | if (kflags & (1 << KEY_FLAG_REVOKED)) | 415 | if (kflags & ((1 << KEY_FLAG_INVALIDATED) | |
416 | (1 << KEY_FLAG_REVOKED))) | ||
412 | continue; | 417 | continue; |
413 | 418 | ||
414 | if (key->expiry && now.tv_sec >= key->expiry) | 419 | if (key->expiry && now.tv_sec >= key->expiry) |
@@ -559,7 +564,8 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, | |||
559 | key->type->match(key, description)) && | 564 | key->type->match(key, description)) && |
560 | key_permission(make_key_ref(key, possessed), | 565 | key_permission(make_key_ref(key, possessed), |
561 | perm) == 0 && | 566 | perm) == 0 && |
562 | !test_bit(KEY_FLAG_REVOKED, &key->flags) | 567 | !(key->flags & ((1 << KEY_FLAG_INVALIDATED) | |
568 | (1 << KEY_FLAG_REVOKED))) | ||
563 | ) | 569 | ) |
564 | goto found; | 570 | goto found; |
565 | } | 571 | } |
@@ -1177,15 +1183,6 @@ static void keyring_revoke(struct key *keyring) | |||
1177 | } | 1183 | } |
1178 | 1184 | ||
1179 | /* | 1185 | /* |
1180 | * Determine whether a key is dead. | ||
1181 | */ | ||
1182 | static bool key_is_dead(struct key *key, time_t limit) | ||
1183 | { | ||
1184 | return test_bit(KEY_FLAG_DEAD, &key->flags) || | ||
1185 | (key->expiry > 0 && key->expiry <= limit); | ||
1186 | } | ||
1187 | |||
1188 | /* | ||
1189 | * Collect garbage from the contents of a keyring, replacing the old list with | 1186 | * Collect garbage from the contents of a keyring, replacing the old list with |
1190 | * a new one with the pointers all shuffled down. | 1187 | * a new one with the pointers all shuffled down. |
1191 | * | 1188 | * |
diff --git a/security/keys/permission.c b/security/keys/permission.c index c35b5229e3cd..5f4c00c0947d 100644 --- a/security/keys/permission.c +++ b/security/keys/permission.c | |||
@@ -87,20 +87,25 @@ EXPORT_SYMBOL(key_task_permission); | |||
87 | * key_validate - Validate a key. | 87 | * key_validate - Validate a key. |
88 | * @key: The key to be validated. | 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 | 90 | * Check that a key is valid, returning 0 if the key is okay, -ENOKEY if the |
91 | * the key's type has been removed or if the key has been revoked or | 91 | * key is invalidated, -EKEYREVOKED if the key's type has been removed or if |
92 | * -EKEYEXPIRED if the key has expired. | 92 | * the key has been revoked or -EKEYEXPIRED if the key has expired. |
93 | */ | 93 | */ |
94 | int key_validate(struct key *key) | 94 | int key_validate(struct key *key) |
95 | { | 95 | { |
96 | struct timespec now; | 96 | struct timespec now; |
97 | unsigned long flags = key->flags; | ||
97 | int ret = 0; | 98 | int ret = 0; |
98 | 99 | ||
99 | if (key) { | 100 | if (key) { |
101 | ret = -ENOKEY; | ||
102 | if (flags & (1 << KEY_FLAG_INVALIDATED)) | ||
103 | goto error; | ||
104 | |||
100 | /* check it's still accessible */ | 105 | /* check it's still accessible */ |
101 | ret = -EKEYREVOKED; | 106 | ret = -EKEYREVOKED; |
102 | if (test_bit(KEY_FLAG_REVOKED, &key->flags) || | 107 | if (flags & ((1 << KEY_FLAG_REVOKED) | |
103 | test_bit(KEY_FLAG_DEAD, &key->flags)) | 108 | (1 << KEY_FLAG_DEAD))) |
104 | goto error; | 109 | goto error; |
105 | 110 | ||
106 | /* check it hasn't expired */ | 111 | /* check it hasn't expired */ |
diff --git a/security/keys/proc.c b/security/keys/proc.c index 49bbc97943ad..30d1ddfd9cef 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c | |||
@@ -242,7 +242,7 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
242 | #define showflag(KEY, LETTER, FLAG) \ | 242 | #define showflag(KEY, LETTER, FLAG) \ |
243 | (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') | 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 | key->serial, | 246 | key->serial, |
247 | showflag(key, 'I', KEY_FLAG_INSTANTIATED), | 247 | showflag(key, 'I', KEY_FLAG_INSTANTIATED), |
248 | showflag(key, 'R', KEY_FLAG_REVOKED), | 248 | showflag(key, 'R', KEY_FLAG_REVOKED), |
@@ -250,6 +250,7 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
250 | showflag(key, 'Q', KEY_FLAG_IN_QUOTA), | 250 | showflag(key, 'Q', KEY_FLAG_IN_QUOTA), |
251 | showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), | 251 | showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), |
252 | showflag(key, 'N', KEY_FLAG_NEGATIVE), | 252 | showflag(key, 'N', KEY_FLAG_NEGATIVE), |
253 | showflag(key, 'i', KEY_FLAG_INVALIDATED), | ||
253 | atomic_read(&key->usage), | 254 | atomic_read(&key->usage), |
254 | xbuf, | 255 | xbuf, |
255 | key->perm, | 256 | key->perm, |