Commit 78b7280cce23293f7570ad52c1ffe1485c6d9669

Authored by David Howells
Committed by James Morris
1 parent c151694b2c

KEYS: Improve /proc/keys

Improve /proc/keys by:

 (1) Don't attempt to summarise the payload of a negated key.  It won't have
     one.  To this end, a helper function - key_is_instantiated() has been
     added that allows the caller to find out whether the key is positively
     instantiated (as opposed to being uninstantiated or negatively
     instantiated).

 (2) Do show keys that are negative, expired or revoked rather than hiding
     them.  This requires an override flag (no_state_check) to be passed to
     search_my_process_keyrings() and keyring_search_aux() to suppress this
     check.

     Without this, keys that are possessed by the caller, but only grant
     permissions to the caller if possessed are skipped as the possession check
     fails.

     Keys that are visible due to user, group or other checks are visible with
     or without this patch.

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: James Morris <jmorris@namei.org>

Showing 9 changed files with 59 additions and 29 deletions Side-by-side Diff

... ... @@ -276,6 +276,19 @@
276 276 return key ? key->serial : 0;
277 277 }
278 278  
  279 +/**
  280 + * key_is_instantiated - Determine if a key has been positively instantiated
  281 + * @key: The key to check.
  282 + *
  283 + * Return true if the specified key has been positively instantiated, false
  284 + * otherwise.
  285 + */
  286 +static inline bool key_is_instantiated(const struct key *key)
  287 +{
  288 + return test_bit(KEY_FLAG_INSTANTIATED, &key->flags) &&
  289 + !test_bit(KEY_FLAG_NEGATIVE, &key->flags);
  290 +}
  291 +
279 292 #define rcu_dereference_key(KEY) \
280 293 (rcu_dereference_protected((KEY)->payload.rcudata, \
281 294 rwsem_is_locked(&((struct key *)(KEY))->sem)))
net/dns_resolver/dns_key.c
... ... @@ -212,10 +212,12 @@
212 212 int err = key->type_data.x[0];
213 213  
214 214 seq_puts(m, key->description);
215   - if (err)
216   - seq_printf(m, ": %d", err);
217   - else
218   - seq_printf(m, ": %u", key->datalen);
  215 + if (key_is_instantiated(key)) {
  216 + if (err)
  217 + seq_printf(m, ": %d", err);
  218 + else
  219 + seq_printf(m, ": %u", key->datalen);
  220 + }
219 221 }
220 222  
221 223 /*
security/keys/internal.h
... ... @@ -109,11 +109,13 @@
109 109 const struct cred *cred,
110 110 struct key_type *type,
111 111 const void *description,
112   - key_match_func_t match);
  112 + key_match_func_t match,
  113 + bool no_state_check);
113 114  
114 115 extern key_ref_t search_my_process_keyrings(struct key_type *type,
115 116 const void *description,
116 117 key_match_func_t match,
  118 + bool no_state_check,
117 119 const struct cred *cred);
118 120 extern key_ref_t search_process_keyrings(struct key_type *type,
119 121 const void *description,
security/keys/keyring.c
... ... @@ -176,13 +176,15 @@
176 176 else
177 177 seq_puts(m, "[anon]");
178 178  
179   - rcu_read_lock();
180   - klist = rcu_dereference(keyring->payload.subscriptions);
181   - if (klist)
182   - seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys);
183   - else
184   - seq_puts(m, ": empty");
185   - rcu_read_unlock();
  179 + if (key_is_instantiated(keyring)) {
  180 + rcu_read_lock();
  181 + klist = rcu_dereference(keyring->payload.subscriptions);
  182 + if (klist)
  183 + seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys);
  184 + else
  185 + seq_puts(m, ": empty");
  186 + rcu_read_unlock();
  187 + }
186 188 }
187 189  
188 190 /*
... ... @@ -271,6 +273,7 @@
271 273 * @type: The type of key to search for.
272 274 * @description: Parameter for @match.
273 275 * @match: Function to rule on whether or not a key is the one required.
  276 + * @no_state_check: Don't check if a matching key is bad
274 277 *
275 278 * Search the supplied keyring tree for a key that matches the criteria given.
276 279 * The root keyring and any linked keyrings must grant Search permission to the
... ... @@ -303,7 +306,8 @@
303 306 const struct cred *cred,
304 307 struct key_type *type,
305 308 const void *description,
306   - key_match_func_t match)
  309 + key_match_func_t match,
  310 + bool no_state_check)
307 311 {
308 312 struct {
309 313 struct keyring_list *keylist;
... ... @@ -345,6 +349,8 @@
345 349 kflags = keyring->flags;
346 350 if (keyring->type == type && match(keyring, description)) {
347 351 key = keyring;
  352 + if (no_state_check)
  353 + goto found;
348 354  
349 355 /* check it isn't negative and hasn't expired or been
350 356 * revoked */
351 357  
... ... @@ -384,11 +390,13 @@
384 390 continue;
385 391  
386 392 /* skip revoked keys and expired keys */
387   - if (kflags & (1 << KEY_FLAG_REVOKED))
388   - continue;
  393 + if (!no_state_check) {
  394 + if (kflags & (1 << KEY_FLAG_REVOKED))
  395 + continue;
389 396  
390   - if (key->expiry && now.tv_sec >= key->expiry)
391   - continue;
  397 + if (key->expiry && now.tv_sec >= key->expiry)
  398 + continue;
  399 + }
392 400  
393 401 /* keys that don't match */
394 402 if (!match(key, description))
... ... @@ -399,6 +407,9 @@
399 407 cred, KEY_SEARCH) < 0)
400 408 continue;
401 409  
  410 + if (no_state_check)
  411 + goto found;
  412 +
402 413 /* we set a different error code if we pass a negative key */
403 414 if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
404 415 err = key->type_data.reject_error;
... ... @@ -478,7 +489,7 @@
478 489 return ERR_PTR(-ENOKEY);
479 490  
480 491 return keyring_search_aux(keyring, current->cred,
481   - type, description, type->match);
  492 + type, description, type->match, false);
482 493 }
483 494 EXPORT_SYMBOL(keyring_search);
484 495  
security/keys/proc.c
... ... @@ -199,7 +199,7 @@
199 199 if (key->perm & KEY_POS_VIEW) {
200 200 skey_ref = search_my_process_keyrings(key->type, key,
201 201 lookup_user_key_possessed,
202   - cred);
  202 + true, cred);
203 203 if (!IS_ERR(skey_ref)) {
204 204 key_ref_put(skey_ref);
205 205 key_ref = make_key_ref(key, 1);
security/keys/process_keys.c
... ... @@ -331,6 +331,7 @@
331 331 key_ref_t search_my_process_keyrings(struct key_type *type,
332 332 const void *description,
333 333 key_match_func_t match,
  334 + bool no_state_check,
334 335 const struct cred *cred)
335 336 {
336 337 key_ref_t key_ref, ret, err;
... ... @@ -350,7 +351,7 @@
350 351 if (cred->thread_keyring) {
351 352 key_ref = keyring_search_aux(
352 353 make_key_ref(cred->thread_keyring, 1),
353   - cred, type, description, match);
  354 + cred, type, description, match, no_state_check);
354 355 if (!IS_ERR(key_ref))
355 356 goto found;
356 357  
... ... @@ -371,7 +372,7 @@
371 372 if (cred->tgcred->process_keyring) {
372 373 key_ref = keyring_search_aux(
373 374 make_key_ref(cred->tgcred->process_keyring, 1),
374   - cred, type, description, match);
  375 + cred, type, description, match, no_state_check);
375 376 if (!IS_ERR(key_ref))
376 377 goto found;
377 378  
... ... @@ -395,7 +396,7 @@
395 396 make_key_ref(rcu_dereference(
396 397 cred->tgcred->session_keyring),
397 398 1),
398   - cred, type, description, match);
  399 + cred, type, description, match, no_state_check);
399 400 rcu_read_unlock();
400 401  
401 402 if (!IS_ERR(key_ref))
... ... @@ -417,7 +418,7 @@
417 418 else if (cred->user->session_keyring) {
418 419 key_ref = keyring_search_aux(
419 420 make_key_ref(cred->user->session_keyring, 1),
420   - cred, type, description, match);
  421 + cred, type, description, match, no_state_check);
421 422 if (!IS_ERR(key_ref))
422 423 goto found;
423 424  
... ... @@ -459,7 +460,8 @@
459 460  
460 461 might_sleep();
461 462  
462   - key_ref = search_my_process_keyrings(type, description, match, cred);
  463 + key_ref = search_my_process_keyrings(type, description, match,
  464 + false, cred);
463 465 if (!IS_ERR(key_ref))
464 466 goto found;
465 467 err = key_ref;
security/keys/request_key.c
... ... @@ -530,8 +530,7 @@
530 530 dest_keyring, flags);
531 531  
532 532 /* search all the process keyrings for a key */
533   - key_ref = search_process_keyrings(type, description, type->match,
534   - cred);
  533 + key_ref = search_process_keyrings(type, description, type->match, cred);
535 534  
536 535 if (!IS_ERR(key_ref)) {
537 536 key = key_ref_to_ptr(key_ref);
security/keys/request_key_auth.c
... ... @@ -59,7 +59,8 @@
59 59  
60 60 seq_puts(m, "key:");
61 61 seq_puts(m, key->description);
62   - seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len);
  62 + if (key_is_instantiated(key))
  63 + seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len);
63 64 }
64 65  
65 66 /*
security/keys/user_defined.c
... ... @@ -169,8 +169,8 @@
169 169 void user_describe(const struct key *key, struct seq_file *m)
170 170 {
171 171 seq_puts(m, key->description);
172   -
173   - seq_printf(m, ": %u", key->datalen);
  172 + if (key_is_instantiated(key))
  173 + seq_printf(m, ": %u", key->datalen);
174 174 }
175 175  
176 176 EXPORT_SYMBOL_GPL(user_describe);