summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 b2bb0171956..ef19b99aff9 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 cfa7a5e1c5c..fa000d26dc6 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 07a025f8190..f375152a250 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 cdd2f3f88c8..a06ffab3856 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 525cf8a29cd..49bbc97943a 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 930634e4514..6c0480db888 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 df3c0417ee4..b18a7174590 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 68164031a74..f6337c9082e 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 c6ca8662a46..63bb1aaffc0 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);