xref: /dragonfly/sys/libprop/prop_kern.c (revision 382849162380481a43b977a890313c5822ab8365)
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