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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 554 prop_dictionary_copyout(struct plistref *pref, prop_dictionary_t dict) 555 { 556 return (_prop_object_copyout(pref, dict)); 557 } 558 559 static int 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 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 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