1 /* $NetBSD: prop_kern.c,v 1.15 2011/01/19 20:34:23 bouyer 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, char **bufp) 46 { 47 char *buf; 48 49 switch (prop_object_type(obj)) { 50 case PROP_TYPE_DICTIONARY: 51 buf = prop_dictionary_externalize(obj); 52 break; 53 case PROP_TYPE_ARRAY: 54 buf = prop_array_externalize(obj); 55 break; 56 default: 57 return (ENOTSUP); 58 } 59 if (buf == NULL) { 60 /* Assume we ran out of memory. */ 61 return (ENOMEM); 62 } 63 pref->pref_plist = buf; 64 pref->pref_len = strlen(buf) + 1; 65 66 *bufp = buf; 67 68 return (0); 69 } 70 71 /* 72 * prop_array_externalize_to_pref -- 73 * Externalize an array into a plistref for sending to the kernel. 74 */ 75 bool 76 prop_array_externalize_to_pref(prop_array_t array, struct plistref *prefp) 77 { 78 char *buf; 79 int rv; 80 81 rv = _prop_object_externalize_to_pref(array, prefp, &buf); 82 if (rv != 0) 83 errno = rv; /* pass up error value in errno */ 84 return (rv == 0); 85 } 86 __strong_reference(prop_array_externalize_to_pref, prop_array_send_syscall) 87 88 /* 89 * prop_dictionary_externalize_to_pref -- 90 * Externalize an dictionary into a plistref for sending to the kernel. 91 */ 92 bool 93 prop_dictionary_externalize_to_pref(prop_dictionary_t dict, struct plistref *prefp) 94 { 95 char *buf; 96 int rv; 97 98 rv = _prop_object_externalize_to_pref(dict, prefp, &buf); 99 if (rv != 0) 100 errno = rv; /* pass up error value in errno */ 101 return (rv == 0); 102 } 103 __strong_reference(prop_dictionary_externalize_to_pref, 104 prop_dictionary_send_syscall) 105 106 static int 107 _prop_object_send_ioctl(prop_object_t obj, int fd, unsigned long cmd) 108 { 109 struct plistref pref; 110 char *buf; 111 int error; 112 113 error = _prop_object_externalize_to_pref(obj, &pref, &buf); 114 if (error) 115 return (error); 116 117 if (ioctl(fd, cmd, &pref) == -1) 118 error = errno; 119 else 120 error = 0; 121 122 free(buf); 123 124 return (error); 125 } 126 127 /* 128 * prop_array_send_ioctl -- 129 * Send an array to the kernel using the specified ioctl. 130 */ 131 int 132 prop_array_send_ioctl(prop_array_t array, int fd, unsigned long cmd) 133 { 134 135 return (_prop_object_send_ioctl(array, fd, cmd)); 136 } 137 138 /* 139 * prop_dictionary_send_ioctl -- 140 * Send a dictionary to the kernel using the specified ioctl. 141 */ 142 int 143 prop_dictionary_send_ioctl(prop_dictionary_t dict, int fd, unsigned long cmd) 144 { 145 146 return (_prop_object_send_ioctl(dict, fd, cmd)); 147 } 148 149 static int 150 _prop_object_internalize_from_pref(const struct plistref *pref, prop_type_t type, 151 prop_object_t *objp) 152 { 153 prop_object_t obj = NULL; 154 char *buf; 155 int error = 0; 156 157 if (pref->pref_len == 0) { 158 /* 159 * This should never happen; we should always get the XML 160 * for an empty dictionary if it's really empty. 161 */ 162 error = EIO; 163 goto out; 164 } else { 165 buf = pref->pref_plist; 166 buf[pref->pref_len - 1] = '\0'; /* extra insurance */ 167 switch (type) { 168 case PROP_TYPE_DICTIONARY: 169 obj = prop_dictionary_internalize(buf); 170 break; 171 case PROP_TYPE_ARRAY: 172 obj = prop_array_internalize(buf); 173 break; 174 default: 175 error = ENOTSUP; 176 } 177 (void) munmap(buf, pref->pref_len); 178 if (obj == NULL && error == 0) 179 error = EIO; 180 } 181 182 out: 183 if (error == 0) 184 *objp = obj; 185 return (error); 186 } 187 188 /* 189 * prop_array_recv_ioctl -- 190 * Receive an array from the kernel using the specified ioctl. 191 */ 192 int 193 prop_array_recv_ioctl(int fd, unsigned long cmd, prop_array_t *arrayp) 194 { 195 struct plistref pref; 196 197 if (ioctl(fd, cmd, &pref) == -1) 198 return (errno); 199 200 return (_prop_object_internalize_from_pref(&pref, PROP_TYPE_ARRAY, 201 (prop_object_t *)arrayp)); 202 } 203 204 /* 205 * prop_dictionary_recv_ioctl -- 206 * Receive a dictionary from the kernel using the specified ioctl. 207 */ 208 int 209 prop_dictionary_recv_ioctl(int fd, unsigned long cmd, prop_dictionary_t *dictp) 210 { 211 struct plistref pref; 212 213 if (ioctl(fd, cmd, &pref) == -1) 214 return (errno); 215 216 return (_prop_object_internalize_from_pref(&pref, PROP_TYPE_DICTIONARY, 217 (prop_object_t *)dictp)); 218 } 219 220 /* 221 * prop_array_recv_syscall -- 222 * Receive an array from the kernel as pref. 223 * Pref's buf is freed on exit 224 */ 225 bool 226 prop_array_recv_syscall(const struct plistref *pref, prop_array_t *arrayp) 227 { 228 return (_prop_object_internalize_from_pref(pref, PROP_TYPE_ARRAY, 229 (prop_object_t *)arrayp)); 230 } 231 232 /* 233 * prop_dictionary_recv_syscall -- 234 * Receive a dictionary from the kernel as pref. 235 * Pref's buf is freed on exit 236 */ 237 bool 238 prop_dictionary_recv_syscall(const struct plistref *pref, 239 prop_dictionary_t *dictp) 240 { 241 return (_prop_object_internalize_from_pref(pref, PROP_TYPE_DICTIONARY, 242 (prop_object_t *)dictp)); 243 } 244 245 /* 246 * prop_dictionary_sendrecv_ioctl -- 247 * Combination send/receive a dictionary to/from the kernel using 248 * the specified ioctl. 249 */ 250 int 251 prop_dictionary_sendrecv_ioctl(prop_dictionary_t dict, int fd, 252 unsigned long cmd, prop_dictionary_t *dictp) 253 { 254 struct plistref pref; 255 char *buf; 256 int error; 257 258 error = _prop_object_externalize_to_pref(dict, &pref, &buf); 259 if (error) 260 return (error); 261 262 if (ioctl(fd, cmd, &pref) == -1) 263 error = errno; 264 else 265 error = 0; 266 267 free(buf); 268 269 if (error) 270 return (error); 271 272 return (_prop_object_internalize_from_pref(&pref, PROP_TYPE_DICTIONARY, 273 (prop_object_t *)dictp)); 274 } 275 #endif /* !_KERNEL && !_STANDALONE */ 276 277 #if defined(_KERNEL) 278 #include <sys/param.h> 279 #include <sys/mman.h> 280 #include <sys/errno.h> 281 #include <sys/malloc.h> 282 #include <sys/systm.h> 283 #include <sys/proc.h> 284 #include <sys/resource.h> 285 #include <sys/objcache.h> 286 #include <sys/ioccom.h> 287 #include <vm/vm.h> 288 #include <vm/vm_extern.h> 289 #include <vm/vm_param.h> 290 291 #include "prop_object_impl.h" 292 293 /* Arbitrary limit ioctl input to 64KB */ 294 unsigned int prop_object_copyin_limit = 65536; 295 296 static int 297 _prop_object_copyin(const struct plistref *pref, const prop_type_t type, 298 prop_object_t *objp) 299 { 300 prop_object_t obj = NULL; 301 char *buf; 302 int error; 303 304 /* 305 * Allocate an extra byte so we can guarantee NUL-termination. 306 * 307 * Allow malloc to fail in case pmap would be exhausted. 308 */ 309 buf = kmalloc(pref->pref_len + 1, M_TEMP, M_WAITOK); 310 if (buf == NULL) 311 return (ENOMEM); 312 error = copyin(pref->pref_plist, buf, pref->pref_len); 313 if (error) { 314 kfree(buf, M_TEMP); 315 return (error); 316 } 317 buf[pref->pref_len] = '\0'; 318 319 switch (type) { 320 case PROP_TYPE_ARRAY: 321 obj = prop_array_internalize(buf); 322 break; 323 case PROP_TYPE_DICTIONARY: 324 obj = prop_dictionary_internalize(buf); 325 break; 326 default: 327 error = ENOTSUP; 328 } 329 330 kfree(buf, M_TEMP); 331 if (obj == NULL) { 332 if (error == 0) 333 error = EIO; 334 } else { 335 *objp = obj; 336 } 337 return (error); 338 } 339 340 341 static int 342 _prop_object_copyin_ioctl(const struct plistref *pref, const prop_type_t type, 343 const u_long cmd, prop_object_t *objp) 344 { 345 if ((cmd & IOC_IN) == 0) 346 return (EFAULT); 347 348 return _prop_object_copyin(pref, type, objp); 349 } 350 351 /* 352 * prop_array_copyin -- 353 * Copy in an array passed as a syscall arg. 354 */ 355 int 356 prop_array_copyin(const struct plistref *pref, prop_array_t *arrayp) 357 { 358 return (_prop_object_copyin(pref, PROP_TYPE_ARRAY, 359 (prop_object_t *)arrayp)); 360 } 361 362 /* 363 * prop_dictionary_copyin -- 364 * Copy in a dictionary passed as a syscall arg. 365 */ 366 int 367 prop_dictionary_copyin(const struct plistref *pref, prop_dictionary_t *dictp) 368 { 369 return (_prop_object_copyin(pref, PROP_TYPE_DICTIONARY, 370 (prop_object_t *)dictp)); 371 } 372 373 374 /* 375 * prop_array_copyin_ioctl -- 376 * Copy in an array send with an ioctl. 377 */ 378 int 379 prop_array_copyin_ioctl(const struct plistref *pref, const u_long cmd, 380 prop_array_t *arrayp) 381 { 382 return (_prop_object_copyin_ioctl(pref, PROP_TYPE_ARRAY, 383 cmd, (prop_object_t *)arrayp)); 384 } 385 386 /* 387 * prop_dictionary_copyin_ioctl -- 388 * Copy in a dictionary sent with an ioctl. 389 */ 390 int 391 prop_dictionary_copyin_ioctl(const struct plistref *pref, const u_long cmd, 392 prop_dictionary_t *dictp) 393 { 394 return (_prop_object_copyin_ioctl(pref, PROP_TYPE_DICTIONARY, 395 cmd, (prop_object_t *)dictp)); 396 } 397 398 static int 399 _prop_object_copyout(struct plistref *pref, prop_object_t obj) 400 { 401 struct proc *p = curproc; 402 char *buf; 403 size_t len, rlen; 404 int error = 0; 405 vm_offset_t uaddr; 406 407 switch (prop_object_type(obj)) { 408 case PROP_TYPE_ARRAY: 409 buf = prop_array_externalize(obj); 410 break; 411 case PROP_TYPE_DICTIONARY: 412 buf = prop_dictionary_externalize(obj); 413 break; 414 default: 415 return (ENOTSUP); 416 } 417 if (buf == NULL) 418 return (ENOMEM); 419 420 len = strlen(buf) + 1; 421 rlen = round_page(len); 422 423 /* 424 * See sys_mmap() in sys/uvm/uvm_mmap.c. 425 * Let's act as if we were calling mmap(0, ...) 426 */ 427 #if 0 428 uaddr = p->p_emul->e_vm_default_addr(p, 429 (vaddr_t)p->p_vmspace->vm_daddr, rlen); 430 #endif 431 uaddr = round_page((vm_offset_t)p->p_vmspace->vm_daddr + maxdsiz); 432 433 error = vm_mmap(&p->p_vmspace->vm_map, 434 &uaddr, rlen, 435 VM_PROT_READ|VM_PROT_WRITE, 436 VM_PROT_READ|VM_PROT_WRITE, 437 MAP_PRIVATE|MAP_ANON, 438 NULL, 0); 439 if (error == 0) { 440 error = copyout(buf, (char *)uaddr, len); 441 if (error == 0) { 442 pref->pref_plist = (char *)uaddr; 443 pref->pref_len = len; 444 } 445 } 446 447 kfree(buf, M_TEMP); 448 449 return (error); 450 } 451 452 /* 453 * prop_array_copyout -- 454 * Copy out an array to a syscall arg. 455 */ 456 int 457 prop_array_copyout(struct plistref *pref, prop_array_t array) 458 { 459 return (_prop_object_copyout(pref, array)); 460 } 461 462 /* 463 * prop_dictionary_copyout -- 464 * Copy out a dictionary to a syscall arg. 465 */ 466 int 467 prop_dictionary_copyout(struct plistref *pref, prop_dictionary_t dict) 468 { 469 return (_prop_object_copyout(pref, dict)); 470 } 471 472 static int 473 _prop_object_copyout_ioctl(struct plistref *pref, const u_long cmd, 474 prop_object_t obj) 475 { 476 if ((cmd & IOC_OUT) == 0) 477 return (EFAULT); 478 return _prop_object_copyout(pref, obj); 479 } 480 481 482 /* 483 * prop_array_copyout_ioctl -- 484 * Copy out an array being received with an ioctl. 485 */ 486 int 487 prop_array_copyout_ioctl(struct plistref *pref, const u_long cmd, 488 prop_array_t array) 489 { 490 return (_prop_object_copyout_ioctl(pref, cmd, array)); 491 } 492 493 /* 494 * prop_dictionary_copyout_ioctl -- 495 * Copy out a dictionary being received with an ioctl. 496 */ 497 int 498 prop_dictionary_copyout_ioctl(struct plistref *pref, const u_long cmd, 499 prop_dictionary_t dict) 500 { 501 return ( 502 _prop_object_copyout_ioctl(pref, cmd, dict)); 503 } 504 #endif /* _KERNEL */ 505