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