xref: /netbsd-src/common/lib/libprop/prop_kern.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: prop_kern.c,v 1.8 2007/08/16 21:44:07 joerg 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  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the NetBSD
21  *      Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #if defined(__NetBSD__)
40 
41 #include <sys/types.h>
42 #include <sys/ioctl.h>
43 
44 #include <prop/proplib.h>
45 
46 #if !defined(_KERNEL) && !defined(_STANDALONE)
47 #include <sys/mman.h>
48 #include <errno.h>
49 #include <string.h>
50 #include <stdlib.h>
51 #include <stdio.h>
52 
53 static int
54 _prop_object_pack_pref(prop_object_t obj, struct plistref *pref, char **bufp)
55 {
56 	char *buf;
57 
58 	switch (prop_object_type(obj)) {
59 	case PROP_TYPE_DICTIONARY:
60 		buf = prop_dictionary_externalize(obj);
61 		break;
62 	case PROP_TYPE_ARRAY:
63 		buf = prop_array_externalize(obj);
64 		break;
65 	default:
66 		return (ENOTSUP);
67 	}
68 	if (buf == NULL) {
69 		/* Assume we ran out of memory. */
70 		return (ENOMEM);
71 	}
72 	pref->pref_plist = buf;
73 	pref->pref_len = strlen(buf) + 1;
74 
75 	*bufp = buf;
76 
77 	return (0);
78 }
79 
80 static int
81 _prop_object_send_ioctl(prop_object_t obj, int fd, unsigned long cmd)
82 {
83 	struct plistref pref;
84 	char *buf;
85 	int error;
86 
87 	error = _prop_object_pack_pref(obj, &pref, &buf);
88 	if (error)
89 		return (error);
90 
91 	if (ioctl(fd, cmd, &pref) == -1)
92 		error = errno;
93 	else
94 		error = 0;
95 
96 	free(buf);
97 
98 	return (error);
99 }
100 
101 /*
102  * prop_array_send_ioctl --
103  *	Send an array to the kernel using the specified ioctl.
104  */
105 int
106 prop_array_send_ioctl(prop_array_t array, int fd, unsigned long cmd)
107 {
108 
109 	return (_prop_object_send_ioctl(array, fd, cmd));
110 }
111 
112 /*
113  * prop_dictionary_send_ioctl --
114  *	Send a dictionary to the kernel using the specified ioctl.
115  */
116 int
117 prop_dictionary_send_ioctl(prop_dictionary_t dict, int fd, unsigned long cmd)
118 {
119 
120 	return (_prop_object_send_ioctl(dict, fd, cmd));
121 }
122 
123 static int
124 _prop_object_unpack_pref(const struct plistref *pref, prop_type_t type,
125 			 prop_object_t *objp)
126 {
127 	prop_object_t obj = NULL;
128 	char *buf;
129 	int error = 0;
130 
131 	if (pref->pref_len == 0) {
132 		/*
133 		 * This should never happen; we should always get the XML
134 		 * for an empty dictionary if it's really empty.
135 		 */
136 		error = EIO;
137 		goto out;
138 	} else {
139 		buf = pref->pref_plist;
140 		buf[pref->pref_len - 1] = '\0';	/* extra insurance */
141 		switch (type) {
142 		case PROP_TYPE_DICTIONARY:
143 			obj = prop_dictionary_internalize(buf);
144 			break;
145 		case PROP_TYPE_ARRAY:
146 			obj = prop_array_internalize(buf);
147 			break;
148 		default:
149 			error = ENOTSUP;
150 		}
151 		(void) munmap(buf, pref->pref_len);
152 		if (obj == NULL && error == 0)
153 			error = EIO;
154 	}
155 
156  out:
157 	if (error == 0)
158 		*objp = obj;
159 	return (error);
160 }
161 
162 /*
163  * prop_array_recv_ioctl --
164  *	Receive an array from the kernel using the specified ioctl.
165  */
166 int
167 prop_array_recv_ioctl(int fd, unsigned long cmd, prop_array_t *arrayp)
168 {
169 	struct plistref pref;
170 
171 	if (ioctl(fd, cmd, &pref) == -1)
172 		return (errno);
173 
174 	return (_prop_object_unpack_pref(&pref, PROP_TYPE_ARRAY,
175 					 (prop_object_t *)arrayp));
176 }
177 
178 /*
179  * prop_dictionary_recv_ioctl --
180  *	Receive a dictionary from the kernel using the specified ioctl.
181  */
182 int
183 prop_dictionary_recv_ioctl(int fd, unsigned long cmd, prop_dictionary_t *dictp)
184 {
185 	struct plistref pref;
186 
187 	if (ioctl(fd, cmd, &pref) == -1)
188 		return (errno);
189 
190 	return (_prop_object_unpack_pref(&pref, PROP_TYPE_DICTIONARY,
191 					 (prop_object_t *)dictp));
192 }
193 
194 /*
195  * prop_dictionary_sendrecv_ioctl --
196  *	Combination send/receive a dictionary to/from the kernel using
197  *	the specified ioctl.
198  */
199 int
200 prop_dictionary_sendrecv_ioctl(prop_dictionary_t dict, int fd,
201 			       unsigned long cmd, prop_dictionary_t *dictp)
202 {
203 	struct plistref pref;
204 	char *buf;
205 	int error;
206 
207 	error = _prop_object_pack_pref(dict, &pref, &buf);
208 	if (error)
209 		return (error);
210 
211 	if (ioctl(fd, cmd, &pref) == -1)
212 		error = errno;
213 	else
214 		error = 0;
215 
216 	free(buf);
217 
218 	if (error)
219 		return (error);
220 
221 	return (_prop_object_unpack_pref(&pref, PROP_TYPE_DICTIONARY,
222 			    (prop_object_t *)dictp));
223 }
224 #endif /* !_KERNEL && !_STANDALONE */
225 
226 #if defined(_KERNEL)
227 #include <sys/param.h>
228 #include <sys/mman.h>
229 #include <sys/errno.h>
230 #include <sys/malloc.h>
231 #include <sys/systm.h>
232 #include <sys/proc.h>
233 #include <sys/resource.h>
234 
235 #include <uvm/uvm.h>
236 
237 /* Arbitrary limit ioctl input to 64KB */
238 unsigned int prop_object_copyin_limit = 65536;
239 
240 static int
241 _prop_object_copyin_ioctl(const struct plistref *pref, const prop_type_t type,
242 			  const u_long cmd, prop_object_t *objp)
243 {
244 	prop_object_t obj = NULL;
245 	char *buf;
246 	int error;
247 
248 	if ((cmd & IOC_IN) == 0)
249 		return (EFAULT);
250 
251 	/*
252 	 * Allocate an extra byte so we can guarantee NUL-termination.
253 	 *
254 	 * Allow malloc to fail in case pmap would be exhausted.
255 	 */
256 	buf = malloc(pref->pref_len + 1, M_TEMP, M_WAITOK | M_CANFAIL);
257 	if (buf == NULL)
258 		return (ENOMEM);
259 	error = copyin(pref->pref_plist, buf, pref->pref_len);
260 	if (error) {
261 		free(buf, M_TEMP);
262 		return (error);
263 	}
264 	buf[pref->pref_len] = '\0';
265 
266 	switch (type) {
267 	case PROP_TYPE_ARRAY:
268 		obj = prop_array_internalize(buf);
269 		break;
270 	case PROP_TYPE_DICTIONARY:
271 		obj = prop_dictionary_internalize(buf);
272 		break;
273 	default:
274 		error = ENOTSUP;
275 	}
276 
277 	free(buf, M_TEMP);
278 	if (obj == NULL) {
279 		if (error == 0)
280 			error = EIO;
281 	} else {
282 		*objp = obj;
283 	}
284 	return (error);
285 }
286 
287 /*
288  * prop_array_copyin_ioctl --
289  *	Copy in an array send with an ioctl.
290  */
291 int
292 prop_array_copyin_ioctl(const struct plistref *pref, const u_long cmd,
293 			prop_array_t *arrayp)
294 {
295 	return (_prop_object_copyin_ioctl(pref, PROP_TYPE_ARRAY,
296 					  cmd, (prop_object_t *)arrayp));
297 }
298 
299 /*
300  * prop_dictionary_copyin_ioctl --
301  *	Copy in a dictionary sent with an ioctl.
302  */
303 int
304 prop_dictionary_copyin_ioctl(const struct plistref *pref, const u_long cmd,
305 			     prop_dictionary_t *dictp)
306 {
307 	return (_prop_object_copyin_ioctl(pref, PROP_TYPE_DICTIONARY,
308 					  cmd, (prop_object_t *)dictp));
309 }
310 
311 static int
312 _prop_object_copyout_ioctl(struct plistref *pref, const u_long cmd,
313 			   prop_object_t obj)
314 {
315 	struct lwp *l = curlwp;		/* XXX */
316 	struct proc *p = l->l_proc;
317 	char *buf;
318 	size_t len, rlen;
319 	int error = 0;
320 	vaddr_t uaddr;
321 
322 	if ((cmd & IOC_OUT) == 0)
323 		return (EFAULT);
324 
325 	switch (prop_object_type(obj)) {
326 	case PROP_TYPE_ARRAY:
327 		buf = prop_array_externalize(obj);
328 		break;
329 	case PROP_TYPE_DICTIONARY:
330 		buf = prop_dictionary_externalize(obj);
331 		break;
332 	default:
333 		return (ENOTSUP);
334 	}
335 	if (buf == NULL)
336 		return (ENOMEM);
337 
338 	len = strlen(buf) + 1;
339 	rlen = round_page(len);
340 
341 	/*
342 	 * See sys_mmap() in sys/uvm/uvm_mmap.c.
343 	 * Let's act as if we were calling mmap(0, ...)
344 	 */
345 	uaddr = p->p_emul->e_vm_default_addr(p,
346 	    (vaddr_t)p->p_vmspace->vm_daddr, rlen);
347 
348 	error = uvm_mmap(&p->p_vmspace->vm_map,
349 			 &uaddr, rlen,
350 			 VM_PROT_READ|VM_PROT_WRITE,
351 			 VM_PROT_READ|VM_PROT_WRITE,
352 			 MAP_PRIVATE|MAP_ANON,
353 			 NULL, 0,
354 			 p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
355 
356 	if (error == 0) {
357 		error = copyout(buf, (char *)uaddr, len);
358 		if (error == 0) {
359 			pref->pref_plist = (char *)uaddr;
360 			pref->pref_len   = len;
361 		}
362 	}
363 
364 	free(buf, M_TEMP);
365 
366 	return (error);
367 }
368 
369 /*
370  * prop_array_copyout_ioctl --
371  *	Copy out an array being received with an ioctl.
372  */
373 int
374 prop_array_copyout_ioctl(struct plistref *pref, const u_long cmd,
375 			 prop_array_t array)
376 {
377 	return (_prop_object_copyout_ioctl(pref, cmd, array));
378 }
379 
380 /*
381  * prop_dictionary_copyout_ioctl --
382  *	Copy out a dictionary being received with an ioctl.
383  */
384 int
385 prop_dictionary_copyout_ioctl(struct plistref *pref, const u_long cmd,
386 			      prop_dictionary_t dict)
387 {
388 	return (_prop_object_copyout_ioctl(pref, cmd, dict));
389 }
390 #endif /* _KERNEL */
391 
392 #endif /* __NetBSD__ */
393