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