xref: /dragonfly/sys/libprop/prop_kern.c (revision c9c5aa9e)
1 /*	$NetBSD: prop_kern.c,v 1.17 2011/09/30 22:08:18 jym Exp $	*/
2 
3 /*-
4  * Copyright (c) 2006, 2009 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/types.h>
33 
34 #include <libprop/proplib.h>
35 
36 #if !defined(_KERNEL) && !defined(_STANDALONE)
37 #include <sys/mman.h>
38 #include <errno.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <sys/ioctl.h>
43 
44 static int
45 _prop_object_externalize_to_pref(prop_object_t obj, struct plistref *pref,
46 	       			 char **bufp)
47 {
48 	char *buf;
49 
50 	switch (prop_object_type(obj)) {
51 	case PROP_TYPE_DICTIONARY:
52 		buf = prop_dictionary_externalize(obj);
53 		break;
54 	case PROP_TYPE_ARRAY:
55 		buf = prop_array_externalize(obj);
56 		break;
57 	default:
58 		return (ENOTSUP);
59 	}
60 	if (buf == NULL) {
61 		/* Assume we ran out of memory. */
62 		return (ENOMEM);
63 	}
64 	pref->pref_plist = buf;
65 	pref->pref_len = strlen(buf) + 1;
66 
67 	*bufp = buf;
68 
69 	return (0);
70 }
71 
72 bool
73 prop_array_externalize_to_pref(prop_array_t array, struct plistref *prefp)
74 {
75 	char *buf;
76 	int rv;
77 
78 	rv = _prop_object_externalize_to_pref(array, prefp, &buf);
79 	if (rv != 0)
80 		errno = rv;	/* pass up error value in errno */
81 	return (rv == 0);
82 }
83 
84 /*
85  * prop_array_externalize_to_pref --
86  *	Externalize an array into a plistref for sending to the kernel.
87  */
88 int
89 prop_array_send_syscall(prop_array_t array, struct plistref *prefp)
90 {
91 	if (prop_array_externalize_to_pref(array, prefp))
92 		return 0;
93 	else
94 		return errno;
95 }
96 
97 bool
98 prop_dictionary_externalize_to_pref(prop_dictionary_t dict,
99 				    struct plistref *prefp)
100 {
101 	char *buf;
102 	int rv;
103 
104 	rv = _prop_object_externalize_to_pref(dict, prefp, &buf);
105 	if (rv != 0)
106 		errno = rv;	/* pass up error value in errno */
107 	return (rv == 0);
108 }
109 
110 /*
111  * prop_dictionary_externalize_to_pref --
112  *	Externalize an dictionary into a plistref for sending to the kernel.
113  */
114 int
115 prop_dictionary_send_syscall(prop_dictionary_t dict,
116 			     struct plistref *prefp)
117 {
118 	if (prop_dictionary_externalize_to_pref(dict, prefp))
119 		return 0;
120 	else
121 		return errno;
122 }
123 
124 static int
125 _prop_object_send_ioctl(prop_object_t obj, int fd, unsigned long cmd)
126 {
127 	struct plistref pref;
128 	char *buf;
129 	int error;
130 
131 	error = _prop_object_externalize_to_pref(obj, &pref, &buf);
132 	if (error)
133 		return (error);
134 
135 	if (ioctl(fd, cmd, &pref) == -1)
136 		error = errno;
137 	else
138 		error = 0;
139 
140 	free(buf);
141 
142 	return (error);
143 }
144 
145 /*
146  * prop_array_send_ioctl --
147  *	Send an array to the kernel using the specified ioctl.
148  */
149 int
150 prop_array_send_ioctl(prop_array_t array, int fd, unsigned long cmd)
151 {
152 	int rv;
153 
154 	rv = _prop_object_send_ioctl(array, fd, cmd);
155 	if (rv != 0) {
156 		errno = rv;	/* pass up error value in errno */
157 		return rv;
158 	} else
159 		return 0;
160 }
161 
162 /*
163  * prop_dictionary_send_ioctl --
164  *	Send a dictionary to the kernel using the specified ioctl.
165  */
166 int
167 prop_dictionary_send_ioctl(prop_dictionary_t dict, int fd, unsigned long cmd)
168 {
169 	int rv;
170 
171 	rv = _prop_object_send_ioctl(dict, fd, cmd);
172 	if (rv != 0) {
173 		errno = rv;	/* pass up error value in errno */
174 		return rv;
175 	} else
176 		return 0;
177 }
178 
179 static int
180 _prop_object_internalize_from_pref(const struct plistref *pref,
181 				   prop_type_t type, prop_object_t *objp)
182 {
183 	prop_object_t obj = NULL;
184 	char *buf;
185 	int error = 0;
186 
187 	if (pref->pref_len == 0) {
188 		/*
189 		 * This should never happen; we should always get the XML
190 		 * for an empty dictionary if it's really empty.
191 		 */
192 		error = EIO;
193 		goto out;
194 	} else {
195 		buf = pref->pref_plist;
196 		buf[pref->pref_len - 1] = '\0';	/* extra insurance */
197 		switch (type) {
198 		case PROP_TYPE_DICTIONARY:
199 			obj = prop_dictionary_internalize(buf);
200 			break;
201 		case PROP_TYPE_ARRAY:
202 			obj = prop_array_internalize(buf);
203 			break;
204 		default:
205 			error = ENOTSUP;
206 		}
207 		(void) munmap(buf, pref->pref_len);
208 		if (obj == NULL && error == 0)
209 			error = EIO;
210 	}
211 
212  out:
213 	if (error == 0)
214 		*objp = obj;
215 	return (error);
216 }
217 
218 /*
219  * prop_array_internalize_from_pref --
220  * 	Internalize a pref into a prop_array_t object.
221  */
222 bool
223 prop_array_internalize_from_pref(const struct plistref *prefp,
224 				 prop_array_t *arrayp)
225 {
226 	int rv;
227 
228 	rv = _prop_object_internalize_from_pref(prefp, PROP_TYPE_ARRAY,
229 	    (prop_object_t *)arrayp);
230 	if (rv != 0)
231 		errno = rv;     /* pass up error value in errno */
232 	return (rv == 0);
233 }
234 
235 /*
236  * prop_array_recv_syscall --
237  * 	Internalize an array received from the kernel as pref.
238  */
239 int
240 prop_array_recv_syscall(const struct plistref *prefp,
241 			prop_array_t *arrayp)
242 {
243 	if (prop_array_internalize_from_pref(prefp, arrayp))
244 		return 0;
245 	else
246 		return errno;
247 }
248 
249 /*
250  * prop_dictionary_internalize_from_pref --
251  * 	Internalize a pref into a prop_dictionary_t object.
252  */
253 bool
254 prop_dictionary_internalize_from_pref(const struct plistref *prefp,
255 				      prop_dictionary_t *dictp)
256 {
257 	int rv;
258 
259 	rv = _prop_object_internalize_from_pref(prefp, PROP_TYPE_DICTIONARY,
260 	    (prop_object_t *)dictp);
261 	if (rv != 0)
262 		errno = rv;     /* pass up error value in errno */
263 	return (rv == 0);
264 }
265 
266 /*
267  * prop_dictionary_recv_syscall --
268  *	Internalize a dictionary received from the kernel as pref.
269  */
270 int
271 prop_dictionary_recv_syscall(const struct plistref *prefp,
272 			     prop_dictionary_t *dictp)
273 {
274 	if (prop_dictionary_internalize_from_pref(prefp, dictp))
275 		return 0;
276 	else
277 		return errno;
278 }
279 
280 
281 /*
282  * prop_array_recv_ioctl --
283  *	Receive an array from the kernel using the specified ioctl.
284  */
285 int
286 prop_array_recv_ioctl(int fd, unsigned long cmd, prop_array_t *arrayp)
287 {
288 	int rv;
289 	struct plistref pref;
290 
291 	rv = ioctl(fd, cmd, &pref);
292 	if (rv == -1)
293 		return errno;
294 
295 	rv = _prop_object_internalize_from_pref(&pref, PROP_TYPE_ARRAY,
296 			    (prop_object_t *)arrayp);
297 	if (rv != 0) {
298 		errno = rv;     /* pass up error value in errno */
299 		return rv;
300 	} else
301 		return 0;
302 }
303 
304 /*
305  * prop_dictionary_recv_ioctl --
306  *	Receive a dictionary from the kernel using the specified ioctl.
307  */
308 int
309 prop_dictionary_recv_ioctl(int fd, unsigned long cmd, prop_dictionary_t *dictp)
310 {
311 	int rv;
312 	struct plistref pref;
313 
314 	rv = ioctl(fd, cmd, &pref);
315 	if (rv == -1)
316 		return errno;
317 
318 	rv = _prop_object_internalize_from_pref(&pref, PROP_TYPE_DICTIONARY,
319 			    (prop_object_t *)dictp);
320 	if (rv != 0) {
321 		errno = rv;     /* pass up error value in errno */
322 		return rv;
323 	} else
324 		return 0;
325 }
326 
327 /*
328  * prop_dictionary_sendrecv_ioctl --
329  *	Combination send/receive a dictionary to/from the kernel using
330  *	the specified ioctl.
331  */
332 int
333 prop_dictionary_sendrecv_ioctl(prop_dictionary_t dict, int fd,
334 			       unsigned long cmd, prop_dictionary_t *dictp)
335 {
336 	struct plistref pref;
337 	char *buf;
338 	int error;
339 
340 	error = _prop_object_externalize_to_pref(dict, &pref, &buf);
341 	if (error != 0) {
342 		errno = error;
343 		return error;
344 	}
345 
346 	if (ioctl(fd, cmd, &pref) == -1)
347 		error = errno;
348 	else
349 		error = 0;
350 
351 	free(buf);
352 
353 	if (error != 0)
354 		return error;
355 
356 	error = _prop_object_internalize_from_pref(&pref, PROP_TYPE_DICTIONARY,
357 			    (prop_object_t *)dictp);
358 	if (error != 0) {
359 		errno = error;     /* pass up error value in errno */
360 		return error;
361 	} else
362 		return 0;
363 }
364 #endif /* !_KERNEL && !_STANDALONE */
365 
366 #if defined(_KERNEL)
367 #include <sys/param.h>
368 #include <sys/mman.h>
369 #include <sys/errno.h>
370 #include <sys/malloc.h>
371 #include <sys/systm.h>
372 #include <sys/proc.h>
373 #include <sys/resource.h>
374 #include <sys/objcache.h>
375 #include <sys/ioccom.h>
376 #include <vm/vm.h>
377 #include <vm/vm_extern.h>
378 #include <vm/vm_param.h>
379 
380 #include "prop_object_impl.h"
381 
382 /* Arbitrary limit ioctl input to 64KB */
383 unsigned int prop_object_copyin_limit = 65536;
384 
385 static int
386 _prop_object_copyin(const struct plistref *pref, const prop_type_t type,
387 			  prop_object_t *objp)
388 {
389 	prop_object_t obj = NULL;
390 	char *buf;
391 	int error;
392 
393 	/*
394 	 * Allocate an extra byte so we can guarantee NUL-termination.
395 	 *
396 	 * Allow malloc to fail in case pmap would be exhausted.
397 	 */
398 	buf = kmalloc(pref->pref_len + 1, M_TEMP, M_WAITOK);
399 	error = copyin(pref->pref_plist, buf, pref->pref_len);
400 	if (error) {
401 		kfree(buf, M_TEMP);
402 		return (error);
403 	}
404 	buf[pref->pref_len] = '\0';
405 
406 	switch (type) {
407 	case PROP_TYPE_ARRAY:
408 		obj = prop_array_internalize(buf);
409 		break;
410 	case PROP_TYPE_DICTIONARY:
411 		obj = prop_dictionary_internalize(buf);
412 		break;
413 	default:
414 		error = ENOTSUP;
415 	}
416 
417 	kfree(buf, M_TEMP);
418 	if (obj == NULL) {
419 		if (error == 0)
420 			error = EIO;
421 	} else {
422 		*objp = obj;
423 	}
424 	return (error);
425 }
426 
427 
428 static int
429 _prop_object_copyin_ioctl(const struct plistref *pref, const prop_type_t type,
430 			  const u_long cmd, prop_object_t *objp)
431 {
432 	if ((cmd & IOC_IN) == 0)
433 		return (EFAULT);
434 
435 	return _prop_object_copyin(pref, type, objp);
436 }
437 
438 /*
439  * prop_array_copyin --
440  *	Copy in an array passed as a syscall arg.
441  */
442 int
443 prop_array_copyin(const struct plistref *pref, prop_array_t *arrayp)
444 {
445 	return (_prop_object_copyin(pref, PROP_TYPE_ARRAY,
446 					  (prop_object_t *)arrayp));
447 }
448 
449 /*
450  * prop_dictionary_copyin --
451  *	Copy in a dictionary passed as a syscall arg.
452  */
453 int
454 prop_dictionary_copyin(const struct plistref *pref, prop_dictionary_t *dictp)
455 {
456 	return (_prop_object_copyin(pref, PROP_TYPE_DICTIONARY,
457 					  (prop_object_t *)dictp));
458 }
459 
460 
461 /*
462  * prop_array_copyin_ioctl --
463  *	Copy in an array send with an ioctl.
464  */
465 int
466 prop_array_copyin_ioctl(const struct plistref *pref, const u_long cmd,
467 			prop_array_t *arrayp)
468 {
469 	return (_prop_object_copyin_ioctl(pref, PROP_TYPE_ARRAY,
470 					  cmd, (prop_object_t *)arrayp));
471 }
472 
473 /*
474  * prop_dictionary_copyin_ioctl --
475  *	Copy in a dictionary sent with an ioctl.
476  */
477 int
478 prop_dictionary_copyin_ioctl(const struct plistref *pref, const u_long cmd,
479 			     prop_dictionary_t *dictp)
480 {
481 	return (_prop_object_copyin_ioctl(pref, PROP_TYPE_DICTIONARY,
482 					  cmd, (prop_object_t *)dictp));
483 }
484 
485 static int
486 _prop_object_copyout(struct plistref *pref, prop_object_t obj)
487 {
488 	struct proc *p = curproc;
489 	char *buf;
490 	size_t len, rlen;
491 	int error = 0;
492 	vm_offset_t uaddr;
493 
494 	switch (prop_object_type(obj)) {
495 	case PROP_TYPE_ARRAY:
496 		buf = prop_array_externalize(obj);
497 		break;
498 	case PROP_TYPE_DICTIONARY:
499 		buf = prop_dictionary_externalize(obj);
500 		break;
501 	default:
502 		return (ENOTSUP);
503 	}
504 	if (buf == NULL)
505 		return (ENOMEM);
506 
507 	len = strlen(buf) + 1;
508 	rlen = round_page(len);
509 
510 	/*
511 	 * See sys_mmap() in sys/uvm/uvm_mmap.c.
512 	 * Let's act as if we were calling mmap(0, ...)
513 	 */
514 #if 0
515 	uaddr = p->p_emul->e_vm_default_addr(p,
516 	    (vaddr_t)p->p_vmspace->vm_daddr, rlen);
517 #endif
518 	uaddr = round_page((vm_offset_t)p->p_vmspace->vm_daddr + maxdsiz);
519 
520 	error = vm_mmap(&p->p_vmspace->vm_map,
521 			 &uaddr, rlen,
522 			 VM_PROT_READ|VM_PROT_WRITE,
523 			 VM_PROT_READ|VM_PROT_WRITE,
524 			 MAP_PRIVATE|MAP_ANON,
525 			 NULL, 0, NULL);
526 	if (error == 0) {
527 		error = copyout(buf, (char *)uaddr, len);
528 		if (error == 0) {
529 			pref->pref_plist = (char *)uaddr;
530 			pref->pref_len   = len;
531 		}
532 	}
533 
534 	kfree(buf, M_TEMP);
535 
536 	return (error);
537 }
538 
539 /*
540  * prop_array_copyout --
541  *	Copy out an array to a syscall arg.
542  */
543 int
544 prop_array_copyout(struct plistref *pref, prop_array_t array)
545 {
546 	return (_prop_object_copyout(pref, array));
547 }
548 
549 /*
550  * prop_dictionary_copyout --
551  *	Copy out a dictionary to a syscall arg.
552  */
553 int
554 prop_dictionary_copyout(struct plistref *pref, prop_dictionary_t dict)
555 {
556 	return (_prop_object_copyout(pref, dict));
557 }
558 
559 static int
560 _prop_object_copyout_ioctl(struct plistref *pref, const u_long cmd,
561 			   prop_object_t obj)
562 {
563 	if ((cmd & IOC_OUT) == 0)
564 		return (EFAULT);
565 	return _prop_object_copyout(pref, obj);
566 }
567 
568 
569 /*
570  * prop_array_copyout_ioctl --
571  *	Copy out an array being received with an ioctl.
572  */
573 int
574 prop_array_copyout_ioctl(struct plistref *pref, const u_long cmd,
575 			 prop_array_t array)
576 {
577 	return (_prop_object_copyout_ioctl(pref, cmd, array));
578 }
579 
580 /*
581  * prop_dictionary_copyout_ioctl --
582  *	Copy out a dictionary being received with an ioctl.
583  */
584 int
585 prop_dictionary_copyout_ioctl(struct plistref *pref, const u_long cmd,
586 			      prop_dictionary_t dict)
587 {
588 	return (
589 	    _prop_object_copyout_ioctl(pref, cmd, dict));
590 }
591 #endif /* _KERNEL */
592