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
_prop_object_externalize_to_pref(prop_object_t obj,struct plistref * pref,char ** bufp)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
prop_array_externalize_to_pref(prop_array_t array,struct plistref * prefp)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
prop_array_send_syscall(prop_array_t array,struct plistref * prefp)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
prop_dictionary_externalize_to_pref(prop_dictionary_t dict,struct plistref * prefp)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
prop_dictionary_send_syscall(prop_dictionary_t dict,struct plistref * prefp)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
_prop_object_send_ioctl(prop_object_t obj,int fd,unsigned long cmd)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
prop_array_send_ioctl(prop_array_t array,int fd,unsigned long cmd)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
prop_dictionary_send_ioctl(prop_dictionary_t dict,int fd,unsigned long cmd)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
_prop_object_internalize_from_pref(const struct plistref * pref,prop_type_t type,prop_object_t * objp)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
prop_array_internalize_from_pref(const struct plistref * prefp,prop_array_t * arrayp)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
prop_array_recv_syscall(const struct plistref * prefp,prop_array_t * arrayp)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
prop_dictionary_internalize_from_pref(const struct plistref * prefp,prop_dictionary_t * dictp)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
prop_dictionary_recv_syscall(const struct plistref * prefp,prop_dictionary_t * dictp)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
prop_array_recv_ioctl(int fd,unsigned long cmd,prop_array_t * arrayp)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
prop_dictionary_recv_ioctl(int fd,unsigned long cmd,prop_dictionary_t * dictp)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
prop_dictionary_sendrecv_ioctl(prop_dictionary_t dict,int fd,unsigned long cmd,prop_dictionary_t * dictp)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
_prop_object_copyin(const struct plistref * pref,const prop_type_t type,prop_object_t * objp)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
_prop_object_copyin_ioctl(const struct plistref * pref,const prop_type_t type,const u_long cmd,prop_object_t * objp)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
prop_array_copyin(const struct plistref * pref,prop_array_t * arrayp)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
prop_dictionary_copyin(const struct plistref * pref,prop_dictionary_t * dictp)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
prop_array_copyin_ioctl(const struct plistref * pref,const u_long cmd,prop_array_t * arrayp)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
prop_dictionary_copyin_ioctl(const struct plistref * pref,const u_long cmd,prop_dictionary_t * dictp)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
_prop_object_copyout(struct plistref * pref,prop_object_t obj)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
prop_array_copyout(struct plistref * pref,prop_array_t array)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
prop_dictionary_copyout(struct plistref * pref,prop_dictionary_t dict)554 prop_dictionary_copyout(struct plistref *pref, prop_dictionary_t dict)
555 {
556 return (_prop_object_copyout(pref, dict));
557 }
558
559 static int
_prop_object_copyout_ioctl(struct plistref * pref,const u_long cmd,prop_object_t obj)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
prop_array_copyout_ioctl(struct plistref * pref,const u_long cmd,prop_array_t array)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
prop_dictionary_copyout_ioctl(struct plistref * pref,const u_long cmd,prop_dictionary_t dict)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