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