Skip to content

Commit

Permalink
KEYS: Improve /proc/keys
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
David Howells authored and James Morris committed Mar 17, 2011
1 parent c151694 commit 78b7280
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 29 deletions.
13 changes: 13 additions & 0 deletions include/linux/key.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,19 @@ static inline key_serial_t key_serial(struct key *key)
return key ? key->serial : 0;
}

/**
* key_is_instantiated - Determine if a key has been positively instantiated
* @key: The key to check.
*
* Return true if the specified key has been positively instantiated, false
* otherwise.
*/
static inline bool key_is_instantiated(const struct key *key)
{
return test_bit(KEY_FLAG_INSTANTIATED, &key->flags) &&
!test_bit(KEY_FLAG_NEGATIVE, &key->flags);
}

#define rcu_dereference_key(KEY) \
(rcu_dereference_protected((KEY)->payload.rcudata, \
rwsem_is_locked(&((struct key *)(KEY))->sem)))
Expand Down
10 changes: 6 additions & 4 deletions net/dns_resolver/dns_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,12 @@ static void dns_resolver_describe(const struct key *key, struct seq_file *m)
int err = key->type_data.x[0];

seq_puts(m, key->description);
if (err)
seq_printf(m, ": %d", err);
else
seq_printf(m, ": %u", key->datalen);
if (key_is_instantiated(key)) {
if (err)
seq_printf(m, ": %d", err);
else
seq_printf(m, ": %u", key->datalen);
}
}

/*
Expand Down
4 changes: 3 additions & 1 deletion security/keys/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,13 @@ extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
const struct cred *cred,
struct key_type *type,
const void *description,
key_match_func_t match);
key_match_func_t match,
bool no_state_check);

extern key_ref_t search_my_process_keyrings(struct key_type *type,
const void *description,
key_match_func_t match,
bool no_state_check,
const struct cred *cred);
extern key_ref_t search_process_keyrings(struct key_type *type,
const void *description,
Expand Down
37 changes: 24 additions & 13 deletions security/keys/keyring.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,15 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m)
else
seq_puts(m, "[anon]");

rcu_read_lock();
klist = rcu_dereference(keyring->payload.subscriptions);
if (klist)
seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys);
else
seq_puts(m, ": empty");
rcu_read_unlock();
if (key_is_instantiated(keyring)) {
rcu_read_lock();
klist = rcu_dereference(keyring->payload.subscriptions);
if (klist)
seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys);
else
seq_puts(m, ": empty");
rcu_read_unlock();
}
}

/*
Expand Down Expand Up @@ -271,6 +273,7 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
* @type: The type of key to search for.
* @description: Parameter for @match.
* @match: Function to rule on whether or not a key is the one required.
* @no_state_check: Don't check if a matching key is bad
*
* Search the supplied keyring tree for a key that matches the criteria given.
* The root keyring and any linked keyrings must grant Search permission to the
Expand Down Expand Up @@ -303,7 +306,8 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
const struct cred *cred,
struct key_type *type,
const void *description,
key_match_func_t match)
key_match_func_t match,
bool no_state_check)
{
struct {
struct keyring_list *keylist;
Expand Down Expand Up @@ -345,6 +349,8 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
kflags = keyring->flags;
if (keyring->type == type && match(keyring, description)) {
key = keyring;
if (no_state_check)
goto found;

/* check it isn't negative and hasn't expired or been
* revoked */
Expand Down Expand Up @@ -384,11 +390,13 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
continue;

/* skip revoked keys and expired keys */
if (kflags & (1 << KEY_FLAG_REVOKED))
continue;
if (!no_state_check) {
if (kflags & (1 << KEY_FLAG_REVOKED))
continue;

if (key->expiry && now.tv_sec >= key->expiry)
continue;
if (key->expiry && now.tv_sec >= key->expiry)
continue;
}

/* keys that don't match */
if (!match(key, description))
Expand All @@ -399,6 +407,9 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
cred, KEY_SEARCH) < 0)
continue;

if (no_state_check)
goto found;

/* we set a different error code if we pass a negative key */
if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
err = key->type_data.reject_error;
Expand Down Expand Up @@ -478,7 +489,7 @@ key_ref_t keyring_search(key_ref_t keyring,
return ERR_PTR(-ENOKEY);

return keyring_search_aux(keyring, current->cred,
type, description, type->match);
type, description, type->match, false);
}
EXPORT_SYMBOL(keyring_search);

Expand Down
2 changes: 1 addition & 1 deletion security/keys/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
if (key->perm & KEY_POS_VIEW) {
skey_ref = search_my_process_keyrings(key->type, key,
lookup_user_key_possessed,
cred);
true, cred);
if (!IS_ERR(skey_ref)) {
key_ref_put(skey_ref);
key_ref = make_key_ref(key, 1);
Expand Down
12 changes: 7 additions & 5 deletions security/keys/process_keys.c
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ void key_fsgid_changed(struct task_struct *tsk)
key_ref_t search_my_process_keyrings(struct key_type *type,
const void *description,
key_match_func_t match,
bool no_state_check,
const struct cred *cred)
{
key_ref_t key_ref, ret, err;
Expand All @@ -350,7 +351,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
if (cred->thread_keyring) {
key_ref = keyring_search_aux(
make_key_ref(cred->thread_keyring, 1),
cred, type, description, match);
cred, type, description, match, no_state_check);
if (!IS_ERR(key_ref))
goto found;

Expand All @@ -371,7 +372,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
if (cred->tgcred->process_keyring) {
key_ref = keyring_search_aux(
make_key_ref(cred->tgcred->process_keyring, 1),
cred, type, description, match);
cred, type, description, match, no_state_check);
if (!IS_ERR(key_ref))
goto found;

Expand All @@ -395,7 +396,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
make_key_ref(rcu_dereference(
cred->tgcred->session_keyring),
1),
cred, type, description, match);
cred, type, description, match, no_state_check);
rcu_read_unlock();

if (!IS_ERR(key_ref))
Expand All @@ -417,7 +418,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
else if (cred->user->session_keyring) {
key_ref = keyring_search_aux(
make_key_ref(cred->user->session_keyring, 1),
cred, type, description, match);
cred, type, description, match, no_state_check);
if (!IS_ERR(key_ref))
goto found;

Expand Down Expand Up @@ -459,7 +460,8 @@ key_ref_t search_process_keyrings(struct key_type *type,

might_sleep();

key_ref = search_my_process_keyrings(type, description, match, cred);
key_ref = search_my_process_keyrings(type, description, match,
false, cred);
if (!IS_ERR(key_ref))
goto found;
err = key_ref;
Expand Down
3 changes: 1 addition & 2 deletions security/keys/request_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -530,8 +530,7 @@ struct key *request_key_and_link(struct key_type *type,
dest_keyring, flags);

/* search all the process keyrings for a key */
key_ref = search_process_keyrings(type, description, type->match,
cred);
key_ref = search_process_keyrings(type, description, type->match, cred);

if (!IS_ERR(key_ref)) {
key = key_ref_to_ptr(key_ref);
Expand Down
3 changes: 2 additions & 1 deletion security/keys/request_key_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ static void request_key_auth_describe(const struct key *key,

seq_puts(m, "key:");
seq_puts(m, key->description);
seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len);
if (key_is_instantiated(key))
seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len);
}

/*
Expand Down
4 changes: 2 additions & 2 deletions security/keys/user_defined.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ EXPORT_SYMBOL_GPL(user_destroy);
void user_describe(const struct key *key, struct seq_file *m)
{
seq_puts(m, key->description);

seq_printf(m, ": %u", key->datalen);
if (key_is_instantiated(key))
seq_printf(m, ": %u", key->datalen);
}

EXPORT_SYMBOL_GPL(user_describe);
Expand Down

0 comments on commit 78b7280

Please sign in to comment.