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