1 /* $NetBSD: prop_kern.c,v 1.8 2007/08/16 21:44:07 joerg 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #if defined(__NetBSD__) 40 41 #include <sys/types.h> 42 #include <sys/ioctl.h> 43 44 #include <prop/proplib.h> 45 46 #if !defined(_KERNEL) && !defined(_STANDALONE) 47 #include <sys/mman.h> 48 #include <errno.h> 49 #include <string.h> 50 #include <stdlib.h> 51 #include <stdio.h> 52 53 static int 54 _prop_object_pack_pref(prop_object_t obj, struct plistref *pref, char **bufp) 55 { 56 char *buf; 57 58 switch (prop_object_type(obj)) { 59 case PROP_TYPE_DICTIONARY: 60 buf = prop_dictionary_externalize(obj); 61 break; 62 case PROP_TYPE_ARRAY: 63 buf = prop_array_externalize(obj); 64 break; 65 default: 66 return (ENOTSUP); 67 } 68 if (buf == NULL) { 69 /* Assume we ran out of memory. */ 70 return (ENOMEM); 71 } 72 pref->pref_plist = buf; 73 pref->pref_len = strlen(buf) + 1; 74 75 *bufp = buf; 76 77 return (0); 78 } 79 80 static int 81 _prop_object_send_ioctl(prop_object_t obj, int fd, unsigned long cmd) 82 { 83 struct plistref pref; 84 char *buf; 85 int error; 86 87 error = _prop_object_pack_pref(obj, &pref, &buf); 88 if (error) 89 return (error); 90 91 if (ioctl(fd, cmd, &pref) == -1) 92 error = errno; 93 else 94 error = 0; 95 96 free(buf); 97 98 return (error); 99 } 100 101 /* 102 * prop_array_send_ioctl -- 103 * Send an array to the kernel using the specified ioctl. 104 */ 105 int 106 prop_array_send_ioctl(prop_array_t array, int fd, unsigned long cmd) 107 { 108 109 return (_prop_object_send_ioctl(array, fd, cmd)); 110 } 111 112 /* 113 * prop_dictionary_send_ioctl -- 114 * Send a dictionary to the kernel using the specified ioctl. 115 */ 116 int 117 prop_dictionary_send_ioctl(prop_dictionary_t dict, int fd, unsigned long cmd) 118 { 119 120 return (_prop_object_send_ioctl(dict, fd, cmd)); 121 } 122 123 static int 124 _prop_object_unpack_pref(const struct plistref *pref, prop_type_t type, 125 prop_object_t *objp) 126 { 127 prop_object_t obj = NULL; 128 char *buf; 129 int error = 0; 130 131 if (pref->pref_len == 0) { 132 /* 133 * This should never happen; we should always get the XML 134 * for an empty dictionary if it's really empty. 135 */ 136 error = EIO; 137 goto out; 138 } else { 139 buf = pref->pref_plist; 140 buf[pref->pref_len - 1] = '\0'; /* extra insurance */ 141 switch (type) { 142 case PROP_TYPE_DICTIONARY: 143 obj = prop_dictionary_internalize(buf); 144 break; 145 case PROP_TYPE_ARRAY: 146 obj = prop_array_internalize(buf); 147 break; 148 default: 149 error = ENOTSUP; 150 } 151 (void) munmap(buf, pref->pref_len); 152 if (obj == NULL && error == 0) 153 error = EIO; 154 } 155 156 out: 157 if (error == 0) 158 *objp = obj; 159 return (error); 160 } 161 162 /* 163 * prop_array_recv_ioctl -- 164 * Receive an array from the kernel using the specified ioctl. 165 */ 166 int 167 prop_array_recv_ioctl(int fd, unsigned long cmd, prop_array_t *arrayp) 168 { 169 struct plistref pref; 170 171 if (ioctl(fd, cmd, &pref) == -1) 172 return (errno); 173 174 return (_prop_object_unpack_pref(&pref, PROP_TYPE_ARRAY, 175 (prop_object_t *)arrayp)); 176 } 177 178 /* 179 * prop_dictionary_recv_ioctl -- 180 * Receive a dictionary from the kernel using the specified ioctl. 181 */ 182 int 183 prop_dictionary_recv_ioctl(int fd, unsigned long cmd, prop_dictionary_t *dictp) 184 { 185 struct plistref pref; 186 187 if (ioctl(fd, cmd, &pref) == -1) 188 return (errno); 189 190 return (_prop_object_unpack_pref(&pref, PROP_TYPE_DICTIONARY, 191 (prop_object_t *)dictp)); 192 } 193 194 /* 195 * prop_dictionary_sendrecv_ioctl -- 196 * Combination send/receive a dictionary to/from the kernel using 197 * the specified ioctl. 198 */ 199 int 200 prop_dictionary_sendrecv_ioctl(prop_dictionary_t dict, int fd, 201 unsigned long cmd, prop_dictionary_t *dictp) 202 { 203 struct plistref pref; 204 char *buf; 205 int error; 206 207 error = _prop_object_pack_pref(dict, &pref, &buf); 208 if (error) 209 return (error); 210 211 if (ioctl(fd, cmd, &pref) == -1) 212 error = errno; 213 else 214 error = 0; 215 216 free(buf); 217 218 if (error) 219 return (error); 220 221 return (_prop_object_unpack_pref(&pref, PROP_TYPE_DICTIONARY, 222 (prop_object_t *)dictp)); 223 } 224 #endif /* !_KERNEL && !_STANDALONE */ 225 226 #if defined(_KERNEL) 227 #include <sys/param.h> 228 #include <sys/mman.h> 229 #include <sys/errno.h> 230 #include <sys/malloc.h> 231 #include <sys/systm.h> 232 #include <sys/proc.h> 233 #include <sys/resource.h> 234 235 #include <uvm/uvm.h> 236 237 /* Arbitrary limit ioctl input to 64KB */ 238 unsigned int prop_object_copyin_limit = 65536; 239 240 static int 241 _prop_object_copyin_ioctl(const struct plistref *pref, const prop_type_t type, 242 const u_long cmd, prop_object_t *objp) 243 { 244 prop_object_t obj = NULL; 245 char *buf; 246 int error; 247 248 if ((cmd & IOC_IN) == 0) 249 return (EFAULT); 250 251 /* 252 * Allocate an extra byte so we can guarantee NUL-termination. 253 * 254 * Allow malloc to fail in case pmap would be exhausted. 255 */ 256 buf = malloc(pref->pref_len + 1, M_TEMP, M_WAITOK | M_CANFAIL); 257 if (buf == NULL) 258 return (ENOMEM); 259 error = copyin(pref->pref_plist, buf, pref->pref_len); 260 if (error) { 261 free(buf, M_TEMP); 262 return (error); 263 } 264 buf[pref->pref_len] = '\0'; 265 266 switch (type) { 267 case PROP_TYPE_ARRAY: 268 obj = prop_array_internalize(buf); 269 break; 270 case PROP_TYPE_DICTIONARY: 271 obj = prop_dictionary_internalize(buf); 272 break; 273 default: 274 error = ENOTSUP; 275 } 276 277 free(buf, M_TEMP); 278 if (obj == NULL) { 279 if (error == 0) 280 error = EIO; 281 } else { 282 *objp = obj; 283 } 284 return (error); 285 } 286 287 /* 288 * prop_array_copyin_ioctl -- 289 * Copy in an array send with an ioctl. 290 */ 291 int 292 prop_array_copyin_ioctl(const struct plistref *pref, const u_long cmd, 293 prop_array_t *arrayp) 294 { 295 return (_prop_object_copyin_ioctl(pref, PROP_TYPE_ARRAY, 296 cmd, (prop_object_t *)arrayp)); 297 } 298 299 /* 300 * prop_dictionary_copyin_ioctl -- 301 * Copy in a dictionary sent with an ioctl. 302 */ 303 int 304 prop_dictionary_copyin_ioctl(const struct plistref *pref, const u_long cmd, 305 prop_dictionary_t *dictp) 306 { 307 return (_prop_object_copyin_ioctl(pref, PROP_TYPE_DICTIONARY, 308 cmd, (prop_object_t *)dictp)); 309 } 310 311 static int 312 _prop_object_copyout_ioctl(struct plistref *pref, const u_long cmd, 313 prop_object_t obj) 314 { 315 struct lwp *l = curlwp; /* XXX */ 316 struct proc *p = l->l_proc; 317 char *buf; 318 size_t len, rlen; 319 int error = 0; 320 vaddr_t uaddr; 321 322 if ((cmd & IOC_OUT) == 0) 323 return (EFAULT); 324 325 switch (prop_object_type(obj)) { 326 case PROP_TYPE_ARRAY: 327 buf = prop_array_externalize(obj); 328 break; 329 case PROP_TYPE_DICTIONARY: 330 buf = prop_dictionary_externalize(obj); 331 break; 332 default: 333 return (ENOTSUP); 334 } 335 if (buf == NULL) 336 return (ENOMEM); 337 338 len = strlen(buf) + 1; 339 rlen = round_page(len); 340 341 /* 342 * See sys_mmap() in sys/uvm/uvm_mmap.c. 343 * Let's act as if we were calling mmap(0, ...) 344 */ 345 uaddr = p->p_emul->e_vm_default_addr(p, 346 (vaddr_t)p->p_vmspace->vm_daddr, rlen); 347 348 error = uvm_mmap(&p->p_vmspace->vm_map, 349 &uaddr, rlen, 350 VM_PROT_READ|VM_PROT_WRITE, 351 VM_PROT_READ|VM_PROT_WRITE, 352 MAP_PRIVATE|MAP_ANON, 353 NULL, 0, 354 p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur); 355 356 if (error == 0) { 357 error = copyout(buf, (char *)uaddr, len); 358 if (error == 0) { 359 pref->pref_plist = (char *)uaddr; 360 pref->pref_len = len; 361 } 362 } 363 364 free(buf, M_TEMP); 365 366 return (error); 367 } 368 369 /* 370 * prop_array_copyout_ioctl -- 371 * Copy out an array being received with an ioctl. 372 */ 373 int 374 prop_array_copyout_ioctl(struct plistref *pref, const u_long cmd, 375 prop_array_t array) 376 { 377 return (_prop_object_copyout_ioctl(pref, cmd, array)); 378 } 379 380 /* 381 * prop_dictionary_copyout_ioctl -- 382 * Copy out a dictionary being received with an ioctl. 383 */ 384 int 385 prop_dictionary_copyout_ioctl(struct plistref *pref, const u_long cmd, 386 prop_dictionary_t dict) 387 { 388 return (_prop_object_copyout_ioctl(pref, cmd, dict)); 389 } 390 #endif /* _KERNEL */ 391 392 #endif /* __NetBSD__ */ 393