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