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