1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* Request key authorisation token key definition. |
3 | * |
4 | * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. |
5 | * Written by David Howells (dhowells@redhat.com) |
6 | * |
7 | * See Documentation/security/keys/request-key.rst |
8 | */ |
9 | |
10 | #include <linux/sched.h> |
11 | #include <linux/err.h> |
12 | #include <linux/seq_file.h> |
13 | #include <linux/slab.h> |
14 | #include <linux/uaccess.h> |
15 | #include "internal.h" |
16 | #include <keys/request_key_auth-type.h> |
17 | |
18 | static int request_key_auth_preparse(struct key_preparsed_payload *); |
19 | static void request_key_auth_free_preparse(struct key_preparsed_payload *); |
20 | static int request_key_auth_instantiate(struct key *, |
21 | struct key_preparsed_payload *); |
22 | static void request_key_auth_describe(const struct key *, struct seq_file *); |
23 | static void request_key_auth_revoke(struct key *); |
24 | static void request_key_auth_destroy(struct key *); |
25 | static long request_key_auth_read(const struct key *, char *, size_t); |
26 | |
27 | /* |
28 | * The request-key authorisation key type definition. |
29 | */ |
30 | struct key_type key_type_request_key_auth = { |
31 | .name = ".request_key_auth" , |
32 | .def_datalen = sizeof(struct request_key_auth), |
33 | .preparse = request_key_auth_preparse, |
34 | .free_preparse = request_key_auth_free_preparse, |
35 | .instantiate = request_key_auth_instantiate, |
36 | .describe = request_key_auth_describe, |
37 | .revoke = request_key_auth_revoke, |
38 | .destroy = request_key_auth_destroy, |
39 | .read = request_key_auth_read, |
40 | }; |
41 | |
42 | static int request_key_auth_preparse(struct key_preparsed_payload *prep) |
43 | { |
44 | return 0; |
45 | } |
46 | |
47 | static void request_key_auth_free_preparse(struct key_preparsed_payload *prep) |
48 | { |
49 | } |
50 | |
51 | /* |
52 | * Instantiate a request-key authorisation key. |
53 | */ |
54 | static int request_key_auth_instantiate(struct key *key, |
55 | struct key_preparsed_payload *prep) |
56 | { |
57 | rcu_assign_keypointer(key, (struct request_key_auth *)prep->data); |
58 | return 0; |
59 | } |
60 | |
61 | /* |
62 | * Describe an authorisation token. |
63 | */ |
64 | static void request_key_auth_describe(const struct key *key, |
65 | struct seq_file *m) |
66 | { |
67 | struct request_key_auth *rka = dereference_key_rcu(key); |
68 | |
69 | if (!rka) |
70 | return; |
71 | |
72 | seq_puts(m, s: "key:" ); |
73 | seq_puts(m, s: key->description); |
74 | if (key_is_positive(key)) |
75 | seq_printf(m, fmt: " pid:%d ci:%zu" , rka->pid, rka->callout_len); |
76 | } |
77 | |
78 | /* |
79 | * Read the callout_info data (retrieves the callout information). |
80 | * - the key's semaphore is read-locked |
81 | */ |
82 | static long request_key_auth_read(const struct key *key, |
83 | char *buffer, size_t buflen) |
84 | { |
85 | struct request_key_auth *rka = dereference_key_locked(key); |
86 | size_t datalen; |
87 | long ret; |
88 | |
89 | if (!rka) |
90 | return -EKEYREVOKED; |
91 | |
92 | datalen = rka->callout_len; |
93 | ret = datalen; |
94 | |
95 | /* we can return the data as is */ |
96 | if (buffer && buflen > 0) { |
97 | if (buflen > datalen) |
98 | buflen = datalen; |
99 | |
100 | memcpy(buffer, rka->callout_info, buflen); |
101 | } |
102 | |
103 | return ret; |
104 | } |
105 | |
106 | static void free_request_key_auth(struct request_key_auth *rka) |
107 | { |
108 | if (!rka) |
109 | return; |
110 | key_put(key: rka->target_key); |
111 | key_put(key: rka->dest_keyring); |
112 | if (rka->cred) |
113 | put_cred(cred: rka->cred); |
114 | kfree(objp: rka->callout_info); |
115 | kfree(objp: rka); |
116 | } |
117 | |
118 | /* |
119 | * Dispose of the request_key_auth record under RCU conditions |
120 | */ |
121 | static void request_key_auth_rcu_disposal(struct rcu_head *rcu) |
122 | { |
123 | struct request_key_auth *rka = |
124 | container_of(rcu, struct request_key_auth, rcu); |
125 | |
126 | free_request_key_auth(rka); |
127 | } |
128 | |
129 | /* |
130 | * Handle revocation of an authorisation token key. |
131 | * |
132 | * Called with the key sem write-locked. |
133 | */ |
134 | static void request_key_auth_revoke(struct key *key) |
135 | { |
136 | struct request_key_auth *rka = dereference_key_locked(key); |
137 | |
138 | kenter("{%d}" , key->serial); |
139 | rcu_assign_keypointer(key, NULL); |
140 | call_rcu(head: &rka->rcu, func: request_key_auth_rcu_disposal); |
141 | } |
142 | |
143 | /* |
144 | * Destroy an instantiation authorisation token key. |
145 | */ |
146 | static void request_key_auth_destroy(struct key *key) |
147 | { |
148 | struct request_key_auth *rka = rcu_access_pointer(key->payload.rcu_data0); |
149 | |
150 | kenter("{%d}" , key->serial); |
151 | if (rka) { |
152 | rcu_assign_keypointer(key, NULL); |
153 | call_rcu(head: &rka->rcu, func: request_key_auth_rcu_disposal); |
154 | } |
155 | } |
156 | |
157 | /* |
158 | * Create an authorisation token for /sbin/request-key or whoever to gain |
159 | * access to the caller's security data. |
160 | */ |
161 | struct key *request_key_auth_new(struct key *target, const char *op, |
162 | const void *callout_info, size_t callout_len, |
163 | struct key *dest_keyring) |
164 | { |
165 | struct request_key_auth *rka, *irka; |
166 | const struct cred *cred = current_cred(); |
167 | struct key *authkey = NULL; |
168 | char desc[20]; |
169 | int ret = -ENOMEM; |
170 | |
171 | kenter("%d," , target->serial); |
172 | |
173 | /* allocate a auth record */ |
174 | rka = kzalloc(size: sizeof(*rka), GFP_KERNEL); |
175 | if (!rka) |
176 | goto error; |
177 | rka->callout_info = kmemdup(p: callout_info, size: callout_len, GFP_KERNEL); |
178 | if (!rka->callout_info) |
179 | goto error_free_rka; |
180 | rka->callout_len = callout_len; |
181 | strscpy(p: rka->op, q: op, size: sizeof(rka->op)); |
182 | |
183 | /* see if the calling process is already servicing the key request of |
184 | * another process */ |
185 | if (cred->request_key_auth) { |
186 | /* it is - use that instantiation context here too */ |
187 | down_read(sem: &cred->request_key_auth->sem); |
188 | |
189 | /* if the auth key has been revoked, then the key we're |
190 | * servicing is already instantiated */ |
191 | if (test_bit(KEY_FLAG_REVOKED, |
192 | &cred->request_key_auth->flags)) { |
193 | up_read(sem: &cred->request_key_auth->sem); |
194 | ret = -EKEYREVOKED; |
195 | goto error_free_rka; |
196 | } |
197 | |
198 | irka = cred->request_key_auth->payload.data[0]; |
199 | rka->cred = get_cred(cred: irka->cred); |
200 | rka->pid = irka->pid; |
201 | |
202 | up_read(sem: &cred->request_key_auth->sem); |
203 | } |
204 | else { |
205 | /* it isn't - use this process as the context */ |
206 | rka->cred = get_cred(cred); |
207 | rka->pid = current->pid; |
208 | } |
209 | |
210 | rka->target_key = key_get(key: target); |
211 | rka->dest_keyring = key_get(key: dest_keyring); |
212 | |
213 | /* allocate the auth key */ |
214 | sprintf(buf: desc, fmt: "%x" , target->serial); |
215 | |
216 | authkey = key_alloc(type: &key_type_request_key_auth, desc, |
217 | uid: cred->fsuid, gid: cred->fsgid, cred, |
218 | KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | KEY_POS_LINK | |
219 | KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA, NULL); |
220 | if (IS_ERR(ptr: authkey)) { |
221 | ret = PTR_ERR(ptr: authkey); |
222 | goto error_free_rka; |
223 | } |
224 | |
225 | /* construct the auth key */ |
226 | ret = key_instantiate_and_link(key: authkey, data: rka, datalen: 0, NULL, NULL); |
227 | if (ret < 0) |
228 | goto error_put_authkey; |
229 | |
230 | kleave(" = {%d,%d}" , authkey->serial, refcount_read(&authkey->usage)); |
231 | return authkey; |
232 | |
233 | error_put_authkey: |
234 | key_put(key: authkey); |
235 | error_free_rka: |
236 | free_request_key_auth(rka); |
237 | error: |
238 | kleave("= %d" , ret); |
239 | return ERR_PTR(error: ret); |
240 | } |
241 | |
242 | /* |
243 | * Search the current process's keyrings for the authorisation key for |
244 | * instantiation of a key. |
245 | */ |
246 | struct key *key_get_instantiation_authkey(key_serial_t target_id) |
247 | { |
248 | char description[16]; |
249 | struct keyring_search_context ctx = { |
250 | .index_key.type = &key_type_request_key_auth, |
251 | .index_key.description = description, |
252 | .cred = current_cred(), |
253 | .match_data.cmp = key_default_cmp, |
254 | .match_data.raw_data = description, |
255 | .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, |
256 | .flags = (KEYRING_SEARCH_DO_STATE_CHECK | |
257 | KEYRING_SEARCH_RECURSE), |
258 | }; |
259 | struct key *authkey; |
260 | key_ref_t authkey_ref; |
261 | |
262 | ctx.index_key.desc_len = sprintf(buf: description, fmt: "%x" , target_id); |
263 | |
264 | rcu_read_lock(); |
265 | authkey_ref = search_process_keyrings_rcu(ctx: &ctx); |
266 | rcu_read_unlock(); |
267 | |
268 | if (IS_ERR(ptr: authkey_ref)) { |
269 | authkey = ERR_CAST(ptr: authkey_ref); |
270 | if (authkey == ERR_PTR(error: -EAGAIN)) |
271 | authkey = ERR_PTR(error: -ENOKEY); |
272 | goto error; |
273 | } |
274 | |
275 | authkey = key_ref_to_ptr(key_ref: authkey_ref); |
276 | if (test_bit(KEY_FLAG_REVOKED, &authkey->flags)) { |
277 | key_put(key: authkey); |
278 | authkey = ERR_PTR(error: -EKEYREVOKED); |
279 | } |
280 | |
281 | error: |
282 | return authkey; |
283 | } |
284 | |