keys: Move the RCU locks outwards from the keyring search functions
Move the RCU locks outwards from the keyring search functions so that it will become possible to provide an RCU-capable partial request_key() function in a later commit. Signed-off-by: David Howells <dhowells@redhat.com>alistair/sunxi64-5.4-dsi
parent
a09003b5d7
commit
e59428f721
|
@ -148,7 +148,7 @@ The Search Algorithm
|
||||||
|
|
||||||
A search of any particular keyring proceeds in the following fashion:
|
A search of any particular keyring proceeds in the following fashion:
|
||||||
|
|
||||||
1) When the key management code searches for a key (keyring_search_aux) it
|
1) When the key management code searches for a key (keyring_search_rcu) it
|
||||||
firstly calls key_permission(SEARCH) on the keyring it's starting with,
|
firstly calls key_permission(SEARCH) on the keyring it's starting with,
|
||||||
if this denies permission, it doesn't search further.
|
if this denies permission, it doesn't search further.
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
* Authorisation record for request_key().
|
* Authorisation record for request_key().
|
||||||
*/
|
*/
|
||||||
struct request_key_auth {
|
struct request_key_auth {
|
||||||
|
struct rcu_head rcu;
|
||||||
struct key *target_key;
|
struct key *target_key;
|
||||||
struct key *dest_keyring;
|
struct key *dest_keyring;
|
||||||
const struct cred *cred;
|
const struct cred *cred;
|
||||||
|
|
|
@ -139,11 +139,11 @@ struct keyring_search_context {
|
||||||
|
|
||||||
extern bool key_default_cmp(const struct key *key,
|
extern bool key_default_cmp(const struct key *key,
|
||||||
const struct key_match_data *match_data);
|
const struct key_match_data *match_data);
|
||||||
extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
|
extern key_ref_t keyring_search_rcu(key_ref_t keyring_ref,
|
||||||
struct keyring_search_context *ctx);
|
struct keyring_search_context *ctx);
|
||||||
|
|
||||||
extern key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx);
|
extern key_ref_t search_cred_keyrings_rcu(struct keyring_search_context *ctx);
|
||||||
extern key_ref_t search_process_keyrings(struct keyring_search_context *ctx);
|
extern key_ref_t search_process_keyrings_rcu(struct keyring_search_context *ctx);
|
||||||
|
|
||||||
extern struct key *find_keyring_by_name(const char *name, bool uid_keyring);
|
extern struct key *find_keyring_by_name(const char *name, bool uid_keyring);
|
||||||
|
|
||||||
|
|
|
@ -835,7 +835,7 @@ found:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* keyring_search_aux - Search a keyring tree for a key matching some criteria
|
* keyring_search_rcu - Search a keyring tree for a matching key under RCU
|
||||||
* @keyring_ref: A pointer to the keyring with possession indicator.
|
* @keyring_ref: A pointer to the keyring with possession indicator.
|
||||||
* @ctx: The keyring search context.
|
* @ctx: The keyring search context.
|
||||||
*
|
*
|
||||||
|
@ -847,7 +847,9 @@ found:
|
||||||
* addition, the LSM gets to forbid keyring searches and key matches.
|
* addition, the LSM gets to forbid keyring searches and key matches.
|
||||||
*
|
*
|
||||||
* The search is performed as a breadth-then-depth search up to the prescribed
|
* The search is performed as a breadth-then-depth search up to the prescribed
|
||||||
* limit (KEYRING_SEARCH_MAX_DEPTH).
|
* limit (KEYRING_SEARCH_MAX_DEPTH). The caller must hold the RCU read lock to
|
||||||
|
* prevent keyrings from being destroyed or rearranged whilst they are being
|
||||||
|
* searched.
|
||||||
*
|
*
|
||||||
* Keys are matched to the type provided and are then filtered by the match
|
* Keys are matched to the type provided and are then filtered by the match
|
||||||
* function, which is given the description to use in any way it sees fit. The
|
* function, which is given the description to use in any way it sees fit. The
|
||||||
|
@ -866,7 +868,7 @@ found:
|
||||||
* In the case of a successful return, the possession attribute from
|
* In the case of a successful return, the possession attribute from
|
||||||
* @keyring_ref is propagated to the returned key reference.
|
* @keyring_ref is propagated to the returned key reference.
|
||||||
*/
|
*/
|
||||||
key_ref_t keyring_search_aux(key_ref_t keyring_ref,
|
key_ref_t keyring_search_rcu(key_ref_t keyring_ref,
|
||||||
struct keyring_search_context *ctx)
|
struct keyring_search_context *ctx)
|
||||||
{
|
{
|
||||||
struct key *keyring;
|
struct key *keyring;
|
||||||
|
@ -888,11 +890,9 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
ctx->now = ktime_get_real_seconds();
|
ctx->now = ktime_get_real_seconds();
|
||||||
if (search_nested_keyrings(keyring, ctx))
|
if (search_nested_keyrings(keyring, ctx))
|
||||||
__key_get(key_ref_to_ptr(ctx->result));
|
__key_get(key_ref_to_ptr(ctx->result));
|
||||||
rcu_read_unlock();
|
|
||||||
return ctx->result;
|
return ctx->result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -902,7 +902,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
|
||||||
* @type: The type of keyring we want to find.
|
* @type: The type of keyring we want to find.
|
||||||
* @description: The name of the keyring we want to find.
|
* @description: The name of the keyring we want to find.
|
||||||
*
|
*
|
||||||
* As keyring_search_aux() above, but using the current task's credentials and
|
* As keyring_search_rcu() above, but using the current task's credentials and
|
||||||
* type's default matching function and preferred search method.
|
* type's default matching function and preferred search method.
|
||||||
*/
|
*/
|
||||||
key_ref_t keyring_search(key_ref_t keyring,
|
key_ref_t keyring_search(key_ref_t keyring,
|
||||||
|
@ -928,7 +928,9 @@ key_ref_t keyring_search(key_ref_t keyring,
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
key = keyring_search_aux(keyring, &ctx);
|
rcu_read_lock();
|
||||||
|
key = keyring_search_rcu(keyring, &ctx);
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
if (type->match_free)
|
if (type->match_free)
|
||||||
type->match_free(&ctx.match_data);
|
type->match_free(&ctx.match_data);
|
||||||
|
|
|
@ -179,7 +179,9 @@ static int proc_keys_show(struct seq_file *m, void *v)
|
||||||
* skip if the key does not indicate the possessor can view it
|
* skip if the key does not indicate the possessor can view it
|
||||||
*/
|
*/
|
||||||
if (key->perm & KEY_POS_VIEW) {
|
if (key->perm & KEY_POS_VIEW) {
|
||||||
skey_ref = search_my_process_keyrings(&ctx);
|
rcu_read_lock();
|
||||||
|
skey_ref = search_cred_keyrings_rcu(&ctx);
|
||||||
|
rcu_read_unlock();
|
||||||
if (!IS_ERR(skey_ref)) {
|
if (!IS_ERR(skey_ref)) {
|
||||||
key_ref_put(skey_ref);
|
key_ref_put(skey_ref);
|
||||||
key_ref = make_key_ref(key, 1);
|
key_ref = make_key_ref(key, 1);
|
||||||
|
|
|
@ -318,7 +318,8 @@ void key_fsgid_changed(struct cred *new_cred)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Search the process keyrings attached to the supplied cred for the first
|
* Search the process keyrings attached to the supplied cred for the first
|
||||||
* matching key.
|
* matching key under RCU conditions (the caller must be holding the RCU read
|
||||||
|
* lock).
|
||||||
*
|
*
|
||||||
* The search criteria are the type and the match function. The description is
|
* The search criteria are the type and the match function. The description is
|
||||||
* given to the match function as a parameter, but doesn't otherwise influence
|
* given to the match function as a parameter, but doesn't otherwise influence
|
||||||
|
@ -337,7 +338,7 @@ void key_fsgid_changed(struct cred *new_cred)
|
||||||
* In the case of a successful return, the possession attribute is set on the
|
* In the case of a successful return, the possession attribute is set on the
|
||||||
* returned key reference.
|
* returned key reference.
|
||||||
*/
|
*/
|
||||||
key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
|
key_ref_t search_cred_keyrings_rcu(struct keyring_search_context *ctx)
|
||||||
{
|
{
|
||||||
key_ref_t key_ref, ret, err;
|
key_ref_t key_ref, ret, err;
|
||||||
const struct cred *cred = ctx->cred;
|
const struct cred *cred = ctx->cred;
|
||||||
|
@ -355,7 +356,7 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
|
||||||
|
|
||||||
/* search the thread keyring first */
|
/* search the thread keyring first */
|
||||||
if (cred->thread_keyring) {
|
if (cred->thread_keyring) {
|
||||||
key_ref = keyring_search_aux(
|
key_ref = keyring_search_rcu(
|
||||||
make_key_ref(cred->thread_keyring, 1), ctx);
|
make_key_ref(cred->thread_keyring, 1), ctx);
|
||||||
if (!IS_ERR(key_ref))
|
if (!IS_ERR(key_ref))
|
||||||
goto found;
|
goto found;
|
||||||
|
@ -373,7 +374,7 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
|
||||||
|
|
||||||
/* search the process keyring second */
|
/* search the process keyring second */
|
||||||
if (cred->process_keyring) {
|
if (cred->process_keyring) {
|
||||||
key_ref = keyring_search_aux(
|
key_ref = keyring_search_rcu(
|
||||||
make_key_ref(cred->process_keyring, 1), ctx);
|
make_key_ref(cred->process_keyring, 1), ctx);
|
||||||
if (!IS_ERR(key_ref))
|
if (!IS_ERR(key_ref))
|
||||||
goto found;
|
goto found;
|
||||||
|
@ -394,7 +395,7 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
|
||||||
|
|
||||||
/* search the session keyring */
|
/* search the session keyring */
|
||||||
if (cred->session_keyring) {
|
if (cred->session_keyring) {
|
||||||
key_ref = keyring_search_aux(
|
key_ref = keyring_search_rcu(
|
||||||
make_key_ref(cred->session_keyring, 1), ctx);
|
make_key_ref(cred->session_keyring, 1), ctx);
|
||||||
|
|
||||||
if (!IS_ERR(key_ref))
|
if (!IS_ERR(key_ref))
|
||||||
|
@ -415,7 +416,7 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
|
||||||
}
|
}
|
||||||
/* or search the user-session keyring */
|
/* or search the user-session keyring */
|
||||||
else if (READ_ONCE(cred->user->session_keyring)) {
|
else if (READ_ONCE(cred->user->session_keyring)) {
|
||||||
key_ref = keyring_search_aux(
|
key_ref = keyring_search_rcu(
|
||||||
make_key_ref(READ_ONCE(cred->user->session_keyring), 1),
|
make_key_ref(READ_ONCE(cred->user->session_keyring), 1),
|
||||||
ctx);
|
ctx);
|
||||||
if (!IS_ERR(key_ref))
|
if (!IS_ERR(key_ref))
|
||||||
|
@ -448,16 +449,16 @@ found:
|
||||||
* the keys attached to the assumed authorisation key using its credentials if
|
* the keys attached to the assumed authorisation key using its credentials if
|
||||||
* one is available.
|
* one is available.
|
||||||
*
|
*
|
||||||
* Return same as search_my_process_keyrings().
|
* The caller must be holding the RCU read lock.
|
||||||
|
*
|
||||||
|
* Return same as search_cred_keyrings_rcu().
|
||||||
*/
|
*/
|
||||||
key_ref_t search_process_keyrings(struct keyring_search_context *ctx)
|
key_ref_t search_process_keyrings_rcu(struct keyring_search_context *ctx)
|
||||||
{
|
{
|
||||||
struct request_key_auth *rka;
|
struct request_key_auth *rka;
|
||||||
key_ref_t key_ref, ret = ERR_PTR(-EACCES), err;
|
key_ref_t key_ref, ret = ERR_PTR(-EACCES), err;
|
||||||
|
|
||||||
might_sleep();
|
key_ref = search_cred_keyrings_rcu(ctx);
|
||||||
|
|
||||||
key_ref = search_my_process_keyrings(ctx);
|
|
||||||
if (!IS_ERR(key_ref))
|
if (!IS_ERR(key_ref))
|
||||||
goto found;
|
goto found;
|
||||||
err = key_ref;
|
err = key_ref;
|
||||||
|
@ -472,24 +473,17 @@ key_ref_t search_process_keyrings(struct keyring_search_context *ctx)
|
||||||
) {
|
) {
|
||||||
const struct cred *cred = ctx->cred;
|
const struct cred *cred = ctx->cred;
|
||||||
|
|
||||||
/* defend against the auth key being revoked */
|
if (key_validate(cred->request_key_auth) == 0) {
|
||||||
down_read(&cred->request_key_auth->sem);
|
|
||||||
|
|
||||||
if (key_validate(ctx->cred->request_key_auth) == 0) {
|
|
||||||
rka = ctx->cred->request_key_auth->payload.data[0];
|
rka = ctx->cred->request_key_auth->payload.data[0];
|
||||||
|
|
||||||
|
//// was search_process_keyrings() [ie. recursive]
|
||||||
ctx->cred = rka->cred;
|
ctx->cred = rka->cred;
|
||||||
key_ref = search_process_keyrings(ctx);
|
key_ref = search_cred_keyrings_rcu(ctx);
|
||||||
ctx->cred = cred;
|
ctx->cred = cred;
|
||||||
|
|
||||||
up_read(&cred->request_key_auth->sem);
|
|
||||||
|
|
||||||
if (!IS_ERR(key_ref))
|
if (!IS_ERR(key_ref))
|
||||||
goto found;
|
goto found;
|
||||||
|
|
||||||
ret = key_ref;
|
ret = key_ref;
|
||||||
} else {
|
|
||||||
up_read(&cred->request_key_auth->sem);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -504,7 +498,6 @@ key_ref_t search_process_keyrings(struct keyring_search_context *ctx)
|
||||||
found:
|
found:
|
||||||
return key_ref;
|
return key_ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See if the key we're looking at is the target key.
|
* See if the key we're looking at is the target key.
|
||||||
*/
|
*/
|
||||||
|
@ -691,7 +684,9 @@ try_again:
|
||||||
ctx.index_key = key->index_key;
|
ctx.index_key = key->index_key;
|
||||||
ctx.match_data.raw_data = key;
|
ctx.match_data.raw_data = key;
|
||||||
kdebug("check possessed");
|
kdebug("check possessed");
|
||||||
skey_ref = search_process_keyrings(&ctx);
|
rcu_read_lock();
|
||||||
|
skey_ref = search_process_keyrings_rcu(&ctx);
|
||||||
|
rcu_read_unlock();
|
||||||
kdebug("possessed=%p", skey_ref);
|
kdebug("possessed=%p", skey_ref);
|
||||||
|
|
||||||
if (!IS_ERR(skey_ref)) {
|
if (!IS_ERR(skey_ref)) {
|
||||||
|
|
|
@ -385,7 +385,9 @@ static int construct_alloc_key(struct keyring_search_context *ctx,
|
||||||
* waited for locks */
|
* waited for locks */
|
||||||
mutex_lock(&key_construction_mutex);
|
mutex_lock(&key_construction_mutex);
|
||||||
|
|
||||||
key_ref = search_process_keyrings(ctx);
|
rcu_read_lock();
|
||||||
|
key_ref = search_process_keyrings_rcu(ctx);
|
||||||
|
rcu_read_unlock();
|
||||||
if (!IS_ERR(key_ref))
|
if (!IS_ERR(key_ref))
|
||||||
goto key_already_present;
|
goto key_already_present;
|
||||||
|
|
||||||
|
@ -561,7 +563,9 @@ struct key *request_key_and_link(struct key_type *type,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* search all the process keyrings for a key */
|
/* search all the process keyrings for a key */
|
||||||
key_ref = search_process_keyrings(&ctx);
|
rcu_read_lock();
|
||||||
|
key_ref = search_process_keyrings_rcu(&ctx);
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
if (!IS_ERR(key_ref)) {
|
if (!IS_ERR(key_ref)) {
|
||||||
if (dest_keyring) {
|
if (dest_keyring) {
|
||||||
|
|
|
@ -58,7 +58,7 @@ static void request_key_auth_free_preparse(struct key_preparsed_payload *prep)
|
||||||
static int request_key_auth_instantiate(struct key *key,
|
static int request_key_auth_instantiate(struct key *key,
|
||||||
struct key_preparsed_payload *prep)
|
struct key_preparsed_payload *prep)
|
||||||
{
|
{
|
||||||
key->payload.data[0] = (struct request_key_auth *)prep->data;
|
rcu_assign_keypointer(key, (struct request_key_auth *)prep->data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ static int request_key_auth_instantiate(struct key *key,
|
||||||
static void request_key_auth_describe(const struct key *key,
|
static void request_key_auth_describe(const struct key *key,
|
||||||
struct seq_file *m)
|
struct seq_file *m)
|
||||||
{
|
{
|
||||||
struct request_key_auth *rka = get_request_key_auth(key);
|
struct request_key_auth *rka = dereference_key_rcu(key);
|
||||||
|
|
||||||
seq_puts(m, "key:");
|
seq_puts(m, "key:");
|
||||||
seq_puts(m, key->description);
|
seq_puts(m, key->description);
|
||||||
|
@ -83,7 +83,7 @@ static void request_key_auth_describe(const struct key *key,
|
||||||
static long request_key_auth_read(const struct key *key,
|
static long request_key_auth_read(const struct key *key,
|
||||||
char __user *buffer, size_t buflen)
|
char __user *buffer, size_t buflen)
|
||||||
{
|
{
|
||||||
struct request_key_auth *rka = get_request_key_auth(key);
|
struct request_key_auth *rka = dereference_key_locked(key);
|
||||||
size_t datalen;
|
size_t datalen;
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
|
@ -102,23 +102,6 @@ static long request_key_auth_read(const struct key *key,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle revocation of an authorisation token key.
|
|
||||||
*
|
|
||||||
* Called with the key sem write-locked.
|
|
||||||
*/
|
|
||||||
static void request_key_auth_revoke(struct key *key)
|
|
||||||
{
|
|
||||||
struct request_key_auth *rka = get_request_key_auth(key);
|
|
||||||
|
|
||||||
kenter("{%d}", key->serial);
|
|
||||||
|
|
||||||
if (rka->cred) {
|
|
||||||
put_cred(rka->cred);
|
|
||||||
rka->cred = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void free_request_key_auth(struct request_key_auth *rka)
|
static void free_request_key_auth(struct request_key_auth *rka)
|
||||||
{
|
{
|
||||||
if (!rka)
|
if (!rka)
|
||||||
|
@ -131,16 +114,43 @@ static void free_request_key_auth(struct request_key_auth *rka)
|
||||||
kfree(rka);
|
kfree(rka);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dispose of the request_key_auth record under RCU conditions
|
||||||
|
*/
|
||||||
|
static void request_key_auth_rcu_disposal(struct rcu_head *rcu)
|
||||||
|
{
|
||||||
|
struct request_key_auth *rka =
|
||||||
|
container_of(rcu, struct request_key_auth, rcu);
|
||||||
|
|
||||||
|
free_request_key_auth(rka);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle revocation of an authorisation token key.
|
||||||
|
*
|
||||||
|
* Called with the key sem write-locked.
|
||||||
|
*/
|
||||||
|
static void request_key_auth_revoke(struct key *key)
|
||||||
|
{
|
||||||
|
struct request_key_auth *rka = dereference_key_locked(key);
|
||||||
|
|
||||||
|
kenter("{%d}", key->serial);
|
||||||
|
rcu_assign_keypointer(key, NULL);
|
||||||
|
call_rcu(&rka->rcu, request_key_auth_rcu_disposal);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Destroy an instantiation authorisation token key.
|
* Destroy an instantiation authorisation token key.
|
||||||
*/
|
*/
|
||||||
static void request_key_auth_destroy(struct key *key)
|
static void request_key_auth_destroy(struct key *key)
|
||||||
{
|
{
|
||||||
struct request_key_auth *rka = get_request_key_auth(key);
|
struct request_key_auth *rka = rcu_access_pointer(key->payload.rcu_data0);
|
||||||
|
|
||||||
kenter("{%d}", key->serial);
|
kenter("{%d}", key->serial);
|
||||||
|
if (rka) {
|
||||||
free_request_key_auth(rka);
|
rcu_assign_keypointer(key, NULL);
|
||||||
|
call_rcu(&rka->rcu, request_key_auth_rcu_disposal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -249,7 +259,9 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id)
|
||||||
|
|
||||||
ctx.index_key.desc_len = sprintf(description, "%x", target_id);
|
ctx.index_key.desc_len = sprintf(description, "%x", target_id);
|
||||||
|
|
||||||
authkey_ref = search_process_keyrings(&ctx);
|
rcu_read_lock();
|
||||||
|
authkey_ref = search_process_keyrings_rcu(&ctx);
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
if (IS_ERR(authkey_ref)) {
|
if (IS_ERR(authkey_ref)) {
|
||||||
authkey = ERR_CAST(authkey_ref);
|
authkey = ERR_CAST(authkey_ref);
|
||||||
|
|
Loading…
Reference in New Issue