Skip to content

Commit e59428f

Browse files
committed
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 <[email protected]>
1 parent a09003b commit e59428f

File tree

8 files changed

+77
-61
lines changed

8 files changed

+77
-61
lines changed

Documentation/security/keys/request-key.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ The Search Algorithm
148148

149149
A search of any particular keyring proceeds in the following fashion:
150150

151-
1) When the key management code searches for a key (keyring_search_aux) it
151+
1) When the key management code searches for a key (keyring_search_rcu) it
152152
firstly calls key_permission(SEARCH) on the keyring it's starting with,
153153
if this denies permission, it doesn't search further.
154154

include/keys/request_key_auth-type.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
* Authorisation record for request_key().
1919
*/
2020
struct request_key_auth {
21+
struct rcu_head rcu;
2122
struct key *target_key;
2223
struct key *dest_keyring;
2324
const struct cred *cred;

security/keys/internal.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,11 @@ struct keyring_search_context {
139139

140140
extern bool key_default_cmp(const struct key *key,
141141
const struct key_match_data *match_data);
142-
extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
142+
extern key_ref_t keyring_search_rcu(key_ref_t keyring_ref,
143143
struct keyring_search_context *ctx);
144144

145-
extern key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx);
146-
extern key_ref_t search_process_keyrings(struct keyring_search_context *ctx);
145+
extern key_ref_t search_cred_keyrings_rcu(struct keyring_search_context *ctx);
146+
extern key_ref_t search_process_keyrings_rcu(struct keyring_search_context *ctx);
147147

148148
extern struct key *find_keyring_by_name(const char *name, bool uid_keyring);
149149

security/keys/keyring.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,7 @@ static bool search_nested_keyrings(struct key *keyring,
835835
}
836836

837837
/**
838-
* keyring_search_aux - Search a keyring tree for a key matching some criteria
838+
* keyring_search_rcu - Search a keyring tree for a matching key under RCU
839839
* @keyring_ref: A pointer to the keyring with possession indicator.
840840
* @ctx: The keyring search context.
841841
*
@@ -847,7 +847,9 @@ static bool search_nested_keyrings(struct key *keyring,
847847
* addition, the LSM gets to forbid keyring searches and key matches.
848848
*
849849
* The search is performed as a breadth-then-depth search up to the prescribed
850-
* limit (KEYRING_SEARCH_MAX_DEPTH).
850+
* limit (KEYRING_SEARCH_MAX_DEPTH). The caller must hold the RCU read lock to
851+
* prevent keyrings from being destroyed or rearranged whilst they are being
852+
* searched.
851853
*
852854
* Keys are matched to the type provided and are then filtered by the match
853855
* function, which is given the description to use in any way it sees fit. The
@@ -866,7 +868,7 @@ static bool search_nested_keyrings(struct key *keyring,
866868
* In the case of a successful return, the possession attribute from
867869
* @keyring_ref is propagated to the returned key reference.
868870
*/
869-
key_ref_t keyring_search_aux(key_ref_t keyring_ref,
871+
key_ref_t keyring_search_rcu(key_ref_t keyring_ref,
870872
struct keyring_search_context *ctx)
871873
{
872874
struct key *keyring;
@@ -888,11 +890,9 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
888890
return ERR_PTR(err);
889891
}
890892

891-
rcu_read_lock();
892893
ctx->now = ktime_get_real_seconds();
893894
if (search_nested_keyrings(keyring, ctx))
894895
__key_get(key_ref_to_ptr(ctx->result));
895-
rcu_read_unlock();
896896
return ctx->result;
897897
}
898898

@@ -902,7 +902,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
902902
* @type: The type of keyring we want to find.
903903
* @description: The name of the keyring we want to find.
904904
*
905-
* As keyring_search_aux() above, but using the current task's credentials and
905+
* As keyring_search_rcu() above, but using the current task's credentials and
906906
* type's default matching function and preferred search method.
907907
*/
908908
key_ref_t keyring_search(key_ref_t keyring,
@@ -928,7 +928,9 @@ key_ref_t keyring_search(key_ref_t keyring,
928928
return ERR_PTR(ret);
929929
}
930930

931-
key = keyring_search_aux(keyring, &ctx);
931+
rcu_read_lock();
932+
key = keyring_search_rcu(keyring, &ctx);
933+
rcu_read_unlock();
932934

933935
if (type->match_free)
934936
type->match_free(&ctx.match_data);

security/keys/proc.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,9 @@ static int proc_keys_show(struct seq_file *m, void *v)
179179
* skip if the key does not indicate the possessor can view it
180180
*/
181181
if (key->perm & KEY_POS_VIEW) {
182-
skey_ref = search_my_process_keyrings(&ctx);
182+
rcu_read_lock();
183+
skey_ref = search_cred_keyrings_rcu(&ctx);
184+
rcu_read_unlock();
183185
if (!IS_ERR(skey_ref)) {
184186
key_ref_put(skey_ref);
185187
key_ref = make_key_ref(key, 1);

security/keys/process_keys.c

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,8 @@ void key_fsgid_changed(struct cred *new_cred)
318318

319319
/*
320320
* Search the process keyrings attached to the supplied cred for the first
321-
* matching key.
321+
* matching key under RCU conditions (the caller must be holding the RCU read
322+
* lock).
322323
*
323324
* The search criteria are the type and the match function. The description is
324325
* 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)
337338
* In the case of a successful return, the possession attribute is set on the
338339
* returned key reference.
339340
*/
340-
key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
341+
key_ref_t search_cred_keyrings_rcu(struct keyring_search_context *ctx)
341342
{
342343
key_ref_t key_ref, ret, err;
343344
const struct cred *cred = ctx->cred;
@@ -355,7 +356,7 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
355356

356357
/* search the thread keyring first */
357358
if (cred->thread_keyring) {
358-
key_ref = keyring_search_aux(
359+
key_ref = keyring_search_rcu(
359360
make_key_ref(cred->thread_keyring, 1), ctx);
360361
if (!IS_ERR(key_ref))
361362
goto found;
@@ -373,7 +374,7 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
373374

374375
/* search the process keyring second */
375376
if (cred->process_keyring) {
376-
key_ref = keyring_search_aux(
377+
key_ref = keyring_search_rcu(
377378
make_key_ref(cred->process_keyring, 1), ctx);
378379
if (!IS_ERR(key_ref))
379380
goto found;
@@ -394,7 +395,7 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
394395

395396
/* search the session keyring */
396397
if (cred->session_keyring) {
397-
key_ref = keyring_search_aux(
398+
key_ref = keyring_search_rcu(
398399
make_key_ref(cred->session_keyring, 1), ctx);
399400

400401
if (!IS_ERR(key_ref))
@@ -415,7 +416,7 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
415416
}
416417
/* or search the user-session keyring */
417418
else if (READ_ONCE(cred->user->session_keyring)) {
418-
key_ref = keyring_search_aux(
419+
key_ref = keyring_search_rcu(
419420
make_key_ref(READ_ONCE(cred->user->session_keyring), 1),
420421
ctx);
421422
if (!IS_ERR(key_ref))
@@ -448,16 +449,16 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
448449
* the keys attached to the assumed authorisation key using its credentials if
449450
* one is available.
450451
*
451-
* Return same as search_my_process_keyrings().
452+
* The caller must be holding the RCU read lock.
453+
*
454+
* Return same as search_cred_keyrings_rcu().
452455
*/
453-
key_ref_t search_process_keyrings(struct keyring_search_context *ctx)
456+
key_ref_t search_process_keyrings_rcu(struct keyring_search_context *ctx)
454457
{
455458
struct request_key_auth *rka;
456459
key_ref_t key_ref, ret = ERR_PTR(-EACCES), err;
457460

458-
might_sleep();
459-
460-
key_ref = search_my_process_keyrings(ctx);
461+
key_ref = search_cred_keyrings_rcu(ctx);
461462
if (!IS_ERR(key_ref))
462463
goto found;
463464
err = key_ref;
@@ -472,24 +473,17 @@ key_ref_t search_process_keyrings(struct keyring_search_context *ctx)
472473
) {
473474
const struct cred *cred = ctx->cred;
474475

475-
/* defend against the auth key being revoked */
476-
down_read(&cred->request_key_auth->sem);
477-
478-
if (key_validate(ctx->cred->request_key_auth) == 0) {
476+
if (key_validate(cred->request_key_auth) == 0) {
479477
rka = ctx->cred->request_key_auth->payload.data[0];
480478

479+
//// was search_process_keyrings() [ie. recursive]
481480
ctx->cred = rka->cred;
482-
key_ref = search_process_keyrings(ctx);
481+
key_ref = search_cred_keyrings_rcu(ctx);
483482
ctx->cred = cred;
484483

485-
up_read(&cred->request_key_auth->sem);
486-
487484
if (!IS_ERR(key_ref))
488485
goto found;
489-
490486
ret = key_ref;
491-
} else {
492-
up_read(&cred->request_key_auth->sem);
493487
}
494488
}
495489

@@ -504,7 +498,6 @@ key_ref_t search_process_keyrings(struct keyring_search_context *ctx)
504498
found:
505499
return key_ref;
506500
}
507-
508501
/*
509502
* See if the key we're looking at is the target key.
510503
*/
@@ -691,7 +684,9 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
691684
ctx.index_key = key->index_key;
692685
ctx.match_data.raw_data = key;
693686
kdebug("check possessed");
694-
skey_ref = search_process_keyrings(&ctx);
687+
rcu_read_lock();
688+
skey_ref = search_process_keyrings_rcu(&ctx);
689+
rcu_read_unlock();
695690
kdebug("possessed=%p", skey_ref);
696691

697692
if (!IS_ERR(skey_ref)) {

security/keys/request_key.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,9 @@ static int construct_alloc_key(struct keyring_search_context *ctx,
385385
* waited for locks */
386386
mutex_lock(&key_construction_mutex);
387387

388-
key_ref = search_process_keyrings(ctx);
388+
rcu_read_lock();
389+
key_ref = search_process_keyrings_rcu(ctx);
390+
rcu_read_unlock();
389391
if (!IS_ERR(key_ref))
390392
goto key_already_present;
391393

@@ -561,7 +563,9 @@ struct key *request_key_and_link(struct key_type *type,
561563
}
562564

563565
/* search all the process keyrings for a key */
564-
key_ref = search_process_keyrings(&ctx);
566+
rcu_read_lock();
567+
key_ref = search_process_keyrings_rcu(&ctx);
568+
rcu_read_unlock();
565569

566570
if (!IS_ERR(key_ref)) {
567571
if (dest_keyring) {

security/keys/request_key_auth.c

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ static void request_key_auth_free_preparse(struct key_preparsed_payload *prep)
5858
static int request_key_auth_instantiate(struct key *key,
5959
struct key_preparsed_payload *prep)
6060
{
61-
key->payload.data[0] = (struct request_key_auth *)prep->data;
61+
rcu_assign_keypointer(key, (struct request_key_auth *)prep->data);
6262
return 0;
6363
}
6464

@@ -68,7 +68,7 @@ static int request_key_auth_instantiate(struct key *key,
6868
static void request_key_auth_describe(const struct key *key,
6969
struct seq_file *m)
7070
{
71-
struct request_key_auth *rka = get_request_key_auth(key);
71+
struct request_key_auth *rka = dereference_key_rcu(key);
7272

7373
seq_puts(m, "key:");
7474
seq_puts(m, key->description);
@@ -83,7 +83,7 @@ static void request_key_auth_describe(const struct key *key,
8383
static long request_key_auth_read(const struct key *key,
8484
char __user *buffer, size_t buflen)
8585
{
86-
struct request_key_auth *rka = get_request_key_auth(key);
86+
struct request_key_auth *rka = dereference_key_locked(key);
8787
size_t datalen;
8888
long ret;
8989

@@ -102,23 +102,6 @@ static long request_key_auth_read(const struct key *key,
102102
return ret;
103103
}
104104

105-
/*
106-
* Handle revocation of an authorisation token key.
107-
*
108-
* Called with the key sem write-locked.
109-
*/
110-
static void request_key_auth_revoke(struct key *key)
111-
{
112-
struct request_key_auth *rka = get_request_key_auth(key);
113-
114-
kenter("{%d}", key->serial);
115-
116-
if (rka->cred) {
117-
put_cred(rka->cred);
118-
rka->cred = NULL;
119-
}
120-
}
121-
122105
static void free_request_key_auth(struct request_key_auth *rka)
123106
{
124107
if (!rka)
@@ -131,16 +114,43 @@ static void free_request_key_auth(struct request_key_auth *rka)
131114
kfree(rka);
132115
}
133116

117+
/*
118+
* Dispose of the request_key_auth record under RCU conditions
119+
*/
120+
static void request_key_auth_rcu_disposal(struct rcu_head *rcu)
121+
{
122+
struct request_key_auth *rka =
123+
container_of(rcu, struct request_key_auth, rcu);
124+
125+
free_request_key_auth(rka);
126+
}
127+
128+
/*
129+
* Handle revocation of an authorisation token key.
130+
*
131+
* Called with the key sem write-locked.
132+
*/
133+
static void request_key_auth_revoke(struct key *key)
134+
{
135+
struct request_key_auth *rka = dereference_key_locked(key);
136+
137+
kenter("{%d}", key->serial);
138+
rcu_assign_keypointer(key, NULL);
139+
call_rcu(&rka->rcu, request_key_auth_rcu_disposal);
140+
}
141+
134142
/*
135143
* Destroy an instantiation authorisation token key.
136144
*/
137145
static void request_key_auth_destroy(struct key *key)
138146
{
139-
struct request_key_auth *rka = get_request_key_auth(key);
147+
struct request_key_auth *rka = rcu_access_pointer(key->payload.rcu_data0);
140148

141149
kenter("{%d}", key->serial);
142-
143-
free_request_key_auth(rka);
150+
if (rka) {
151+
rcu_assign_keypointer(key, NULL);
152+
call_rcu(&rka->rcu, request_key_auth_rcu_disposal);
153+
}
144154
}
145155

146156
/*
@@ -249,7 +259,9 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id)
249259

250260
ctx.index_key.desc_len = sprintf(description, "%x", target_id);
251261

252-
authkey_ref = search_process_keyrings(&ctx);
262+
rcu_read_lock();
263+
authkey_ref = search_process_keyrings_rcu(&ctx);
264+
rcu_read_unlock();
253265

254266
if (IS_ERR(authkey_ref)) {
255267
authkey = ERR_CAST(authkey_ref);

0 commit comments

Comments
 (0)