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