1 /*
2  * Copyright (c) 2014-2015 Dmitry V. Levin <ldv@altlinux.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "defs.h"
29 
30 typedef int32_t key_serial_t;
31 
32 #include "xlat/key_spec.h"
33 
34 struct keyctl_dh_params {
35 	int32_t private;
36 	int32_t prime;
37 	int32_t base;
38 };
39 
40 static void
print_keyring_serial_number(key_serial_t id)41 print_keyring_serial_number(key_serial_t id)
42 {
43 	const char *str = xlookup(key_spec, (unsigned int) id);
44 
45 	if (str)
46 		tprints(str);
47 	else
48 		tprintf("%d", id);
49 }
50 
SYS_FUNC(add_key)51 SYS_FUNC(add_key)
52 {
53 	/* type */
54 	printstr(tcp, tcp->u_arg[0]);
55 	/* description */
56 	tprints(", ");
57 	printstr(tcp, tcp->u_arg[1]);
58 	/* payload */
59 	tprints(", ");
60 	printstrn(tcp, tcp->u_arg[2], tcp->u_arg[3]);
61 	/* payload length */
62 	tprintf(", %" PRI_klu ", ", tcp->u_arg[3]);
63 	/* keyring serial number */
64 	print_keyring_serial_number(tcp->u_arg[4]);
65 
66 	return RVAL_DECODED;
67 }
68 
SYS_FUNC(request_key)69 SYS_FUNC(request_key)
70 {
71 	/* type */
72 	printstr(tcp, tcp->u_arg[0]);
73 	/* description */
74 	tprints(", ");
75 	printstr(tcp, tcp->u_arg[1]);
76 	/* callout_info */
77 	tprints(", ");
78 	printstr(tcp, tcp->u_arg[2]);
79 	/* keyring serial number */
80 	tprints(", ");
81 	print_keyring_serial_number(tcp->u_arg[3]);
82 
83 	return RVAL_DECODED;
84 }
85 
86 static void
keyctl_get_keyring_id(struct tcb * tcp,key_serial_t id,int create)87 keyctl_get_keyring_id(struct tcb *tcp, key_serial_t id, int create)
88 {
89 	print_keyring_serial_number(id);
90 	tprintf(", %d", create);
91 }
92 
93 static void
keyctl_update_key(struct tcb * tcp,key_serial_t id,kernel_ulong_t addr,kernel_ulong_t len)94 keyctl_update_key(struct tcb *tcp, key_serial_t id, kernel_ulong_t addr,
95 		  kernel_ulong_t len)
96 {
97 	print_keyring_serial_number(id);
98 	tprints(", ");
99 	printstrn(tcp, addr, len);
100 	tprintf(", %llu", zero_extend_signed_to_ull(len));
101 }
102 
103 static void
keyctl_handle_key_key(struct tcb * tcp,key_serial_t id1,key_serial_t id2)104 keyctl_handle_key_key(struct tcb *tcp, key_serial_t id1, key_serial_t id2)
105 {
106 	print_keyring_serial_number(id1);
107 	tprints(", ");
108 	print_keyring_serial_number(id2);
109 }
110 
111 static void
keyctl_read_key(struct tcb * tcp,key_serial_t id,kernel_ulong_t addr,kernel_ulong_t len,bool has_nul)112 keyctl_read_key(struct tcb *tcp, key_serial_t id, kernel_ulong_t addr,
113 		kernel_ulong_t len, bool has_nul)
114 {
115 	if (entering(tcp)) {
116 		print_keyring_serial_number(id);
117 		tprints(", ");
118 	} else {
119 		if (syserror(tcp))
120 			printaddr(addr);
121 		else {
122 			kernel_ulong_t rval = (tcp->u_rval >= 0) &&
123 				((kernel_ulong_t) tcp->u_rval > len) ? len :
124 				(kernel_ulong_t) tcp->u_rval;
125 			printstr_ex(tcp, addr, rval, has_nul ?
126 				    QUOTE_OMIT_TRAILING_0 : 0);
127 		}
128 		tprintf(", %llu", zero_extend_signed_to_ull(len));
129 	}
130 }
131 
132 static void
keyctl_keyring_search(struct tcb * tcp,key_serial_t id1,kernel_ulong_t addr1,kernel_ulong_t addr2,key_serial_t id2)133 keyctl_keyring_search(struct tcb *tcp, key_serial_t id1, kernel_ulong_t addr1,
134 		      kernel_ulong_t addr2, key_serial_t id2)
135 {
136 	print_keyring_serial_number(id1);
137 	tprints(", ");
138 	printstr(tcp, addr1);
139 	tprints(", ");
140 	printstr(tcp, addr2);
141 	tprints(", ");
142 	print_keyring_serial_number(id2);
143 }
144 
145 static void
keyctl_chown_key(struct tcb * tcp,key_serial_t id,unsigned user,unsigned group)146 keyctl_chown_key(struct tcb *tcp, key_serial_t id, unsigned user,
147 		 unsigned group)
148 {
149 	print_keyring_serial_number(id);
150 	printuid(", ", user);
151 	printuid(", ", group);
152 }
153 
154 static void
keyctl_instantiate_key(struct tcb * tcp,key_serial_t id1,kernel_ulong_t addr,kernel_ulong_t len,key_serial_t id2)155 keyctl_instantiate_key(struct tcb *tcp, key_serial_t id1, kernel_ulong_t addr,
156 		       kernel_ulong_t len, key_serial_t id2)
157 {
158 	print_keyring_serial_number(id1);
159 	tprints(", ");
160 	printstrn(tcp, addr, len);
161 	tprintf(", %llu, ", zero_extend_signed_to_ull(len));
162 	print_keyring_serial_number(id2);
163 }
164 
165 static void
keyctl_instantiate_key_iov(struct tcb * tcp,key_serial_t id1,kernel_ulong_t addr,kernel_ulong_t len,key_serial_t id2)166 keyctl_instantiate_key_iov(struct tcb *tcp, key_serial_t id1,
167 			   kernel_ulong_t addr, kernel_ulong_t len,
168 			   key_serial_t id2)
169 {
170 	print_keyring_serial_number(id1);
171 	tprints(", ");
172 	tprint_iov(tcp, len, addr, IOV_DECODE_STR);
173 	tprintf(", %llu, ", zero_extend_signed_to_ull(len));
174 	print_keyring_serial_number(id2);
175 }
176 
177 static void
keyctl_negate_key(struct tcb * tcp,key_serial_t id1,unsigned timeout,key_serial_t id2)178 keyctl_negate_key(struct tcb *tcp, key_serial_t id1, unsigned timeout,
179 		  key_serial_t id2)
180 {
181 	print_keyring_serial_number(id1);
182 	tprintf(", %u, ", timeout);
183 	print_keyring_serial_number(id2);
184 }
185 
186 static void
keyctl_reject_key(struct tcb * tcp,key_serial_t id1,unsigned timeout,unsigned error,key_serial_t id2)187 keyctl_reject_key(struct tcb *tcp, key_serial_t id1, unsigned timeout,
188 		  unsigned error, key_serial_t id2)
189 {
190 	const char *err_str = err_name(error);
191 
192 	print_keyring_serial_number(id1);
193 	tprintf(", %u, ", timeout);
194 
195 	if (err_str)
196 		tprintf("%s, ", err_str);
197 	else
198 		tprintf("%u, ", error);
199 
200 	print_keyring_serial_number(id2);
201 }
202 
203 static void
keyctl_set_timeout(struct tcb * tcp,key_serial_t id,unsigned timeout)204 keyctl_set_timeout(struct tcb *tcp, key_serial_t id, unsigned timeout)
205 {
206 	print_keyring_serial_number(id);
207 	tprintf(", %u", timeout);
208 }
209 
210 static void
keyctl_get_persistent(struct tcb * tcp,unsigned uid,key_serial_t id)211 keyctl_get_persistent(struct tcb *tcp, unsigned uid, key_serial_t id)
212 {
213 	printuid("", uid);
214 	tprints(", ");
215 	print_keyring_serial_number(id);
216 }
217 
218 #include "xlat/key_perms.h"
219 
220 static void
keyctl_setperm_key(struct tcb * tcp,key_serial_t id,uint32_t perm)221 keyctl_setperm_key(struct tcb *tcp, key_serial_t id, uint32_t perm)
222 {
223 	print_keyring_serial_number(id);
224 	tprints(", ");
225 	printflags(key_perms, perm, "KEY_???");
226 }
227 
228 static void
print_dh_params(struct tcb * tcp,kernel_ulong_t addr)229 print_dh_params(struct tcb *tcp, kernel_ulong_t addr)
230 {
231 	struct keyctl_dh_params params;
232 
233 	if (umove_or_printaddr(tcp, addr, &params))
234 		return;
235 
236 	tprints("{private=");
237 	print_keyring_serial_number(params.private);
238 	tprints(", prime=");
239 	print_keyring_serial_number(params.prime);
240 	tprints(", base=");
241 	print_keyring_serial_number(params.base);
242 	tprints("}");
243 }
244 
245 static void
keyctl_dh_compute(struct tcb * tcp,kernel_ulong_t params,kernel_ulong_t buf,kernel_ulong_t len)246 keyctl_dh_compute(struct tcb *tcp, kernel_ulong_t params, kernel_ulong_t buf,
247 		  kernel_ulong_t len)
248 {
249 	if (entering(tcp)) {
250 		print_dh_params(tcp, params);
251 		tprints(", ");
252 	} else {
253 		if (syserror(tcp)) {
254 			printaddr(buf);
255 		} else {
256 			kernel_ulong_t rval = (tcp->u_rval >= 0) &&
257 				((kernel_ulong_t) tcp->u_rval > len) ? len :
258 				(kernel_ulong_t) tcp->u_rval;
259 			printstrn(tcp, buf, rval);
260 		}
261 		tprintf(", %llu", zero_extend_signed_to_ull(len));
262 	}
263 }
264 
265 #include "xlat/key_reqkeys.h"
266 #include "xlat/keyctl_commands.h"
267 
SYS_FUNC(keyctl)268 SYS_FUNC(keyctl)
269 {
270 	int cmd = tcp->u_arg[0];
271 	kernel_ulong_t arg2 = tcp->u_arg[1];
272 	kernel_ulong_t arg3 = tcp->u_arg[2];
273 	kernel_ulong_t arg4 = tcp->u_arg[3];
274 	kernel_ulong_t arg5 = tcp->u_arg[4];
275 
276 	if (entering(tcp)) {
277 		printxval(keyctl_commands, cmd, "KEYCTL_???");
278 
279 		/*
280 		 * For now, KEYCTL_SESSION_TO_PARENT is the only cmd without
281 		 * arguments.
282 		 */
283 		if (cmd != KEYCTL_SESSION_TO_PARENT)
284 			tprints(", ");
285 	}
286 
287 	switch (cmd) {
288 	case KEYCTL_GET_KEYRING_ID:
289 		keyctl_get_keyring_id(tcp, arg2, arg3);
290 		break;
291 
292 	case KEYCTL_JOIN_SESSION_KEYRING:
293 		printstr(tcp, arg2);
294 		break;
295 
296 	case KEYCTL_UPDATE:
297 		keyctl_update_key(tcp, arg2, arg3, arg4);
298 		break;
299 
300 	case KEYCTL_REVOKE:
301 	case KEYCTL_CLEAR:
302 	case KEYCTL_INVALIDATE:
303 	case KEYCTL_ASSUME_AUTHORITY:
304 		print_keyring_serial_number(arg2);
305 		break;
306 
307 	case KEYCTL_LINK:
308 	case KEYCTL_UNLINK:
309 		keyctl_handle_key_key(tcp, arg2, arg3);
310 		break;
311 
312 	case KEYCTL_DESCRIBE:
313 	case KEYCTL_READ:
314 	case KEYCTL_GET_SECURITY:
315 		keyctl_read_key(tcp, arg2, arg3, arg4, cmd != KEYCTL_READ);
316 		return 0;
317 
318 	case KEYCTL_SEARCH:
319 		keyctl_keyring_search(tcp, arg2, arg3, arg4, arg5);
320 		break;
321 
322 	case KEYCTL_CHOWN:
323 		keyctl_chown_key(tcp, arg2, arg3, arg4);
324 		break;
325 
326 	case KEYCTL_SETPERM:
327 		keyctl_setperm_key(tcp, arg2, arg3);
328 		break;
329 
330 	case KEYCTL_INSTANTIATE:
331 		keyctl_instantiate_key(tcp, arg2, arg3, arg4, arg5);
332 		break;
333 
334 	case KEYCTL_NEGATE:
335 		keyctl_negate_key(tcp, arg2, arg3, arg4);
336 		break;
337 
338 	case KEYCTL_SET_REQKEY_KEYRING:
339 		printxval(key_reqkeys, arg2, "KEY_REQKEY_DEFL_???");
340 		break;
341 
342 	case KEYCTL_SET_TIMEOUT:
343 		keyctl_set_timeout(tcp, arg2, arg3);
344 		break;
345 
346 	case KEYCTL_SESSION_TO_PARENT:
347 		break;
348 
349 	case KEYCTL_REJECT:
350 		keyctl_reject_key(tcp, arg2, arg3, arg4, arg5);
351 		break;
352 
353 	case KEYCTL_INSTANTIATE_IOV:
354 		keyctl_instantiate_key_iov(tcp, arg2, arg3, arg4, arg5);
355 		break;
356 
357 	case KEYCTL_GET_PERSISTENT:
358 		keyctl_get_persistent(tcp, arg2, arg3);
359 		break;
360 
361 	case KEYCTL_DH_COMPUTE:
362 		keyctl_dh_compute(tcp, arg2, arg3, arg4);
363 		return 0;
364 
365 	default:
366 		tprintf("%#" PRI_klx ", %#" PRI_klx
367 			", %#" PRI_klx ", %#" PRI_klx,
368 			arg2, arg3, arg4, arg5);
369 		break;
370 	}
371 
372 	return RVAL_DECODED;
373 }
374