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