Skip to content

Commit 04c567d

Browse files
dhowellsLinus Torvalds
authored andcommitted
[PATCH] Keys: Fix race between two instantiators of a key
Add a revocation notification method to the key type and calls it whilst the key's semaphore is still write-locked after setting the revocation flag. The patch then uses this to maintain a reference on the task_struct of the process that calls request_key() for as long as the authorisation key remains unrevoked. This fixes a potential race between two processes both of which have assumed the authority to instantiate a key (one may have forked the other for example). The problem is that there's no locking around the check for revocation of the auth key and the use of the task_struct it points to, nor does the auth key keep a reference on the task_struct. Access to the "context" pointer in the auth key must thenceforth be done with the auth key semaphore held. The revocation method is called with the target key semaphore held write-locked and the search of the context process's keyrings is done with the auth key semaphore read-locked. The check for the revocation state of the auth key just prior to searching it is done after the auth key is read-locked for the search. This ensures that the auth key can't be revoked between the check and the search. The revocation notification method is added so that the context task_struct can be released as soon as instantiation happens rather than waiting for the auth key to be destroyed, thus avoiding the unnecessary pinning of the requesting process. Signed-off-by: David Howells <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent d720024 commit 04c567d

File tree

5 files changed

+89
-17
lines changed

5 files changed

+89
-17
lines changed

Documentation/keys.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,16 @@ The structure has a number of fields, some of which are mandatory:
964964
It is not safe to sleep in this method; the caller may hold spinlocks.
965965

966966

967+
(*) void (*revoke)(struct key *key);
968+
969+
This method is optional. It is called to discard part of the payload
970+
data upon a key being revoked. The caller will have the key semaphore
971+
write-locked.
972+
973+
It is safe to sleep in this method, though care should be taken to avoid
974+
a deadlock against the key semaphore.
975+
976+
967977
(*) void (*destroy)(struct key *key);
968978

969979
This method is optional. It is called to discard the payload data on a key

include/linux/key.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,11 @@ struct key_type {
205205
/* match a key against a description */
206206
int (*match)(const struct key *key, const void *desc);
207207

208+
/* clear some of the data from a key on revokation (optional)
209+
* - the key's semaphore will be write-locked by the caller
210+
*/
211+
void (*revoke)(struct key *key);
212+
208213
/* clear the data from a key (optional) */
209214
void (*destroy)(struct key *key);
210215

security/keys/key.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,10 @@ void key_revoke(struct key *key)
907907
* it */
908908
down_write(&key->sem);
909909
set_bit(KEY_FLAG_REVOKED, &key->flags);
910+
911+
if (key->type->revoke)
912+
key->type->revoke(key);
913+
910914
up_write(&key->sem);
911915

912916
} /* end key_revoke() */

security/keys/process_keys.c

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,8 @@ key_ref_t search_process_keyrings(struct key_type *type,
391391
struct request_key_auth *rka;
392392
key_ref_t key_ref, ret, err;
393393

394+
might_sleep();
395+
394396
/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
395397
* searchable, but we failed to find a key or we found a negative key;
396398
* otherwise we want to return a sample error (probably -EACCES) if
@@ -496,27 +498,35 @@ key_ref_t search_process_keyrings(struct key_type *type,
496498
*/
497499
if (context->request_key_auth &&
498500
context == current &&
499-
type != &key_type_request_key_auth &&
500-
key_validate(context->request_key_auth) == 0
501+
type != &key_type_request_key_auth
501502
) {
502-
rka = context->request_key_auth->payload.data;
503+
/* defend against the auth key being revoked */
504+
down_read(&context->request_key_auth->sem);
503505

504-
key_ref = search_process_keyrings(type, description, match,
505-
rka->context);
506+
if (key_validate(context->request_key_auth) == 0) {
507+
rka = context->request_key_auth->payload.data;
506508

507-
if (!IS_ERR(key_ref))
508-
goto found;
509+
key_ref = search_process_keyrings(type, description,
510+
match, rka->context);
509511

510-
switch (PTR_ERR(key_ref)) {
511-
case -EAGAIN: /* no key */
512-
if (ret)
512+
up_read(&context->request_key_auth->sem);
513+
514+
if (!IS_ERR(key_ref))
515+
goto found;
516+
517+
switch (PTR_ERR(key_ref)) {
518+
case -EAGAIN: /* no key */
519+
if (ret)
520+
break;
521+
case -ENOKEY: /* negative key */
522+
ret = key_ref;
513523
break;
514-
case -ENOKEY: /* negative key */
515-
ret = key_ref;
516-
break;
517-
default:
518-
err = key_ref;
519-
break;
524+
default:
525+
err = key_ref;
526+
break;
527+
}
528+
} else {
529+
up_read(&context->request_key_auth->sem);
520530
}
521531
}
522532

security/keys/request_key_auth.c

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
static int request_key_auth_instantiate(struct key *, const void *, size_t);
2222
static void request_key_auth_describe(const struct key *, struct seq_file *);
23+
static void request_key_auth_revoke(struct key *);
2324
static void request_key_auth_destroy(struct key *);
2425
static long request_key_auth_read(const struct key *, char __user *, size_t);
2526

@@ -31,6 +32,7 @@ struct key_type key_type_request_key_auth = {
3132
.def_datalen = sizeof(struct request_key_auth),
3233
.instantiate = request_key_auth_instantiate,
3334
.describe = request_key_auth_describe,
35+
.revoke = request_key_auth_revoke,
3436
.destroy = request_key_auth_destroy,
3537
.read = request_key_auth_read,
3638
};
@@ -91,6 +93,24 @@ static long request_key_auth_read(const struct key *key,
9193

9294
} /* end request_key_auth_read() */
9395

96+
/*****************************************************************************/
97+
/*
98+
* handle revocation of an authorisation token key
99+
* - called with the key sem write-locked
100+
*/
101+
static void request_key_auth_revoke(struct key *key)
102+
{
103+
struct request_key_auth *rka = key->payload.data;
104+
105+
kenter("{%d}", key->serial);
106+
107+
if (rka->context) {
108+
put_task_struct(rka->context);
109+
rka->context = NULL;
110+
}
111+
112+
} /* end request_key_auth_revoke() */
113+
94114
/*****************************************************************************/
95115
/*
96116
* destroy an instantiation authorisation token key
@@ -101,6 +121,11 @@ static void request_key_auth_destroy(struct key *key)
101121

102122
kenter("{%d}", key->serial);
103123

124+
if (rka->context) {
125+
put_task_struct(rka->context);
126+
rka->context = NULL;
127+
}
128+
104129
key_put(rka->target_key);
105130
kfree(rka);
106131

@@ -131,14 +156,26 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info)
131156
* another process */
132157
if (current->request_key_auth) {
133158
/* it is - use that instantiation context here too */
159+
down_read(&current->request_key_auth->sem);
160+
161+
/* if the auth key has been revoked, then the key we're
162+
* servicing is already instantiated */
163+
if (test_bit(KEY_FLAG_REVOKED,
164+
&current->request_key_auth->flags))
165+
goto auth_key_revoked;
166+
134167
irka = current->request_key_auth->payload.data;
135168
rka->context = irka->context;
136169
rka->pid = irka->pid;
170+
get_task_struct(rka->context);
171+
172+
up_read(&current->request_key_auth->sem);
137173
}
138174
else {
139175
/* it isn't - use this process as the context */
140176
rka->context = current;
141177
rka->pid = current->pid;
178+
get_task_struct(rka->context);
142179
}
143180

144181
rka->target_key = key_get(target);
@@ -161,9 +198,15 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info)
161198
if (ret < 0)
162199
goto error_inst;
163200

164-
kleave(" = {%d})", authkey->serial);
201+
kleave(" = {%d}", authkey->serial);
165202
return authkey;
166203

204+
auth_key_revoked:
205+
up_read(&current->request_key_auth->sem);
206+
kfree(rka);
207+
kleave("= -EKEYREVOKED");
208+
return ERR_PTR(-EKEYREVOKED);
209+
167210
error_inst:
168211
key_revoke(authkey);
169212
key_put(authkey);

0 commit comments

Comments
 (0)