]> git.proxmox.com Git - mirror_qemu.git/blame - bsd-user/freebsd/os-proc.c
Merge tag 'firmware/edk2-20231213-pull-request' of https://gitlab.com/kraxel/qemu...
[mirror_qemu.git] / bsd-user / freebsd / os-proc.c
CommitLineData
84d41c5e
KT
1/*
2 * FreeBSD process related emulation code
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#include "qemu/osdep.h"
20
21#include <sys/param.h>
22#include <sys/queue.h>
23#include <sys/sysctl.h>
24struct kinfo_proc;
25#include <libprocstat.h>
26
27#include "qemu.h"
28
29/*
30 * Get the filename for the given file descriptor.
31 * Note that this may return NULL (fail) if no longer cached in the kernel.
32 */
86327290 33static char *
84d41c5e
KT
34get_filename_from_fd(pid_t pid, int fd, char *filename, size_t len)
35{
36 char *ret = NULL;
37 unsigned int cnt;
38 struct procstat *procstat = NULL;
39 struct kinfo_proc *kp = NULL;
40 struct filestat_list *head = NULL;
41 struct filestat *fst;
42
43 procstat = procstat_open_sysctl();
44 if (procstat == NULL) {
45 goto out;
46 }
47
48 kp = procstat_getprocs(procstat, KERN_PROC_PID, pid, &cnt);
49 if (kp == NULL) {
50 goto out;
51 }
52
53 head = procstat_getfiles(procstat, kp, 0);
54 if (head == NULL) {
55 goto out;
56 }
57
58 STAILQ_FOREACH(fst, head, next) {
59 if (fd == fst->fs_fd) {
60 if (fst->fs_path != NULL) {
61 (void)strlcpy(filename, fst->fs_path, len);
62 ret = filename;
63 }
64 break;
65 }
66 }
67
68out:
69 if (head != NULL) {
70 procstat_freefiles(procstat, head);
71 }
72 if (kp != NULL) {
73 procstat_freeprocs(procstat, kp);
74 }
75 if (procstat != NULL) {
76 procstat_close(procstat);
77 }
78 return ret;
79}
80
86327290
SS
81/*
82 * execve/fexecve
83 */
84abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
85 abi_ulong guest_envp, int do_fexec)
86{
87 char **argp, **envp, **qargp, **qarg1, **qarg0, **qargend;
88 int argc, envc;
89 abi_ulong gp;
90 abi_ulong addr;
91 char **q;
92 int total_size = 0;
93 void *p;
94 abi_long ret;
95
96 argc = 0;
97 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
98 if (get_user_ual(addr, gp)) {
99 return -TARGET_EFAULT;
100 }
101 if (!addr) {
102 break;
103 }
104 argc++;
105 }
106 envc = 0;
107 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
108 if (get_user_ual(addr, gp)) {
109 return -TARGET_EFAULT;
110 }
111 if (!addr) {
112 break;
113 }
114 envc++;
115 }
116
117 qarg0 = argp = g_new0(char *, argc + 9);
9bfba08a 118 /* save the first argument for the emulator */
86327290
SS
119 *argp++ = (char *)getprogname();
120 qargp = argp;
121 *argp++ = (char *)getprogname();
122 qarg1 = argp;
123 envp = g_new0(char *, envc + 1);
124 for (gp = guest_argp, q = argp; gp; gp += sizeof(abi_ulong), q++) {
125 if (get_user_ual(addr, gp)) {
126 ret = -TARGET_EFAULT;
127 goto execve_end;
128 }
129 if (!addr) {
130 break;
131 }
132 *q = lock_user_string(addr);
133 if (*q == NULL) {
134 ret = -TARGET_EFAULT;
135 goto execve_end;
136 }
137 total_size += strlen(*q) + 1;
138 }
139 *q++ = NULL;
140 qargend = q;
141
142 for (gp = guest_envp, q = envp; gp; gp += sizeof(abi_ulong), q++) {
143 if (get_user_ual(addr, gp)) {
144 ret = -TARGET_EFAULT;
145 goto execve_end;
146 }
147 if (!addr) {
148 break;
149 }
150 *q = lock_user_string(addr);
151 if (*q == NULL) {
152 ret = -TARGET_EFAULT;
153 goto execve_end;
154 }
155 total_size += strlen(*q) + 1;
156 }
157 *q = NULL;
158
159 /*
160 * This case will not be caught by the host's execve() if its
161 * page size is bigger than the target's.
162 */
163 if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
164 ret = -TARGET_E2BIG;
165 goto execve_end;
166 }
167
168 if (do_fexec) {
169 if (((int)path_or_fd > 0 &&
170 is_target_elf_binary((int)path_or_fd)) == 1) {
171 char execpath[PATH_MAX];
172
173 /*
174 * The executable is an elf binary for the target
175 * arch. execve() it using the emulator if we can
176 * determine the filename path from the fd.
177 */
178 if (get_filename_from_fd(getpid(), (int)path_or_fd, execpath,
179 sizeof(execpath)) != NULL) {
180 memmove(qarg1 + 2, qarg1, (qargend - qarg1) * sizeof(*qarg1));
181 qarg1[1] = qarg1[0];
182 qarg1[0] = (char *)"-0";
183 qarg1 += 2;
184 qargend += 2;
185 *qarg1 = execpath;
186#ifndef DONT_INHERIT_INTERP_PREFIX
187 memmove(qarg1 + 2, qarg1, (qargend - qarg1) * sizeof(*qarg1));
188 *qarg1++ = (char *)"-L";
189 *qarg1++ = (char *)interp_prefix;
190#endif
191 ret = get_errno(execve(qemu_proc_pathname, qargp, envp));
192 } else {
193 /* Getting the filename path failed. */
194 ret = -TARGET_EBADF;
195 goto execve_end;
196 }
197 } else {
198 ret = get_errno(fexecve((int)path_or_fd, argp, envp));
199 }
200 } else {
201 int fd;
202
203 p = lock_user_string(path_or_fd);
204 if (p == NULL) {
205 ret = -TARGET_EFAULT;
206 goto execve_end;
207 }
208
209 /*
210 * Check the header and see if it a target elf binary. If so
211 * then execute using qemu user mode emulator.
212 */
213 fd = open(p, O_RDONLY | O_CLOEXEC);
214 if (fd > 0 && is_target_elf_binary(fd) == 1) {
215 close(fd);
216 /* execve() as a target binary using emulator. */
217 memmove(qarg1 + 2, qarg1, (qargend - qarg1) * sizeof(*qarg1));
218 qarg1[1] = qarg1[0];
219 qarg1[0] = (char *)"-0";
220 qarg1 += 2;
221 qargend += 2;
222 *qarg1 = (char *)p;
223#ifndef DONT_INHERIT_INTERP_PREFIX
224 memmove(qarg1 + 2, qarg1, (qargend - qarg1) * sizeof(*qarg1));
225 *qarg1++ = (char *)"-L";
226 *qarg1++ = (char *)interp_prefix;
227#endif
228 ret = get_errno(execve(qemu_proc_pathname, qargp, envp));
229 } else {
230 close(fd);
231 /* Execve() as a host native binary. */
232 ret = get_errno(execve(p, argp, envp));
233 }
234 unlock_user(p, path_or_fd, 0);
235 }
236
237execve_end:
238 for (gp = guest_argp, q = argp; *q; gp += sizeof(abi_ulong), q++) {
239 if (get_user_ual(addr, gp) || !addr) {
240 break;
241 }
242 unlock_user(*q, addr, 0);
243 }
244
245 for (gp = guest_envp, q = envp; *q; gp += sizeof(abi_ulong), q++) {
246 if (get_user_ual(addr, gp) || !addr) {
247 break;
248 }
249 unlock_user(*q, addr, 0);
250 }
251
252 g_free(qarg0);
253 g_free(envp);
254
255 return ret;
256}
257
dcaa3dfd
SS
258#include <sys/procctl.h>
259
260static abi_long
261t2h_procctl_cmd(int target_cmd, int *host_cmd)
262{
263 switch (target_cmd) {
264 case TARGET_PROC_SPROTECT:
265 *host_cmd = PROC_SPROTECT;
266 break;
267
268 case TARGET_PROC_REAP_ACQUIRE:
269 *host_cmd = PROC_REAP_ACQUIRE;
270 break;
271
272 case TARGET_PROC_REAP_RELEASE:
273 *host_cmd = PROC_REAP_RELEASE;
274 break;
275
276 case TARGET_PROC_REAP_STATUS:
277 *host_cmd = PROC_REAP_STATUS;
278 break;
279
280 case TARGET_PROC_REAP_KILL:
281 *host_cmd = PROC_REAP_KILL;
282 break;
283
284 default:
285 return -TARGET_EINVAL;
286 }
287
288 return 0;
289}
290
291static abi_long
292h2t_reaper_status(struct procctl_reaper_status *host_rs,
293 abi_ulong target_rs_addr)
294{
295 struct target_procctl_reaper_status *target_rs;
296
297 if (!lock_user_struct(VERIFY_WRITE, target_rs, target_rs_addr, 0)) {
298 return -TARGET_EFAULT;
299 }
300 __put_user(host_rs->rs_flags, &target_rs->rs_flags);
301 __put_user(host_rs->rs_children, &target_rs->rs_children);
302 __put_user(host_rs->rs_descendants, &target_rs->rs_descendants);
303 __put_user(host_rs->rs_reaper, &target_rs->rs_reaper);
304 __put_user(host_rs->rs_pid, &target_rs->rs_pid);
305 unlock_user_struct(target_rs, target_rs_addr, 1);
306
307 return 0;
308}
309
310static abi_long
311t2h_reaper_kill(abi_ulong target_rk_addr, struct procctl_reaper_kill *host_rk)
312{
313 struct target_procctl_reaper_kill *target_rk;
314
315 if (!lock_user_struct(VERIFY_READ, target_rk, target_rk_addr, 1)) {
316 return -TARGET_EFAULT;
317 }
318 __get_user(host_rk->rk_sig, &target_rk->rk_sig);
319 __get_user(host_rk->rk_flags, &target_rk->rk_flags);
320 __get_user(host_rk->rk_subtree, &target_rk->rk_subtree);
321 __get_user(host_rk->rk_killed, &target_rk->rk_killed);
322 __get_user(host_rk->rk_fpid, &target_rk->rk_fpid);
323 unlock_user_struct(target_rk, target_rk_addr, 0);
324
325 return 0;
326}
327
328static abi_long
329h2t_reaper_kill(struct procctl_reaper_kill *host_rk, abi_ulong target_rk_addr)
330{
331 struct target_procctl_reaper_kill *target_rk;
332
333 if (!lock_user_struct(VERIFY_WRITE, target_rk, target_rk_addr, 0)) {
334 return -TARGET_EFAULT;
335 }
336 __put_user(host_rk->rk_sig, &target_rk->rk_sig);
337 __put_user(host_rk->rk_flags, &target_rk->rk_flags);
338 __put_user(host_rk->rk_subtree, &target_rk->rk_subtree);
339 __put_user(host_rk->rk_killed, &target_rk->rk_killed);
340 __put_user(host_rk->rk_fpid, &target_rk->rk_fpid);
341 unlock_user_struct(target_rk, target_rk_addr, 1);
342
343 return 0;
344}
345
346static abi_long
347h2t_procctl_reaper_pidinfo(struct procctl_reaper_pidinfo *host_pi,
348 abi_ulong target_pi_addr)
349{
350 struct target_procctl_reaper_pidinfo *target_pi;
351
352 if (!lock_user_struct(VERIFY_WRITE, target_pi, target_pi_addr, 0)) {
353 return -TARGET_EFAULT;
354 }
355 __put_user(host_pi->pi_pid, &target_pi->pi_pid);
356 __put_user(host_pi->pi_subtree, &target_pi->pi_subtree);
357 __put_user(host_pi->pi_flags, &target_pi->pi_flags);
358 unlock_user_struct(target_pi, target_pi_addr, 1);
359
360 return 0;
361}
362
363abi_long
364do_freebsd_procctl(void *cpu_env, int idtype, abi_ulong arg2, abi_ulong arg3,
365 abi_ulong arg4, abi_ulong arg5, abi_ulong arg6)
366{
367 abi_long error = 0, target_rp_pids;
368 void *data;
369 int host_cmd, flags;
370 uint32_t u, target_rp_count;
371 g_autofree union {
372 struct procctl_reaper_status rs;
373 struct procctl_reaper_pids rp;
374 struct procctl_reaper_kill rk;
375 } host;
376 struct target_procctl_reaper_pids *target_rp;
377 id_t id; /* 64-bit */
378 int target_cmd;
379 abi_ulong target_arg;
380
381#if TARGET_ABI_BITS == 32
382 /* See if we need to align the register pairs. */
383 if (regpairs_aligned(cpu_env)) {
384 id = (id_t)target_arg64(arg3, arg4);
385 target_cmd = (int)arg5;
386 target_arg = arg6;
387 } else {
388 id = (id_t)target_arg64(arg2, arg3);
389 target_cmd = (int)arg4;
390 target_arg = arg5;
391 }
392#else
393 id = (id_t)arg2;
394 target_cmd = (int)arg3;
395 target_arg = arg4;
396#endif
397
398 error = t2h_procctl_cmd(target_cmd, &host_cmd);
399 if (error) {
400 return error;
401 }
402 switch (host_cmd) {
403 case PROC_SPROTECT:
404 data = &flags;
405 break;
406
407 case PROC_REAP_ACQUIRE:
408 case PROC_REAP_RELEASE:
409 if (target_arg == 0) {
410 data = NULL;
411 } else {
412 error = -TARGET_EINVAL;
413 }
414 break;
415
416 case PROC_REAP_STATUS:
417 data = &host.rs;
418 break;
419
420 case PROC_REAP_GETPIDS:
421 if (!lock_user_struct(VERIFY_READ, target_rp, target_arg, 1)) {
422 return -TARGET_EFAULT;
423 }
424 __get_user(target_rp_count, &target_rp->rp_count);
425 __get_user(target_rp_pids, &target_rp->rp_pids);
426 unlock_user_struct(target_rp, target_arg, 0);
427 host.rp.rp_count = target_rp_count;
428 host.rp.rp_pids = g_try_new(struct procctl_reaper_pidinfo,
429 target_rp_count);
430
431 if (host.rp.rp_pids == NULL) {
432 error = -TARGET_ENOMEM;
433 } else {
434 data = &host.rp;
435 }
436 break;
437
438 case PROC_REAP_KILL:
439 error = t2h_reaper_kill(target_arg, &host.rk);
440 break;
441 }
442
443 if (error) {
444 return error;
445 }
446 error = get_errno(procctl(idtype, id, host_cmd, data));
447
448 if (error) {
449 return error;
450 }
451 switch (host_cmd) {
452 case PROC_SPROTECT:
453 if (put_user_s32(flags, target_arg)) {
454 return -TARGET_EFAULT;
455 }
456 break;
457
458 case PROC_REAP_STATUS:
459 error = h2t_reaper_status(&host.rs, target_arg);
460 break;
461
462 case PROC_REAP_GETPIDS:
463 /* copyout reaper pidinfo */
464 for (u = 0; u < target_rp_count; u++) {
465 error = h2t_procctl_reaper_pidinfo(&host.rp.rp_pids[u],
466 target_rp_pids +
467 (u * sizeof(struct target_procctl_reaper_pidinfo)));
468 if (error) {
469 break;
470 }
471 }
472 break;
473
474 case PROC_REAP_KILL:
475 error = h2t_reaper_kill(&host.rk, target_arg);
476 break;
477 }
478
479 return error;
480}