1 /*        $NetBSD: prop_kern.c,v 1.29 2025/04/27 02:54:05 kre Exp $   */
2 
3 /*-
4  * Copyright (c) 2006, 2009, 2025 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 #if defined(__NetBSD__)
33 
34 #include <sys/types.h>
35 #include <sys/ioctl.h>
36 
37 #include <prop/proplib.h>
38 
39 #if defined(HAVE_NBTOOL_CONFIG_H) || defined(_STANDALONE)
40 #define _PROP_EXPORT
41 #else
42 #include "prop_object_impl.h"           /* for _PROP_EXPORT */
43 #endif
44 
45 #if !defined(_KERNEL) && !defined(_STANDALONE)
46 #include <sys/mman.h>
47 #include <errno.h>
48 #include <string.h>
49 #include <stdlib.h>
50 #include <stdio.h>
51 
52 #ifdef RUMP_ACTION
53 #include <rump/rump_syscalls.h>
54 #define ioctl(a,b,c) rump_sys_ioctl(a,b,c)
55 #endif
56 
57 /*
58  * prop_object_externalize_to_pref --
59  *        Externalize an object into a plistref for sending to the kernel.
60  */
61 static int
_prop_object_externalize_to_pref(prop_object_t obj,struct plistref * pref,char ** bufp)62 _prop_object_externalize_to_pref(prop_object_t obj, struct plistref *pref,
63                                          char **bufp)
64 {
65           char *buf = prop_object_externalize(obj);
66 
67           if (buf == NULL) {
68                     /* Assume we ran out of memory. */
69                     return (ENOMEM);
70           }
71           pref->pref_plist = buf;
72           pref->pref_len = strlen(buf) + 1;
73 
74           if (bufp != NULL) {
75                     *bufp = buf;
76           }
77 
78           return (0);
79 }
80 
81 static bool
prop_object_externalize_to_pref(prop_object_t obj,struct plistref * prefp)82 prop_object_externalize_to_pref(prop_object_t obj, struct plistref *prefp)
83 {
84           int rv = _prop_object_externalize_to_pref(obj, prefp, NULL);
85           if (rv != 0)
86                     errno = rv;         /* pass up error value in errno */
87           return (rv == 0);
88 }
89 
90 _PROP_EXPORT bool
prop_array_externalize_to_pref(prop_array_t array,struct plistref * prefp)91 prop_array_externalize_to_pref(prop_array_t array, struct plistref *prefp)
92 {
93           return prop_object_externalize_to_pref(array, prefp);
94 }
__strong_alias(prop_dictionary_externalize_to_pref,prop_array_externalize_to_pref)95 __strong_alias(prop_dictionary_externalize_to_pref,
96                  prop_array_externalize_to_pref)
97 
98 _PROP_EXPORT int
99 prop_object_send_syscall(prop_object_t obj, struct plistref *prefp)
100 {
101           if (prop_object_externalize_to_pref(obj, prefp))
102                     return 0;
103           else
104                     return errno;
105 }
__strong_alias(prop_array_send_syscall,prop_object_send_syscall)106 __strong_alias(prop_array_send_syscall, prop_object_send_syscall)
107 __strong_alias(prop_dictionary_send_syscall, prop_object_send_syscall)
108 
109 /*
110  * prop_object_send_ioctl --
111  *        Send an array to the kernel using the specified ioctl.
112  */
113 static int
114 _prop_object_send_ioctl(prop_object_t obj, int fd, unsigned long cmd)
115 {
116           struct plistref pref;
117           char *buf;
118           int error;
119 
120           error = _prop_object_externalize_to_pref(obj, &pref, &buf);
121           if (error)
122                     return (error);
123 
124           if (ioctl(fd, cmd, &pref) == -1)
125                     error = errno;
126           else
127                     error = 0;
128 
129           free(buf);
130 
131           return (error);
132 }
133 
134 _PROP_EXPORT int
prop_object_send_ioctl(prop_object_t obj,int fd,unsigned long cmd)135 prop_object_send_ioctl(prop_object_t obj, int fd, unsigned long cmd)
136 {
137           int rv;
138 
139           rv = _prop_object_send_ioctl(obj, fd, cmd);
140           if (rv != 0) {
141                     errno = rv;         /* pass up error value in errno */
142                     return rv;
143           } else
144                     return 0;
145 }
__strong_alias(prop_array_send_ioctl,prop_object_send_ioctl)146 __strong_alias(prop_array_send_ioctl, prop_object_send_ioctl)
147 __strong_alias(prop_dictionary_send_ioctl, prop_object_send_ioctl)
148 
149 /*
150  * prop_object_internalize_from_pref --
151  *        Internalize a pref into an object.
152  */
153 static int
154 _prop_object_internalize_from_pref_with_type(const struct plistref *pref,
155                                                        prop_object_t *objp,
156                                                        prop_type_t type)
157 {
158           prop_object_t obj = NULL;
159           char *buf;
160           int error = 0;
161 
162           if (pref->pref_len == 0) {
163                     /*
164                      * This should never happen; we should always get the XML
165                      * for an empty dictionary if it's really empty.
166                      */
167                     error = EIO;
168                     goto out;
169           } else {
170                     buf = pref->pref_plist;
171                     buf[pref->pref_len - 1] = '\0';         /* extra insurance */
172                     obj = prop_object_internalize(buf);
173                     (void) munmap(buf, pref->pref_len);
174                     if (obj != NULL && type != PROP_TYPE_UNKNOWN &&
175                         prop_object_type(obj) != type) {
176                               prop_object_release(obj);
177                               obj = NULL;
178                     }
179                     if (obj == NULL)
180                               error = EIO;
181           }
182 
183  out:
184           if (error == 0)
185                     *objp = obj;
186           return (error);
187 }
188 
189 static bool
_prop_object_internalize_from_pref(const struct plistref * prefp,prop_object_t * objp,prop_type_t type)190 _prop_object_internalize_from_pref(const struct plistref *prefp,
191                                            prop_object_t *objp,
192                                            prop_type_t type)
193 {
194           int rv;
195 
196           rv = _prop_object_internalize_from_pref_with_type(prefp, objp, type);
197           if (rv != 0)
198                     errno = rv;     /* pass up error value in errno */
199           return (rv == 0);
200 }
201 
202 _PROP_EXPORT bool
prop_array_internalize_from_pref(const struct plistref * prefp,prop_array_t * arrayp)203 prop_array_internalize_from_pref(const struct plistref *prefp,
204                                          prop_array_t *arrayp)
205 {
206           return _prop_object_internalize_from_pref(prefp,
207               (prop_object_t *)arrayp, PROP_TYPE_ARRAY);
208 }
209 
210 _PROP_EXPORT bool
prop_dictionary_internalize_from_pref(const struct plistref * prefp,prop_dictionary_t * dictp)211 prop_dictionary_internalize_from_pref(const struct plistref *prefp,
212                                               prop_dictionary_t *dictp)
213 {
214           return _prop_object_internalize_from_pref(prefp,
215               (prop_object_t *)dictp, PROP_TYPE_DICTIONARY);
216 }
217 
218 static int
_prop_object_recv_syscall(const struct plistref * prefp,prop_object_t * objp,prop_type_t type)219 _prop_object_recv_syscall(const struct plistref *prefp,
220                                 prop_object_t *objp, prop_type_t type)
221 {
222           if (_prop_object_internalize_from_pref_with_type(prefp, objp, type)) {
223                     return 0;
224           } else {
225                     return errno;
226           }
227 }
228 
229 _PROP_EXPORT int
prop_object_recv_syscall(const struct plistref * prefp,prop_object_t * objp)230 prop_object_recv_syscall(const struct plistref *prefp,
231                                prop_object_t *objp)
232 {
233           return _prop_object_recv_syscall(prefp, objp, PROP_TYPE_UNKNOWN);
234 }
235 
236 _PROP_EXPORT int
prop_array_recv_syscall(const struct plistref * prefp,prop_array_t * arrayp)237 prop_array_recv_syscall(const struct plistref *prefp,
238                               prop_array_t *arrayp)
239 {
240           return _prop_object_recv_syscall(prefp, (prop_object_t *)arrayp,
241               PROP_TYPE_ARRAY);
242 }
243 
244 _PROP_EXPORT int
prop_dictionary_recv_syscall(const struct plistref * prefp,prop_dictionary_t * dictp)245 prop_dictionary_recv_syscall(const struct plistref *prefp,
246                                    prop_dictionary_t *dictp)
247 {
248           return _prop_object_recv_syscall(prefp, (prop_object_t *)dictp,
249               PROP_TYPE_DICTIONARY);
250 }
251 
252 /*
253  * prop_object_recv_ioctl --
254  *        Receive an array from the kernel using the specified ioctl.
255  */
256 static int
_prop_object_recv_ioctl(int fd,unsigned long cmd,prop_object_t * objp,prop_type_t type)257 _prop_object_recv_ioctl(int fd, unsigned long cmd, prop_object_t *objp,
258     prop_type_t type)
259 {
260           int rv;
261           struct plistref pref;
262 
263           rv = ioctl(fd, cmd, &pref);
264           if (rv == -1)
265                     return errno;
266 
267           rv = _prop_object_internalize_from_pref_with_type(&pref, objp, type);
268           if (rv != 0) {
269                     errno = rv;     /* pass up error value in errno */
270                     return rv;
271           } else
272                     return 0;
273 }
274 
275 _PROP_EXPORT int
prop_object_recv_ioctl(int fd,unsigned long cmd,prop_object_t * objp)276 prop_object_recv_ioctl(int fd, unsigned long cmd, prop_object_t *objp)
277 {
278           return _prop_object_recv_ioctl(fd, cmd, objp, PROP_TYPE_UNKNOWN);
279 }
280 
281 _PROP_EXPORT int
prop_array_recv_ioctl(int fd,unsigned long cmd,prop_array_t * arrayp)282 prop_array_recv_ioctl(int fd, unsigned long cmd, prop_array_t *arrayp)
283 {
284           return _prop_object_recv_ioctl(fd, cmd,
285               (prop_object_t *)arrayp, PROP_TYPE_ARRAY);
286 }
287 
288 _PROP_EXPORT int
prop_dictionary_recv_ioctl(int fd,unsigned long cmd,prop_dictionary_t * dictp)289 prop_dictionary_recv_ioctl(int fd, unsigned long cmd, prop_dictionary_t *dictp)
290 {
291           return _prop_object_recv_ioctl(fd, cmd,
292               (prop_object_t *)dictp, PROP_TYPE_DICTIONARY);
293 }
294 
295 /*
296  * prop_object_sendrecv_ioctl --
297  *        Combination send/receive an object to/from the kernel using
298  *        the specified ioctl.
299  */
300 static int
_prop_object_sendrecv_ioctl(prop_object_t obj,int fd,unsigned long cmd,prop_object_t * objp,prop_type_t type)301 _prop_object_sendrecv_ioctl(prop_object_t obj, int fd,
302                                   unsigned long cmd, prop_object_t *objp,
303                                   prop_type_t type)
304 {
305           struct plistref pref;
306           char *buf;
307           int error;
308 
309           error = _prop_object_externalize_to_pref(obj, &pref, &buf);
310           if (error != 0) {
311                     errno = error;
312                     return error;
313           }
314 
315           if (ioctl(fd, cmd, &pref) == -1)
316                     error = errno;
317           else
318                     error = 0;
319 
320           free(buf);
321 
322           if (error != 0)
323                     return error;
324 
325           error = _prop_object_internalize_from_pref_with_type(&pref, objp, type);
326           if (error != 0) {
327                     errno = error;     /* pass up error value in errno */
328                     return error;
329           } else
330                     return 0;
331 }
332 
333 _PROP_EXPORT int
prop_object_sendrecv_ioctl(prop_object_t obj,int fd,unsigned long cmd,prop_object_t * objp)334 prop_object_sendrecv_ioctl(prop_object_t obj, int fd,
335                                  unsigned long cmd, prop_object_t *objp)
336 {
337           return _prop_object_sendrecv_ioctl(obj, fd, cmd, objp,
338               PROP_TYPE_UNKNOWN);
339 }
340 
341 _PROP_EXPORT int
prop_dictionary_sendrecv_ioctl(prop_dictionary_t dict,int fd,unsigned long cmd,prop_dictionary_t * dictp)342 prop_dictionary_sendrecv_ioctl(prop_dictionary_t dict, int fd,
343                                      unsigned long cmd, prop_dictionary_t *dictp)
344 {
345           return _prop_object_sendrecv_ioctl(dict, fd, cmd,
346               (prop_object_t *)dictp, PROP_TYPE_DICTIONARY);
347 }
348 #endif /* !_KERNEL && !_STANDALONE */
349 
350 #if defined(_KERNEL)
351 #include <sys/param.h>
352 #include <sys/mman.h>
353 #include <sys/errno.h>
354 #include <sys/malloc.h>
355 #include <sys/systm.h>
356 #include <sys/proc.h>
357 #include <sys/resource.h>
358 #include <sys/pool.h>
359 
360 #include <uvm/uvm_extern.h>
361 
362 #include "prop_object_impl.h"
363 
364 /* Arbitrary limit ioctl input to 128KB */
365 unsigned int prop_object_copyin_limit = 128 * 1024;
366 
367 /* initialize proplib for use in the kernel */
368 void
prop_kern_init(void)369 prop_kern_init(void)
370 {
371           __link_set_decl(prop_linkpools, struct prop_pool_init);
372           struct prop_pool_init * const *pi;
373 
374           __link_set_foreach(pi, prop_linkpools)
375                     pool_init((*pi)->pp, (*pi)->size, 0, 0, 0, (*pi)->wchan,
376                         &pool_allocator_nointr, IPL_NONE);
377 }
378 
379 static int
_prop_object_copyin_size(const struct plistref * pref,prop_object_t * objp,size_t lim,prop_type_t type)380 _prop_object_copyin_size(const struct plistref *pref, prop_object_t *objp,
381     size_t lim, prop_type_t type)
382 {
383           prop_object_t obj = NULL;
384           char *buf;
385           int error;
386 
387           if (pref->pref_len >= lim)
388                     return E2BIG;
389 
390           /*
391            * Allocate an extra byte so we can guarantee NUL-termination.
392            */
393           buf = malloc(pref->pref_len + 1, M_TEMP, M_WAITOK);
394           if (buf == NULL)
395                     return (ENOMEM);
396           error = copyin(pref->pref_plist, buf, pref->pref_len);
397           if (error) {
398                     free(buf, M_TEMP);
399                     return (error);
400           }
401           buf[pref->pref_len] = '\0';
402 
403           obj = prop_object_internalize(buf);
404           if (obj != NULL &&
405               type != PROP_TYPE_UNKNOWN && prop_object_type(obj) != type) {
406                     prop_object_release(obj);
407                     obj = NULL;
408           }
409 
410           free(buf, M_TEMP);
411           if (obj == NULL) {
412                     error = EIO;
413           } else {
414                     *objp = obj;
415           }
416           return (error);
417 }
418 
419 int
prop_object_copyin_size(const struct plistref * pref,prop_object_t * objp,size_t lim)420 prop_object_copyin_size(const struct plistref *pref,
421     prop_object_t *objp, size_t lim)
422 {
423           return _prop_object_copyin_size(pref, objp, lim, PROP_TYPE_UNKNOWN);
424 }
425 
426 int
prop_array_copyin_size(const struct plistref * pref,prop_array_t * arrayp,size_t lim)427 prop_array_copyin_size(const struct plistref *pref,
428     prop_array_t *arrayp, size_t lim)
429 {
430           return _prop_object_copyin_size(pref, (prop_object_t *)arrayp, lim,
431               PROP_TYPE_ARRAY);
432 }
433 
434 int
prop_dictionary_copyin_size(const struct plistref * pref,prop_dictionary_t * dictp,size_t lim)435 prop_dictionary_copyin_size(const struct plistref *pref,
436     prop_dictionary_t *dictp, size_t lim)
437 {
438           return _prop_object_copyin_size(pref, (prop_object_t *)dictp, lim,
439               PROP_TYPE_DICTIONARY);
440 }
441 
442 int
prop_object_copyin(const struct plistref * pref,prop_object_t * objp)443 prop_object_copyin(const struct plistref *pref, prop_object_t *objp)
444 {
445           return _prop_object_copyin_size(pref, objp, prop_object_copyin_limit,
446               PROP_TYPE_UNKNOWN);
447 }
448 
449 int
prop_array_copyin(const struct plistref * pref,prop_array_t * arrayp)450 prop_array_copyin(const struct plistref *pref, prop_array_t *arrayp)
451 {
452           return _prop_object_copyin_size(pref, (prop_object_t *)arrayp,
453               prop_object_copyin_limit, PROP_TYPE_ARRAY);
454 }
455 
456 int
prop_dictionary_copyin(const struct plistref * pref,prop_dictionary_t * dictp)457 prop_dictionary_copyin(const struct plistref *pref, prop_dictionary_t *dictp)
458 {
459           return _prop_object_copyin_size(pref, (prop_object_t *)dictp,
460               prop_object_copyin_limit, PROP_TYPE_DICTIONARY);
461 }
462 
463 static int
_prop_object_copyin_ioctl_size(const struct plistref * pref,const u_long cmd,prop_object_t * objp,size_t lim,prop_type_t type)464 _prop_object_copyin_ioctl_size(const struct plistref *pref,
465     const u_long cmd, prop_object_t *objp, size_t lim, prop_type_t type)
466 {
467           if ((cmd & IOC_IN) == 0)
468                     return (EFAULT);
469 
470           return _prop_object_copyin_size(pref, objp, lim, type);
471 }
472 
473 int
prop_object_copyin_ioctl_size(const struct plistref * pref,const u_long cmd,prop_object_t * objp,size_t lim)474 prop_object_copyin_ioctl_size(const struct plistref *pref,
475     const u_long cmd, prop_object_t *objp, size_t lim)
476 {
477           return _prop_object_copyin_ioctl_size(pref, cmd, objp, lim,
478               PROP_TYPE_UNKNOWN);
479 }
480 
481 int
prop_array_copyin_ioctl_size(const struct plistref * pref,const u_long cmd,prop_array_t * arrayp,size_t lim)482 prop_array_copyin_ioctl_size(const struct plistref *pref,
483     const u_long cmd, prop_array_t *arrayp, size_t lim)
484 {
485           return _prop_object_copyin_ioctl_size(pref, cmd,
486               (prop_object_t *)arrayp, lim, PROP_TYPE_ARRAY);
487 }
488 
489 int
prop_dictionary_copyin_ioctl_size(const struct plistref * pref,const u_long cmd,prop_dictionary_t * dictp,size_t lim)490 prop_dictionary_copyin_ioctl_size(const struct plistref *pref,
491     const u_long cmd, prop_dictionary_t *dictp, size_t lim)
492 {
493           return _prop_object_copyin_ioctl_size(pref, cmd,
494               (prop_object_t *)dictp, lim, PROP_TYPE_DICTIONARY);
495 }
496 
497 int
prop_object_copyin_ioctl(const struct plistref * pref,const u_long cmd,prop_object_t * objp)498 prop_object_copyin_ioctl(const struct plistref *pref,
499     const u_long cmd, prop_object_t *objp)
500 {
501           return _prop_object_copyin_ioctl_size(pref, cmd, objp,
502               prop_object_copyin_limit, PROP_TYPE_UNKNOWN);
503 }
504 
505 int
prop_array_copyin_ioctl(const struct plistref * pref,const u_long cmd,prop_array_t * arrayp)506 prop_array_copyin_ioctl(const struct plistref *pref,
507     const u_long cmd, prop_array_t *arrayp)
508 {
509           return _prop_object_copyin_ioctl_size(pref, cmd,
510               (prop_object_t *)arrayp, prop_object_copyin_limit,
511               PROP_TYPE_ARRAY);
512 }
513 
514 int
prop_dictionary_copyin_ioctl(const struct plistref * pref,const u_long cmd,prop_dictionary_t * dictp)515 prop_dictionary_copyin_ioctl(const struct plistref *pref,
516     const u_long cmd, prop_dictionary_t *dictp)
517 {
518           return _prop_object_copyin_ioctl_size(pref, cmd,
519               (prop_object_t *)dictp, prop_object_copyin_limit,
520               PROP_TYPE_DICTIONARY);
521 }
522 
523 int
prop_object_copyout(struct plistref * pref,prop_object_t obj)524 prop_object_copyout(struct plistref *pref, prop_object_t obj)
525 {
526           struct lwp *l = curlwp;                 /* XXX */
527           struct proc *p = l->l_proc;
528           char *buf;
529           void *uaddr;
530           size_t len, rlen;
531           int error = 0;
532 
533           buf = prop_object_externalize(obj);
534           if (buf == NULL)
535                     return (ENOMEM);
536 
537           len = strlen(buf) + 1;
538           rlen = round_page(len);
539           uaddr = NULL;
540           error = uvm_mmap_anon(p, &uaddr, rlen);
541           if (error == 0) {
542                     error = copyout(buf, uaddr, len);
543                     if (error == 0) {
544                               pref->pref_plist = uaddr;
545                               pref->pref_len   = len;
546                     }
547           }
548 
549           free(buf, M_TEMP);
550 
551           return (error);
552 }
__strong_alias(prop_array_copyout,prop_object_copyout)553 __strong_alias(prop_array_copyout, prop_object_copyout)
554 __strong_alias(prop_dictionary_copyout, prop_object_copyout)
555 
556 int
557 prop_object_copyout_ioctl(struct plistref *pref, const u_long cmd,
558                                 prop_object_t obj)
559 {
560           if ((cmd & IOC_OUT) == 0)
561                     return (EFAULT);
562           return prop_object_copyout(pref, obj);
563 }
564 __strong_alias(prop_array_copyout_ioctl, prop_object_copyout_ioctl)
565 __strong_alias(prop_dictionary_copyout_ioctl, prop_object_copyout_ioctl)
566 
567 #endif /* _KERNEL */
568 
569 #endif /* __NetBSD__ */
570