aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2011-03-11 17:57:23 +0000
committerJames Morris <jmorris@namei.org>2011-03-17 11:59:32 +1100
commit78b7280cce23293f7570ad52c1ffe1485c6d9669 (patch)
treef3051c5fe69cb41e88f9470dead8534dda3e94e0
parentc151694b2c48d956ac8c8c59c6927f89cc29ef70 (diff)
downloadkernel_goldelico_gta04-78b7280cce23293f7570ad52c1ffe1485c6d9669.zip
kernel_goldelico_gta04-78b7280cce23293f7570ad52c1ffe1485c6d9669.tar.gz
kernel_goldelico_gta04-78b7280cce23293f7570ad52c1ffe1485c6d9669.tar.bz2
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>
-rw-r--r--include/linux/key.h13
-rw-r--r--net/dns_resolver/dns_key.c10
-rw-r--r--security/keys/internal.h4
-rw-r--r--security/keys/keyring.c37
-rw-r--r--security/keys/proc.c2
-rw-r--r--security/keys/process_keys.c12
-rw-r--r--security/keys/request_key.c3
-rw-r--r--security/keys/request_key_auth.c3
-rw-r--r--security/keys/user_defined.c4
9 files changed, 59 insertions, 29 deletions
diff --git a/include/linux/key.h b/include/linux/key.h
index b2bb017..ef19b99 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -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)))
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c
index cfa7a5e..fa000d2 100644
--- a/net/dns_resolver/dns_key.c
+++ b/net/dns_resolver/dns_key.c
@@ -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);
+ }
}
/*
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 07a025f..f375152 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -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,
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index cdd2f3f..a06ffab 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -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();
+ }
}
/*
@@ -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
@@ -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;
@@ -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 */
@@ -384,11 +390,13 @@ descend:
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))
@@ -399,6 +407,9 @@ descend:
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;
@@ -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);
diff --git a/security/keys/proc.c b/security/keys/proc.c
index 525cf8a..49bbc97 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -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);
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 930634e..6c0480d 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -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;
@@ -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;
@@ -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;
@@ -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))
@@ -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;
@@ -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;
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index df3c041..b18a717 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -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);
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index 6816403..f6337c9 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -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);
}
/*
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index c6ca866..63bb1aa 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -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);