aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2012-05-11 05:56:56 -0400
committerDavid Howells <dhowells@redhat.com>2012-05-11 05:56:56 -0400
commitfd75815f727f157a05f4c96b5294a4617c0557da (patch)
treeb2e76abf176d37b5d810b0c813b8c0219754b88c /security
parent31d5a79d7f3d436da176a78ebc12d53c06da402e (diff)
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>
Diffstat (limited to 'security')
-rw-r--r--security/keys/compat.c3
-rw-r--r--security/keys/gc.c21
-rw-r--r--security/keys/internal.h15
-rw-r--r--security/keys/key.c22
-rw-r--r--security/keys/keyctl.c34
-rw-r--r--security/keys/keyring.c25
-rw-r--r--security/keys/permission.c15
-rw-r--r--security/keys/proc.c3
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 */
77void 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)
131static void key_gc_keyring(struct key *keyring, time_t limit) 139static 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);
152extern struct work_struct key_gc_work; 152extern struct work_struct key_gc_work;
153extern unsigned key_gc_delay; 153extern unsigned key_gc_delay;
154extern void keyring_gc(struct key *keyring, time_t limit); 154extern void keyring_gc(struct key *keyring, time_t limit);
155extern void key_schedule_gc(time_t expiry_at); 155extern void key_schedule_gc(time_t gc_at);
156extern void key_schedule_gc_links(void);
156extern void key_gc_keytype(struct key_type *ktype); 157extern void key_gc_keytype(struct key_type *ktype);
157 158
158extern int key_task_permission(const key_ref_t key_ref, 159extern int key_task_permission(const key_ref_t key_ref,
@@ -197,6 +198,17 @@ extern struct key *request_key_auth_new(struct key *target,
197extern struct key *key_get_instantiation_authkey(key_serial_t target_id); 198extern struct key *key_get_instantiation_authkey(key_serial_t target_id);
198 199
199/* 200/*
201 * Determine whether a key is dead.
202 */
203static 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 */
202extern long keyctl_get_keyring_ID(key_serial_t, int); 214extern 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);
225extern long keyctl_instantiate_key_iov(key_serial_t, 237extern 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);
240extern long keyctl_invalidate_key(key_serial_t);
228 241
229extern long keyctl_instantiate_key_common(key_serial_t, 242extern 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)
955EXPORT_SYMBOL(key_revoke); 955EXPORT_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 */
964void 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}
977EXPORT_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 */
386long 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);
403error:
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 */
390descend: 392descend:
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 */
1182static 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 */
94int key_validate(struct key *key) 94int 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,