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