1 /* $NetBSD: prop_kern.c,v 1.9 2008/04/28 20:22:53 martin Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 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_pack_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 static int 74 _prop_object_send_ioctl(prop_object_t obj, int fd, unsigned long cmd) 75 { 76 struct plistref pref; 77 char *buf; 78 int error; 79 80 error = _prop_object_pack_pref(obj, &pref, &buf); 81 if (error) 82 return (error); 83 84 if (ioctl(fd, cmd, &pref) == -1) 85 error = errno; 86 else 87 error = 0; 88 89 free(buf); 90 91 return (error); 92 } 93 94 /* 95 * prop_array_send_ioctl -- 96 * Send an array to the kernel using the specified ioctl. 97 */ 98 int 99 prop_array_send_ioctl(prop_array_t array, int fd, unsigned long cmd) 100 { 101 102 return (_prop_object_send_ioctl(array, fd, cmd)); 103 } 104 105 /* 106 * prop_dictionary_send_ioctl -- 107 * Send a dictionary to the kernel using the specified ioctl. 108 */ 109 int 110 prop_dictionary_send_ioctl(prop_dictionary_t dict, int fd, unsigned long cmd) 111 { 112 113 return (_prop_object_send_ioctl(dict, fd, cmd)); 114 } 115 116 static int 117 _prop_object_unpack_pref(const struct plistref *pref, prop_type_t type, 118 prop_object_t *objp) 119 { 120 prop_object_t obj = NULL; 121 char *buf; 122 int error = 0; 123 124 if (pref->pref_len == 0) { 125 /* 126 * This should never happen; we should always get the XML 127 * for an empty dictionary if it's really empty. 128 */ 129 error = EIO; 130 goto out; 131 } else { 132 buf = pref->pref_plist; 133 buf[pref->pref_len - 1] = '\0'; /* extra insurance */ 134 switch (type) { 135 case PROP_TYPE_DICTIONARY: 136 obj = prop_dictionary_internalize(buf); 137 break; 138 case PROP_TYPE_ARRAY: 139 obj = prop_array_internalize(buf); 140 break; 141 default: 142 error = ENOTSUP; 143 } 144 (void) munmap(buf, pref->pref_len); 145 if (obj == NULL && error == 0) 146 error = EIO; 147 } 148 149 out: 150 if (error == 0) 151 *objp = obj; 152 return (error); 153 } 154 155 /* 156 * prop_array_recv_ioctl -- 157 * Receive an array from the kernel using the specified ioctl. 158 */ 159 int 160 prop_array_recv_ioctl(int fd, unsigned long cmd, prop_array_t *arrayp) 161 { 162 struct plistref pref; 163 164 if (ioctl(fd, cmd, &pref) == -1) 165 return (errno); 166 167 return (_prop_object_unpack_pref(&pref, PROP_TYPE_ARRAY, 168 (prop_object_t *)arrayp)); 169 } 170 171 /* 172 * prop_dictionary_recv_ioctl -- 173 * Receive a dictionary from the kernel using the specified ioctl. 174 */ 175 int 176 prop_dictionary_recv_ioctl(int fd, unsigned long cmd, prop_dictionary_t *dictp) 177 { 178 struct plistref pref; 179 180 if (ioctl(fd, cmd, &pref) == -1) 181 return (errno); 182 183 return (_prop_object_unpack_pref(&pref, PROP_TYPE_DICTIONARY, 184 (prop_object_t *)dictp)); 185 } 186 187 /* 188 * prop_dictionary_sendrecv_ioctl -- 189 * Combination send/receive a dictionary to/from the kernel using 190 * the specified ioctl. 191 */ 192 int 193 prop_dictionary_sendrecv_ioctl(prop_dictionary_t dict, int fd, 194 unsigned long cmd, prop_dictionary_t *dictp) 195 { 196 struct plistref pref; 197 char *buf; 198 int error; 199 200 error = _prop_object_pack_pref(dict, &pref, &buf); 201 if (error) 202 return (error); 203 204 if (ioctl(fd, cmd, &pref) == -1) 205 error = errno; 206 else 207 error = 0; 208 209 free(buf); 210 211 if (error) 212 return (error); 213 214 return (_prop_object_unpack_pref(&pref, PROP_TYPE_DICTIONARY, 215 (prop_object_t *)dictp)); 216 } 217 #endif /* !_KERNEL && !_STANDALONE */ 218 219 #if defined(_KERNEL) 220 #include <sys/param.h> 221 #include <sys/mman.h> 222 #include <sys/errno.h> 223 #include <sys/malloc.h> 224 #include <sys/systm.h> 225 #include <sys/proc.h> 226 #include <sys/resource.h> 227 228 #include <uvm/uvm.h> 229 230 /* Arbitrary limit ioctl input to 64KB */ 231 unsigned int prop_object_copyin_limit = 65536; 232 233 static int 234 _prop_object_copyin_ioctl(const struct plistref *pref, const prop_type_t type, 235 const u_long cmd, prop_object_t *objp) 236 { 237 prop_object_t obj = NULL; 238 char *buf; 239 int error; 240 241 if ((cmd & IOC_IN) == 0) 242 return (EFAULT); 243 244 /* 245 * Allocate an extra byte so we can guarantee NUL-termination. 246 * 247 * Allow malloc to fail in case pmap would be exhausted. 248 */ 249 buf = malloc(pref->pref_len + 1, M_TEMP, M_WAITOK | M_CANFAIL); 250 if (buf == NULL) 251 return (ENOMEM); 252 error = copyin(pref->pref_plist, buf, pref->pref_len); 253 if (error) { 254 free(buf, M_TEMP); 255 return (error); 256 } 257 buf[pref->pref_len] = '\0'; 258 259 switch (type) { 260 case PROP_TYPE_ARRAY: 261 obj = prop_array_internalize(buf); 262 break; 263 case PROP_TYPE_DICTIONARY: 264 obj = prop_dictionary_internalize(buf); 265 break; 266 default: 267 error = ENOTSUP; 268 } 269 270 free(buf, M_TEMP); 271 if (obj == NULL) { 272 if (error == 0) 273 error = EIO; 274 } else { 275 *objp = obj; 276 } 277 return (error); 278 } 279 280 /* 281 * prop_array_copyin_ioctl -- 282 * Copy in an array send with an ioctl. 283 */ 284 int 285 prop_array_copyin_ioctl(const struct plistref *pref, const u_long cmd, 286 prop_array_t *arrayp) 287 { 288 return (_prop_object_copyin_ioctl(pref, PROP_TYPE_ARRAY, 289 cmd, (prop_object_t *)arrayp)); 290 } 291 292 /* 293 * prop_dictionary_copyin_ioctl -- 294 * Copy in a dictionary sent with an ioctl. 295 */ 296 int 297 prop_dictionary_copyin_ioctl(const struct plistref *pref, const u_long cmd, 298 prop_dictionary_t *dictp) 299 { 300 return (_prop_object_copyin_ioctl(pref, PROP_TYPE_DICTIONARY, 301 cmd, (prop_object_t *)dictp)); 302 } 303 304 static int 305 _prop_object_copyout_ioctl(struct plistref *pref, const u_long cmd, 306 prop_object_t obj) 307 { 308 struct lwp *l = curlwp; /* XXX */ 309 struct proc *p = l->l_proc; 310 char *buf; 311 size_t len, rlen; 312 int error = 0; 313 vaddr_t uaddr; 314 315 if ((cmd & IOC_OUT) == 0) 316 return (EFAULT); 317 318 switch (prop_object_type(obj)) { 319 case PROP_TYPE_ARRAY: 320 buf = prop_array_externalize(obj); 321 break; 322 case PROP_TYPE_DICTIONARY: 323 buf = prop_dictionary_externalize(obj); 324 break; 325 default: 326 return (ENOTSUP); 327 } 328 if (buf == NULL) 329 return (ENOMEM); 330 331 len = strlen(buf) + 1; 332 rlen = round_page(len); 333 334 /* 335 * See sys_mmap() in sys/uvm/uvm_mmap.c. 336 * Let's act as if we were calling mmap(0, ...) 337 */ 338 uaddr = p->p_emul->e_vm_default_addr(p, 339 (vaddr_t)p->p_vmspace->vm_daddr, rlen); 340 341 error = uvm_mmap(&p->p_vmspace->vm_map, 342 &uaddr, rlen, 343 VM_PROT_READ|VM_PROT_WRITE, 344 VM_PROT_READ|VM_PROT_WRITE, 345 MAP_PRIVATE|MAP_ANON, 346 NULL, 0, 347 p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur); 348 349 if (error == 0) { 350 error = copyout(buf, (char *)uaddr, len); 351 if (error == 0) { 352 pref->pref_plist = (char *)uaddr; 353 pref->pref_len = len; 354 } 355 } 356 357 free(buf, M_TEMP); 358 359 return (error); 360 } 361 362 /* 363 * prop_array_copyout_ioctl -- 364 * Copy out an array being received with an ioctl. 365 */ 366 int 367 prop_array_copyout_ioctl(struct plistref *pref, const u_long cmd, 368 prop_array_t array) 369 { 370 return (_prop_object_copyout_ioctl(pref, cmd, array)); 371 } 372 373 /* 374 * prop_dictionary_copyout_ioctl -- 375 * Copy out a dictionary being received with an ioctl. 376 */ 377 int 378 prop_dictionary_copyout_ioctl(struct plistref *pref, const u_long cmd, 379 prop_dictionary_t dict) 380 { 381 return (_prop_object_copyout_ioctl(pref, cmd, dict)); 382 } 383 #endif /* _KERNEL */ 384 385 #endif /* __NetBSD__ */ 386