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