xref: /openbmc/qemu/bsd-user/freebsd/os-proc.c (revision 2df1eb27)
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>
24 struct 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  */
33 static char *
34 get_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 
68 out:
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 
81 /*
82  * execve/fexecve
83  */
84 abi_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);
118     /* save the first argument for the emulator */
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 
237 execve_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 
258 #include <sys/procctl.h>
259 
260 static abi_long
261 t2h_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 
291 static abi_long
292 h2t_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 
310 static abi_long
311 t2h_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 
328 static abi_long
329 h2t_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 
346 static abi_long
347 h2t_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 
363 abi_long
364 do_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 }
481