1 /*
2 * FreeBSD sysctl() and sysarch() system call emulation
3 *
4 * Copyright (c) 2013-15 Stacey D. Son
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "qemu/osdep.h"
21 #include "qemu.h"
22 #include "target_arch_sysarch.h"
23
24 #include <sys/sysctl.h>
25
26 /*
27 * Length for the fixed length types.
28 * 0 means variable length for strings and structures
29 * Compare with sys/kern_sysctl.c ctl_size
30 * Note: Not all types appear to be used in-tree.
31 */
32 static const int guest_ctl_size[CTLTYPE + 1] = {
33 [CTLTYPE_INT] = sizeof(abi_int),
34 [CTLTYPE_UINT] = sizeof(abi_uint),
35 [CTLTYPE_LONG] = sizeof(abi_long),
36 [CTLTYPE_ULONG] = sizeof(abi_ulong),
37 [CTLTYPE_S8] = sizeof(int8_t),
38 [CTLTYPE_S16] = sizeof(int16_t),
39 [CTLTYPE_S32] = sizeof(int32_t),
40 [CTLTYPE_S64] = sizeof(int64_t),
41 [CTLTYPE_U8] = sizeof(uint8_t),
42 [CTLTYPE_U16] = sizeof(uint16_t),
43 [CTLTYPE_U32] = sizeof(uint32_t),
44 [CTLTYPE_U64] = sizeof(uint64_t),
45 };
46
47 static const int host_ctl_size[CTLTYPE + 1] = {
48 [CTLTYPE_INT] = sizeof(int),
49 [CTLTYPE_UINT] = sizeof(u_int),
50 [CTLTYPE_LONG] = sizeof(long),
51 [CTLTYPE_ULONG] = sizeof(u_long),
52 [CTLTYPE_S8] = sizeof(int8_t),
53 [CTLTYPE_S16] = sizeof(int16_t),
54 [CTLTYPE_S32] = sizeof(int32_t),
55 [CTLTYPE_S64] = sizeof(int64_t),
56 [CTLTYPE_U8] = sizeof(uint8_t),
57 [CTLTYPE_U16] = sizeof(uint16_t),
58 [CTLTYPE_U32] = sizeof(uint32_t),
59 [CTLTYPE_U64] = sizeof(uint64_t),
60 };
61
62 #ifdef TARGET_ABI32
63 /*
64 * Limit the amount of available memory to be most of the 32-bit address
65 * space. 0x100c000 was arrived at through trial and error as a good
66 * definition of 'most'.
67 */
68 static const abi_ulong guest_max_mem = UINT32_MAX - 0x100c000 + 1;
69
cap_memory(uint64_t mem)70 static abi_ulong cap_memory(uint64_t mem)
71 {
72 return MIN(guest_max_mem, mem);
73 }
74 #endif
75
scale_to_guest_pages(uint64_t pages)76 static abi_ulong scale_to_guest_pages(uint64_t pages)
77 {
78 /* Scale pages from host to guest */
79 pages = muldiv64(pages, qemu_real_host_page_size(), TARGET_PAGE_SIZE);
80 #ifdef TARGET_ABI32
81 /* cap pages if need be */
82 pages = MIN(pages, guest_max_mem / (abi_ulong)TARGET_PAGE_SIZE);
83 #endif
84 return pages;
85 }
86
87 #ifdef TARGET_ABI32
88 /* Used only for TARGET_ABI32 */
h2g_long_sat(long l)89 static abi_long h2g_long_sat(long l)
90 {
91 if (l > INT32_MAX) {
92 l = INT32_MAX;
93 } else if (l < INT32_MIN) {
94 l = INT32_MIN;
95 }
96 return l;
97 }
98
h2g_ulong_sat(u_long ul)99 static abi_ulong h2g_ulong_sat(u_long ul)
100 {
101 return MIN(ul, UINT32_MAX);
102 }
103 #endif
104
105 /*
106 * placeholder until bsd-user downstream upstreams this with its thread support
107 */
108 #define bsd_get_ncpu() 1
109
110 /*
111 * This uses the undocumented oidfmt interface to find the kind of a requested
112 * sysctl, see /sys/kern/kern_sysctl.c:sysctl_sysctl_oidfmt() (compare to
113 * src/sbin/sysctl/sysctl.c)
114 */
oidfmt(int * oid,int len,char * fmt,uint32_t * kind)115 static int oidfmt(int *oid, int len, char *fmt, uint32_t *kind)
116 {
117 int qoid[CTL_MAXNAME + 2];
118 uint8_t buf[BUFSIZ];
119 int i;
120 size_t j;
121
122 qoid[0] = CTL_SYSCTL;
123 qoid[1] = CTL_SYSCTL_OIDFMT;
124 memcpy(qoid + 2, oid, len * sizeof(int));
125
126 j = sizeof(buf);
127 i = sysctl(qoid, len + 2, buf, &j, 0, 0);
128 if (i) {
129 return i;
130 }
131
132 if (kind) {
133 *kind = *(uint32_t *)buf;
134 }
135
136 if (fmt) {
137 strcpy(fmt, (char *)(buf + sizeof(uint32_t)));
138 }
139 return 0;
140 }
141
142 /*
143 * Convert the old value from host to guest.
144 *
145 * For LONG and ULONG on ABI32, we need to 'down convert' the 8 byte quantities
146 * to 4 bytes. The caller setup a buffer in host memory to get this data from
147 * the kernel and pass it to us. We do the down conversion and adjust the length
148 * so the caller knows what to write as the returned length into the target when
149 * it copies the down converted values into the target.
150 *
151 * For normal integral types, we just need to byte swap. No size changes.
152 *
153 * For strings and node data, there's no conversion needed.
154 *
155 * For opaque data, per sysctl OID converts take care of it.
156 */
h2g_old_sysctl(void * holdp,size_t * holdlen,uint32_t kind)157 static void h2g_old_sysctl(void *holdp, size_t *holdlen, uint32_t kind)
158 {
159 size_t len;
160 int hlen, glen;
161 uint8_t *hp, *gp;
162
163 /*
164 * Although rare, we can have arrays of sysctl. Both sysctl_old_ddb in
165 * kern_sysctl.c and show_var in sbin/sysctl/sysctl.c have code that loops
166 * this way. *holdlen has been set by the kernel to the host's length.
167 * Only LONG and ULONG on ABI32 have different sizes: see below.
168 */
169 gp = hp = (uint8_t *)holdp;
170 len = 0;
171 hlen = host_ctl_size[kind & CTLTYPE];
172 glen = guest_ctl_size[kind & CTLTYPE];
173
174 /*
175 * hlen == 0 for CTLTYPE_STRING and CTLTYPE_NODE, which need no conversion
176 * as well as CTLTYPE_OPAQUE, which needs special converters.
177 */
178 if (hlen == 0) {
179 return;
180 }
181
182 while (len < *holdlen) {
183 if (hlen == glen) {
184 switch (hlen) {
185 case 1:
186 /* Nothing needed: no byteswapping and assigning in place */
187 break;
188 case 2:
189 *(uint16_t *)gp = tswap16(*(uint16_t *)hp);
190 break;
191 case 4:
192 *(uint32_t *)gp = tswap32(*(uint32_t *)hp);
193 break;
194 case 8:
195 *(uint64_t *)gp = tswap64(*(uint64_t *)hp);
196 break;
197 default:
198 g_assert_not_reached();
199 }
200 } else {
201 #ifdef TARGET_ABI32
202 /*
203 * Saturating assignment for the only two types that differ between
204 * 32-bit and 64-bit machines. All other integral types have the
205 * same, fixed size and will be converted w/o loss of precision
206 * in the above switch.
207 */
208 switch (kind & CTLTYPE) {
209 case CTLTYPE_LONG:
210 *(abi_long *)gp = tswap32(h2g_long_sat(*(long *)hp));
211 break;
212 case CTLTYPE_ULONG:
213 *(abi_ulong *)gp = tswap32(h2g_ulong_sat(*(u_long *)hp));
214 break;
215 default:
216 g_assert_not_reached();
217 }
218 #else
219 g_assert_not_reached();
220 #endif
221 }
222 gp += glen;
223 hp += hlen;
224 len += hlen;
225 }
226 #ifdef TARGET_ABI32
227 if (hlen != glen) {
228 *holdlen = (*holdlen / hlen) * glen;
229 }
230 #endif
231 }
232
233 /*
234 * Convert the undocmented name2oid sysctl data for the target.
235 */
sysctl_name2oid(uint32_t * holdp,size_t holdlen)236 static inline void sysctl_name2oid(uint32_t *holdp, size_t holdlen)
237 {
238 size_t i, num = holdlen / sizeof(uint32_t);
239
240 for (i = 0; i < num; i++) {
241 holdp[i] = tswap32(holdp[i]);
242 }
243 }
244
sysctl_oidfmt(uint32_t * holdp)245 static inline void sysctl_oidfmt(uint32_t *holdp)
246 {
247 /* byte swap the kind */
248 holdp[0] = tswap32(holdp[0]);
249 }
250
do_freebsd_sysctl_oid(CPUArchState * env,int32_t * snamep,int32_t namelen,void * holdp,size_t * holdlenp,void * hnewp,size_t newlen)251 static abi_long do_freebsd_sysctl_oid(CPUArchState *env, int32_t *snamep,
252 int32_t namelen, void *holdp, size_t *holdlenp, void *hnewp,
253 size_t newlen)
254 {
255 uint32_t kind = 0;
256 abi_long ret;
257 size_t holdlen, oldlen;
258 #ifdef TARGET_ABI32
259 void *old_holdp;
260 #endif
261
262 holdlen = oldlen = *holdlenp;
263 oidfmt(snamep, namelen, NULL, &kind);
264
265 /* Handle some arch/emulator dependent sysctl()'s here. */
266 switch (snamep[0]) {
267 case CTL_KERN:
268 switch (snamep[1]) {
269 case KERN_USRSTACK:
270 if (oldlen) {
271 (*(abi_ulong *)holdp) = tswapal(TARGET_USRSTACK);
272 }
273 holdlen = sizeof(abi_ulong);
274 ret = 0;
275 goto out;
276
277 case KERN_PS_STRINGS:
278 if (oldlen) {
279 (*(abi_ulong *)holdp) = tswapal(TARGET_PS_STRINGS);
280 }
281 holdlen = sizeof(abi_ulong);
282 ret = 0;
283 goto out;
284
285 default:
286 break;
287 }
288 break;
289
290 case CTL_HW:
291 switch (snamep[1]) {
292 case HW_MACHINE:
293 holdlen = sizeof(TARGET_HW_MACHINE);
294 if (holdp) {
295 strlcpy(holdp, TARGET_HW_MACHINE, oldlen);
296 }
297 ret = 0;
298 goto out;
299
300 case HW_MACHINE_ARCH:
301 {
302 holdlen = sizeof(TARGET_HW_MACHINE_ARCH);
303 if (holdp) {
304 strlcpy(holdp, TARGET_HW_MACHINE_ARCH, oldlen);
305 }
306 ret = 0;
307 goto out;
308 }
309 case HW_NCPU:
310 if (oldlen) {
311 (*(abi_int *)holdp) = tswap32(bsd_get_ncpu());
312 }
313 holdlen = sizeof(int32_t);
314 ret = 0;
315 goto out;
316 #if defined(TARGET_ARM)
317 case HW_FLOATINGPT:
318 if (oldlen) {
319 ARMCPU *cpu = env_archcpu(env);
320 *(abi_int *)holdp = cpu_isar_feature(aa32_vfp, cpu);
321 }
322 holdlen = sizeof(abi_int);
323 ret = 0;
324 goto out;
325 #endif
326
327
328 #ifdef TARGET_ABI32
329 case HW_PHYSMEM:
330 case HW_USERMEM:
331 case HW_REALMEM:
332 holdlen = sizeof(abi_ulong);
333 ret = 0;
334
335 if (oldlen) {
336 int mib[2] = {snamep[0], snamep[1]};
337 unsigned long lvalue;
338 size_t len = sizeof(lvalue);
339
340 if (sysctl(mib, 2, &lvalue, &len, NULL, 0) == -1) {
341 ret = -1;
342 } else {
343 lvalue = cap_memory(lvalue);
344 (*(abi_ulong *)holdp) = tswapal((abi_ulong)lvalue);
345 }
346 }
347 goto out;
348 #endif
349
350 default:
351 {
352 static int oid_hw_availpages;
353 static int oid_hw_pagesizes;
354
355 if (!oid_hw_availpages) {
356 int real_oid[CTL_MAXNAME + 2];
357 size_t len = sizeof(real_oid) / sizeof(int);
358
359 if (sysctlnametomib("hw.availpages", real_oid, &len) >= 0) {
360 oid_hw_availpages = real_oid[1];
361 }
362 }
363 if (!oid_hw_pagesizes) {
364 int real_oid[CTL_MAXNAME + 2];
365 size_t len = sizeof(real_oid) / sizeof(int);
366
367 if (sysctlnametomib("hw.pagesizes", real_oid, &len) >= 0) {
368 oid_hw_pagesizes = real_oid[1];
369 }
370 }
371
372 if (oid_hw_availpages && snamep[1] == oid_hw_availpages) {
373 long lvalue;
374 size_t len = sizeof(lvalue);
375
376 if (sysctlbyname("hw.availpages", &lvalue, &len, NULL, 0) == -1) {
377 ret = -1;
378 } else {
379 if (oldlen) {
380 lvalue = scale_to_guest_pages(lvalue);
381 (*(abi_ulong *)holdp) = tswapal((abi_ulong)lvalue);
382 }
383 holdlen = sizeof(abi_ulong);
384 ret = 0;
385 }
386 goto out;
387 }
388
389 if (oid_hw_pagesizes && snamep[1] == oid_hw_pagesizes) {
390 if (oldlen) {
391 (*(abi_ulong *)holdp) = tswapal((abi_ulong)TARGET_PAGE_SIZE);
392 ((abi_ulong *)holdp)[1] = 0;
393 }
394 holdlen = sizeof(abi_ulong) * 2;
395 ret = 0;
396 goto out;
397 }
398 break;
399 }
400 }
401 break;
402
403 default:
404 break;
405 }
406
407 #ifdef TARGET_ABI32
408 /*
409 * For long and ulong with a 64-bit host and a 32-bit target we have to do
410 * special things. holdlen here is the length provided by the target to the
411 * system call. So we allocate a buffer twice as large because longs are
412 * twice as big on the host which will be writing them. In h2g_old_sysctl
413 * we'll adjust them and adjust the length.
414 */
415 if (kind == CTLTYPE_LONG || kind == CTLTYPE_ULONG) {
416 old_holdp = holdp;
417 holdlen = holdlen * 2;
418 holdp = g_malloc(holdlen);
419 }
420 #endif
421
422 ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen));
423 if (!ret && (holdp != 0)) {
424
425 if (snamep[0] == CTL_SYSCTL) {
426 switch (snamep[1]) {
427 case CTL_SYSCTL_NEXT:
428 case CTL_SYSCTL_NAME2OID:
429 case CTL_SYSCTL_NEXTNOSKIP:
430 /*
431 * All of these return an OID array, so we need to convert to
432 * target.
433 */
434 sysctl_name2oid(holdp, holdlen);
435 break;
436
437 case CTL_SYSCTL_OIDFMT:
438 /* Handle oidfmt */
439 sysctl_oidfmt(holdp);
440 break;
441 case CTL_SYSCTL_OIDDESCR:
442 case CTL_SYSCTL_OIDLABEL:
443 default:
444 /* Handle it based on the type */
445 h2g_old_sysctl(holdp, &holdlen, kind);
446 /* NB: None of these are LONG or ULONG */
447 break;
448 }
449 } else {
450 /*
451 * Need to convert from host to target. All the weird special cases
452 * are handled above.
453 */
454 h2g_old_sysctl(holdp, &holdlen, kind);
455 #ifdef TARGET_ABI32
456 /*
457 * For the 32-bit on 64-bit case, for longs we need to copy the
458 * now-converted buffer to the target and free the buffer.
459 */
460 if (kind == CTLTYPE_LONG || kind == CTLTYPE_ULONG) {
461 memcpy(old_holdp, holdp, holdlen);
462 g_free(holdp);
463 holdp = old_holdp;
464 }
465 #endif
466 }
467 }
468
469 out:
470 *holdlenp = holdlen;
471 return ret;
472 }
473
474 /*
475 * This syscall was created to make sysctlbyname(3) more efficient, but we can't
476 * really provide it in bsd-user. Notably, we must always translate the names
477 * independently since some sysctl values have to be faked for the target
478 * environment, so it still has to break down to two syscalls for the underlying
479 * implementation.
480 */
do_freebsd_sysctlbyname(CPUArchState * env,abi_ulong namep,int32_t namelen,abi_ulong oldp,abi_ulong oldlenp,abi_ulong newp,abi_ulong newlen)481 abi_long do_freebsd_sysctlbyname(CPUArchState *env, abi_ulong namep,
482 int32_t namelen, abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp,
483 abi_ulong newlen)
484 {
485 abi_long ret = -TARGET_EFAULT;
486 void *holdp = NULL, *hnewp = NULL;
487 char *snamep = NULL;
488 int oid[CTL_MAXNAME + 2];
489 size_t holdlen, oidplen;
490 abi_ulong oldlen = 0;
491
492 /* oldlenp is read/write, pre-check here for write */
493 if (oldlenp) {
494 if (!access_ok(VERIFY_WRITE, oldlenp, sizeof(abi_ulong)) ||
495 get_user_ual(oldlen, oldlenp)) {
496 goto out;
497 }
498 }
499 snamep = lock_user_string(namep);
500 if (snamep == NULL) {
501 goto out;
502 }
503 if (newp) {
504 hnewp = lock_user(VERIFY_READ, newp, newlen, 1);
505 if (hnewp == NULL) {
506 goto out;
507 }
508 }
509 if (oldp) {
510 holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0);
511 if (holdp == NULL) {
512 goto out;
513 }
514 }
515 holdlen = oldlen;
516
517 oidplen = ARRAY_SIZE(oid);
518 if (sysctlnametomib(snamep, oid, &oidplen) != 0) {
519 ret = -TARGET_EINVAL;
520 goto out;
521 }
522
523 ret = do_freebsd_sysctl_oid(env, oid, oidplen, holdp, &holdlen, hnewp,
524 newlen);
525
526 /*
527 * writeability pre-checked above. __sysctl(2) returns ENOMEM and updates
528 * oldlenp for the proper size to use.
529 */
530 if (oldlenp && (ret == 0 || ret == -TARGET_ENOMEM)) {
531 put_user_ual(holdlen, oldlenp);
532 }
533 out:
534 unlock_user(snamep, namep, 0);
535 unlock_user(holdp, oldp, ret == 0 ? holdlen : 0);
536 unlock_user(hnewp, newp, 0);
537
538 return ret;
539 }
540
do_freebsd_sysctl(CPUArchState * env,abi_ulong namep,int32_t namelen,abi_ulong oldp,abi_ulong oldlenp,abi_ulong newp,abi_ulong newlen)541 abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
542 abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
543 {
544 abi_long ret = -TARGET_EFAULT;
545 void *hnamep, *holdp = NULL, *hnewp = NULL;
546 size_t holdlen;
547 abi_ulong oldlen = 0;
548 int32_t *snamep = g_malloc(sizeof(int32_t) * namelen), *p, *q, i;
549
550 /* oldlenp is read/write, pre-check here for write */
551 if (oldlenp) {
552 if (!access_ok(VERIFY_WRITE, oldlenp, sizeof(abi_ulong)) ||
553 get_user_ual(oldlen, oldlenp)) {
554 goto out;
555 }
556 }
557 hnamep = lock_user(VERIFY_READ, namep, namelen, 1);
558 if (hnamep == NULL) {
559 goto out;
560 }
561 if (newp) {
562 hnewp = lock_user(VERIFY_READ, newp, newlen, 1);
563 if (hnewp == NULL) {
564 goto out;
565 }
566 }
567 if (oldp) {
568 holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0);
569 if (holdp == NULL) {
570 goto out;
571 }
572 }
573 holdlen = oldlen;
574 for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++, q++) {
575 *q = tswap32(*p);
576 }
577
578 ret = do_freebsd_sysctl_oid(env, snamep, namelen, holdp, &holdlen, hnewp,
579 newlen);
580
581 /*
582 * writeability pre-checked above. __sysctl(2) returns ENOMEM and updates
583 * oldlenp for the proper size to use.
584 */
585 if (oldlenp && (ret == 0 || ret == -TARGET_ENOMEM)) {
586 put_user_ual(holdlen, oldlenp);
587 }
588 unlock_user(hnamep, namep, 0);
589 unlock_user(holdp, oldp, ret == 0 ? holdlen : 0);
590 out:
591 g_free(snamep);
592 return ret;
593 }
594
595 /* sysarch() is architecture dependent. */
do_freebsd_sysarch(void * cpu_env,abi_long arg1,abi_long arg2)596 abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2)
597 {
598 return do_freebsd_arch_sysarch(cpu_env, arg1, arg2);
599 }
600