diff options
-rw-r--r-- | Documentation/keys.txt | 10 | ||||
-rw-r--r-- | include/linux/key.h | 5 | ||||
-rw-r--r-- | security/keys/key.c | 4 | ||||
-rw-r--r-- | security/keys/process_keys.c | 42 | ||||
-rw-r--r-- | security/keys/request_key_auth.c | 45 |
5 files changed, 89 insertions, 17 deletions
diff --git a/Documentation/keys.txt b/Documentation/keys.txt index 703020012708..3bbe157b45e4 100644 --- a/Documentation/keys.txt +++ b/Documentation/keys.txt | |||
@@ -964,6 +964,16 @@ The structure has a number of fields, some of which are mandatory: | |||
964 | It is not safe to sleep in this method; the caller may hold spinlocks. | 964 | It is not safe to sleep in this method; the caller may hold spinlocks. |
965 | 965 | ||
966 | 966 | ||
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 | |||
967 | (*) void (*destroy)(struct key *key); | 977 | (*) void (*destroy)(struct key *key); |
968 | 978 | ||
969 | This method is optional. It is called to discard the payload data on a key | 979 | This method is optional. It is called to discard the payload data on a key |
diff --git a/include/linux/key.h b/include/linux/key.h index 8c275d12ef63..e81ebf910d0b 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
@@ -205,6 +205,11 @@ struct key_type { | |||
205 | /* match a key against a description */ | 205 | /* match a key against a description */ |
206 | int (*match)(const struct key *key, const void *desc); | 206 | int (*match)(const struct key *key, const void *desc); |
207 | 207 | ||
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 | |||
208 | /* clear the data from a key (optional) */ | 213 | /* clear the data from a key (optional) */ |
209 | void (*destroy)(struct key *key); | 214 | void (*destroy)(struct key *key); |
210 | 215 | ||
diff --git a/security/keys/key.c b/security/keys/key.c index 14a15abb7735..51f851557389 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -907,6 +907,10 @@ void key_revoke(struct key *key) | |||
907 | * it */ | 907 | * it */ |
908 | down_write(&key->sem); | 908 | down_write(&key->sem); |
909 | set_bit(KEY_FLAG_REVOKED, &key->flags); | 909 | set_bit(KEY_FLAG_REVOKED, &key->flags); |
910 | |||
911 | if (key->type->revoke) | ||
912 | key->type->revoke(key); | ||
913 | |||
910 | up_write(&key->sem); | 914 | up_write(&key->sem); |
911 | 915 | ||
912 | } /* end key_revoke() */ | 916 | } /* end key_revoke() */ |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index a50a91332fe1..4d9825f9962c 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -391,6 +391,8 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
391 | struct request_key_auth *rka; | 391 | struct request_key_auth *rka; |
392 | key_ref_t key_ref, ret, err; | 392 | key_ref_t key_ref, ret, err; |
393 | 393 | ||
394 | might_sleep(); | ||
395 | |||
394 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were | 396 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were |
395 | * searchable, but we failed to find a key or we found a negative key; | 397 | * searchable, but we failed to find a key or we found a negative key; |
396 | * otherwise we want to return a sample error (probably -EACCES) if | 398 | * 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, | |||
496 | */ | 498 | */ |
497 | if (context->request_key_auth && | 499 | if (context->request_key_auth && |
498 | context == current && | 500 | context == current && |
499 | type != &key_type_request_key_auth && | 501 | type != &key_type_request_key_auth |
500 | key_validate(context->request_key_auth) == 0 | ||
501 | ) { | 502 | ) { |
502 | rka = context->request_key_auth->payload.data; | 503 | /* defend against the auth key being revoked */ |
504 | down_read(&context->request_key_auth->sem); | ||
503 | 505 | ||
504 | key_ref = search_process_keyrings(type, description, match, | 506 | if (key_validate(context->request_key_auth) == 0) { |
505 | rka->context); | 507 | rka = context->request_key_auth->payload.data; |
506 | 508 | ||
507 | if (!IS_ERR(key_ref)) | 509 | key_ref = search_process_keyrings(type, description, |
508 | goto found; | 510 | match, rka->context); |
509 | 511 | ||
510 | switch (PTR_ERR(key_ref)) { | 512 | up_read(&context->request_key_auth->sem); |
511 | case -EAGAIN: /* no key */ | 513 | |
512 | if (ret) | 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; | ||
513 | break; | 523 | break; |
514 | case -ENOKEY: /* negative key */ | 524 | default: |
515 | ret = key_ref; | 525 | err = key_ref; |
516 | break; | 526 | break; |
517 | default: | 527 | } |
518 | err = key_ref; | 528 | } else { |
519 | break; | 529 | up_read(&context->request_key_auth->sem); |
520 | } | 530 | } |
521 | } | 531 | } |
522 | 532 | ||
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index 0ecc2e8d2bd0..cb9817ced3fd 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c | |||
@@ -20,6 +20,7 @@ | |||
20 | 20 | ||
21 | static int request_key_auth_instantiate(struct key *, const void *, size_t); | 21 | static int request_key_auth_instantiate(struct key *, const void *, size_t); |
22 | static void request_key_auth_describe(const struct key *, struct seq_file *); | 22 | static void request_key_auth_describe(const struct key *, struct seq_file *); |
23 | static void request_key_auth_revoke(struct key *); | ||
23 | static void request_key_auth_destroy(struct key *); | 24 | static void request_key_auth_destroy(struct key *); |
24 | static long request_key_auth_read(const struct key *, char __user *, size_t); | 25 | static long request_key_auth_read(const struct key *, char __user *, size_t); |
25 | 26 | ||
@@ -31,6 +32,7 @@ struct key_type key_type_request_key_auth = { | |||
31 | .def_datalen = sizeof(struct request_key_auth), | 32 | .def_datalen = sizeof(struct request_key_auth), |
32 | .instantiate = request_key_auth_instantiate, | 33 | .instantiate = request_key_auth_instantiate, |
33 | .describe = request_key_auth_describe, | 34 | .describe = request_key_auth_describe, |
35 | .revoke = request_key_auth_revoke, | ||
34 | .destroy = request_key_auth_destroy, | 36 | .destroy = request_key_auth_destroy, |
35 | .read = request_key_auth_read, | 37 | .read = request_key_auth_read, |
36 | }; | 38 | }; |
@@ -93,6 +95,24 @@ static long request_key_auth_read(const struct key *key, | |||
93 | 95 | ||
94 | /*****************************************************************************/ | 96 | /*****************************************************************************/ |
95 | /* | 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 | |||
114 | /*****************************************************************************/ | ||
115 | /* | ||
96 | * destroy an instantiation authorisation token key | 116 | * destroy an instantiation authorisation token key |
97 | */ | 117 | */ |
98 | static void request_key_auth_destroy(struct key *key) | 118 | static void request_key_auth_destroy(struct key *key) |
@@ -101,6 +121,11 @@ static void request_key_auth_destroy(struct key *key) | |||
101 | 121 | ||
102 | kenter("{%d}", key->serial); | 122 | kenter("{%d}", key->serial); |
103 | 123 | ||
124 | if (rka->context) { | ||
125 | put_task_struct(rka->context); | ||
126 | rka->context = NULL; | ||
127 | } | ||
128 | |||
104 | key_put(rka->target_key); | 129 | key_put(rka->target_key); |
105 | kfree(rka); | 130 | kfree(rka); |
106 | 131 | ||
@@ -131,14 +156,26 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info) | |||
131 | * another process */ | 156 | * another process */ |
132 | if (current->request_key_auth) { | 157 | if (current->request_key_auth) { |
133 | /* it is - use that instantiation context here too */ | 158 | /* it is - use that instantiation context here too */ |
159 | down_read(¤t->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 | ¤t->request_key_auth->flags)) | ||
165 | goto auth_key_revoked; | ||
166 | |||
134 | irka = current->request_key_auth->payload.data; | 167 | irka = current->request_key_auth->payload.data; |
135 | rka->context = irka->context; | 168 | rka->context = irka->context; |
136 | rka->pid = irka->pid; | 169 | rka->pid = irka->pid; |
170 | get_task_struct(rka->context); | ||
171 | |||
172 | up_read(¤t->request_key_auth->sem); | ||
137 | } | 173 | } |
138 | else { | 174 | else { |
139 | /* it isn't - use this process as the context */ | 175 | /* it isn't - use this process as the context */ |
140 | rka->context = current; | 176 | rka->context = current; |
141 | rka->pid = current->pid; | 177 | rka->pid = current->pid; |
178 | get_task_struct(rka->context); | ||
142 | } | 179 | } |
143 | 180 | ||
144 | rka->target_key = key_get(target); | 181 | rka->target_key = key_get(target); |
@@ -161,9 +198,15 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info) | |||
161 | if (ret < 0) | 198 | if (ret < 0) |
162 | goto error_inst; | 199 | goto error_inst; |
163 | 200 | ||
164 | kleave(" = {%d})", authkey->serial); | 201 | kleave(" = {%d}", authkey->serial); |
165 | return authkey; | 202 | return authkey; |
166 | 203 | ||
204 | auth_key_revoked: | ||
205 | up_read(¤t->request_key_auth->sem); | ||
206 | kfree(rka); | ||
207 | kleave("= -EKEYREVOKED"); | ||
208 | return ERR_PTR(-EKEYREVOKED); | ||
209 | |||
167 | error_inst: | 210 | error_inst: |
168 | key_revoke(authkey); | 211 | key_revoke(authkey); |
169 | key_put(authkey); | 212 | key_put(authkey); |