xref: /netbsd-src/common/lib/libprop/prop_kern.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
1 /*	$NetBSD: prop_kern.c,v 1.9 2008/04/28 20:22:53 martin Exp $	*/
2 
3 /*-
4  * Copyright (c) 2006 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_pack_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 static int
74 _prop_object_send_ioctl(prop_object_t obj, int fd, unsigned long cmd)
75 {
76 	struct plistref pref;
77 	char *buf;
78 	int error;
79 
80 	error = _prop_object_pack_pref(obj, &pref, &buf);
81 	if (error)
82 		return (error);
83 
84 	if (ioctl(fd, cmd, &pref) == -1)
85 		error = errno;
86 	else
87 		error = 0;
88 
89 	free(buf);
90 
91 	return (error);
92 }
93 
94 /*
95  * prop_array_send_ioctl --
96  *	Send an array to the kernel using the specified ioctl.
97  */
98 int
99 prop_array_send_ioctl(prop_array_t array, int fd, unsigned long cmd)
100 {
101 
102 	return (_prop_object_send_ioctl(array, fd, cmd));
103 }
104 
105 /*
106  * prop_dictionary_send_ioctl --
107  *	Send a dictionary to the kernel using the specified ioctl.
108  */
109 int
110 prop_dictionary_send_ioctl(prop_dictionary_t dict, int fd, unsigned long cmd)
111 {
112 
113 	return (_prop_object_send_ioctl(dict, fd, cmd));
114 }
115 
116 static int
117 _prop_object_unpack_pref(const struct plistref *pref, prop_type_t type,
118 			 prop_object_t *objp)
119 {
120 	prop_object_t obj = NULL;
121 	char *buf;
122 	int error = 0;
123 
124 	if (pref->pref_len == 0) {
125 		/*
126 		 * This should never happen; we should always get the XML
127 		 * for an empty dictionary if it's really empty.
128 		 */
129 		error = EIO;
130 		goto out;
131 	} else {
132 		buf = pref->pref_plist;
133 		buf[pref->pref_len - 1] = '\0';	/* extra insurance */
134 		switch (type) {
135 		case PROP_TYPE_DICTIONARY:
136 			obj = prop_dictionary_internalize(buf);
137 			break;
138 		case PROP_TYPE_ARRAY:
139 			obj = prop_array_internalize(buf);
140 			break;
141 		default:
142 			error = ENOTSUP;
143 		}
144 		(void) munmap(buf, pref->pref_len);
145 		if (obj == NULL && error == 0)
146 			error = EIO;
147 	}
148 
149  out:
150 	if (error == 0)
151 		*objp = obj;
152 	return (error);
153 }
154 
155 /*
156  * prop_array_recv_ioctl --
157  *	Receive an array from the kernel using the specified ioctl.
158  */
159 int
160 prop_array_recv_ioctl(int fd, unsigned long cmd, prop_array_t *arrayp)
161 {
162 	struct plistref pref;
163 
164 	if (ioctl(fd, cmd, &pref) == -1)
165 		return (errno);
166 
167 	return (_prop_object_unpack_pref(&pref, PROP_TYPE_ARRAY,
168 					 (prop_object_t *)arrayp));
169 }
170 
171 /*
172  * prop_dictionary_recv_ioctl --
173  *	Receive a dictionary from the kernel using the specified ioctl.
174  */
175 int
176 prop_dictionary_recv_ioctl(int fd, unsigned long cmd, prop_dictionary_t *dictp)
177 {
178 	struct plistref pref;
179 
180 	if (ioctl(fd, cmd, &pref) == -1)
181 		return (errno);
182 
183 	return (_prop_object_unpack_pref(&pref, PROP_TYPE_DICTIONARY,
184 					 (prop_object_t *)dictp));
185 }
186 
187 /*
188  * prop_dictionary_sendrecv_ioctl --
189  *	Combination send/receive a dictionary to/from the kernel using
190  *	the specified ioctl.
191  */
192 int
193 prop_dictionary_sendrecv_ioctl(prop_dictionary_t dict, int fd,
194 			       unsigned long cmd, prop_dictionary_t *dictp)
195 {
196 	struct plistref pref;
197 	char *buf;
198 	int error;
199 
200 	error = _prop_object_pack_pref(dict, &pref, &buf);
201 	if (error)
202 		return (error);
203 
204 	if (ioctl(fd, cmd, &pref) == -1)
205 		error = errno;
206 	else
207 		error = 0;
208 
209 	free(buf);
210 
211 	if (error)
212 		return (error);
213 
214 	return (_prop_object_unpack_pref(&pref, PROP_TYPE_DICTIONARY,
215 			    (prop_object_t *)dictp));
216 }
217 #endif /* !_KERNEL && !_STANDALONE */
218 
219 #if defined(_KERNEL)
220 #include <sys/param.h>
221 #include <sys/mman.h>
222 #include <sys/errno.h>
223 #include <sys/malloc.h>
224 #include <sys/systm.h>
225 #include <sys/proc.h>
226 #include <sys/resource.h>
227 
228 #include <uvm/uvm.h>
229 
230 /* Arbitrary limit ioctl input to 64KB */
231 unsigned int prop_object_copyin_limit = 65536;
232 
233 static int
234 _prop_object_copyin_ioctl(const struct plistref *pref, const prop_type_t type,
235 			  const u_long cmd, prop_object_t *objp)
236 {
237 	prop_object_t obj = NULL;
238 	char *buf;
239 	int error;
240 
241 	if ((cmd & IOC_IN) == 0)
242 		return (EFAULT);
243 
244 	/*
245 	 * Allocate an extra byte so we can guarantee NUL-termination.
246 	 *
247 	 * Allow malloc to fail in case pmap would be exhausted.
248 	 */
249 	buf = malloc(pref->pref_len + 1, M_TEMP, M_WAITOK | M_CANFAIL);
250 	if (buf == NULL)
251 		return (ENOMEM);
252 	error = copyin(pref->pref_plist, buf, pref->pref_len);
253 	if (error) {
254 		free(buf, M_TEMP);
255 		return (error);
256 	}
257 	buf[pref->pref_len] = '\0';
258 
259 	switch (type) {
260 	case PROP_TYPE_ARRAY:
261 		obj = prop_array_internalize(buf);
262 		break;
263 	case PROP_TYPE_DICTIONARY:
264 		obj = prop_dictionary_internalize(buf);
265 		break;
266 	default:
267 		error = ENOTSUP;
268 	}
269 
270 	free(buf, M_TEMP);
271 	if (obj == NULL) {
272 		if (error == 0)
273 			error = EIO;
274 	} else {
275 		*objp = obj;
276 	}
277 	return (error);
278 }
279 
280 /*
281  * prop_array_copyin_ioctl --
282  *	Copy in an array send with an ioctl.
283  */
284 int
285 prop_array_copyin_ioctl(const struct plistref *pref, const u_long cmd,
286 			prop_array_t *arrayp)
287 {
288 	return (_prop_object_copyin_ioctl(pref, PROP_TYPE_ARRAY,
289 					  cmd, (prop_object_t *)arrayp));
290 }
291 
292 /*
293  * prop_dictionary_copyin_ioctl --
294  *	Copy in a dictionary sent with an ioctl.
295  */
296 int
297 prop_dictionary_copyin_ioctl(const struct plistref *pref, const u_long cmd,
298 			     prop_dictionary_t *dictp)
299 {
300 	return (_prop_object_copyin_ioctl(pref, PROP_TYPE_DICTIONARY,
301 					  cmd, (prop_object_t *)dictp));
302 }
303 
304 static int
305 _prop_object_copyout_ioctl(struct plistref *pref, const u_long cmd,
306 			   prop_object_t obj)
307 {
308 	struct lwp *l = curlwp;		/* XXX */
309 	struct proc *p = l->l_proc;
310 	char *buf;
311 	size_t len, rlen;
312 	int error = 0;
313 	vaddr_t uaddr;
314 
315 	if ((cmd & IOC_OUT) == 0)
316 		return (EFAULT);
317 
318 	switch (prop_object_type(obj)) {
319 	case PROP_TYPE_ARRAY:
320 		buf = prop_array_externalize(obj);
321 		break;
322 	case PROP_TYPE_DICTIONARY:
323 		buf = prop_dictionary_externalize(obj);
324 		break;
325 	default:
326 		return (ENOTSUP);
327 	}
328 	if (buf == NULL)
329 		return (ENOMEM);
330 
331 	len = strlen(buf) + 1;
332 	rlen = round_page(len);
333 
334 	/*
335 	 * See sys_mmap() in sys/uvm/uvm_mmap.c.
336 	 * Let's act as if we were calling mmap(0, ...)
337 	 */
338 	uaddr = p->p_emul->e_vm_default_addr(p,
339 	    (vaddr_t)p->p_vmspace->vm_daddr, rlen);
340 
341 	error = uvm_mmap(&p->p_vmspace->vm_map,
342 			 &uaddr, rlen,
343 			 VM_PROT_READ|VM_PROT_WRITE,
344 			 VM_PROT_READ|VM_PROT_WRITE,
345 			 MAP_PRIVATE|MAP_ANON,
346 			 NULL, 0,
347 			 p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
348 
349 	if (error == 0) {
350 		error = copyout(buf, (char *)uaddr, len);
351 		if (error == 0) {
352 			pref->pref_plist = (char *)uaddr;
353 			pref->pref_len   = len;
354 		}
355 	}
356 
357 	free(buf, M_TEMP);
358 
359 	return (error);
360 }
361 
362 /*
363  * prop_array_copyout_ioctl --
364  *	Copy out an array being received with an ioctl.
365  */
366 int
367 prop_array_copyout_ioctl(struct plistref *pref, const u_long cmd,
368 			 prop_array_t array)
369 {
370 	return (_prop_object_copyout_ioctl(pref, cmd, array));
371 }
372 
373 /*
374  * prop_dictionary_copyout_ioctl --
375  *	Copy out a dictionary being received with an ioctl.
376  */
377 int
378 prop_dictionary_copyout_ioctl(struct plistref *pref, const u_long cmd,
379 			      prop_dictionary_t dict)
380 {
381 	return (_prop_object_copyout_ioctl(pref, cmd, dict));
382 }
383 #endif /* _KERNEL */
384 
385 #endif /* __NetBSD__ */
386