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