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 * execve/fexecve 31 */ 32 abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp, 33 abi_ulong guest_envp, int do_fexec) 34 { 35 char **argp, **envp, **qarg0; 36 int argc, envc; 37 abi_ulong gp; 38 abi_ulong addr; 39 char **q; 40 int total_size = 0; 41 void *p; 42 abi_long ret; 43 44 argc = 0; 45 for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) { 46 if (get_user_ual(addr, gp)) { 47 return -TARGET_EFAULT; 48 } 49 if (!addr) { 50 break; 51 } 52 argc++; 53 } 54 envc = 0; 55 for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) { 56 if (get_user_ual(addr, gp)) { 57 return -TARGET_EFAULT; 58 } 59 if (!addr) { 60 break; 61 } 62 envc++; 63 } 64 65 qarg0 = argp = g_new0(char *, argc + 9); 66 /* save the first argument for the emulator */ 67 *argp++ = (char *)getprogname(); 68 *argp++ = (char *)getprogname(); 69 envp = g_new0(char *, envc + 1); 70 for (gp = guest_argp, q = argp; gp; gp += sizeof(abi_ulong), q++) { 71 if (get_user_ual(addr, gp)) { 72 ret = -TARGET_EFAULT; 73 goto execve_end; 74 } 75 if (!addr) { 76 break; 77 } 78 *q = lock_user_string(addr); 79 if (*q == NULL) { 80 ret = -TARGET_EFAULT; 81 goto execve_end; 82 } 83 total_size += strlen(*q) + 1; 84 } 85 *q++ = NULL; 86 87 for (gp = guest_envp, q = envp; gp; gp += sizeof(abi_ulong), q++) { 88 if (get_user_ual(addr, gp)) { 89 ret = -TARGET_EFAULT; 90 goto execve_end; 91 } 92 if (!addr) { 93 break; 94 } 95 *q = lock_user_string(addr); 96 if (*q == NULL) { 97 ret = -TARGET_EFAULT; 98 goto execve_end; 99 } 100 total_size += strlen(*q) + 1; 101 } 102 *q = NULL; 103 104 /* 105 * This case will not be caught by the host's execve() if its 106 * page size is bigger than the target's. 107 */ 108 if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) { 109 ret = -TARGET_E2BIG; 110 goto execve_end; 111 } 112 113 if (do_fexec) { 114 ret = get_errno(fexecve((int)path_or_fd, argp, envp)); 115 } else { 116 p = lock_user_string(path_or_fd); 117 if (p == NULL) { 118 ret = -TARGET_EFAULT; 119 goto execve_end; 120 } 121 ret = get_errno(execve(p, argp, envp)); 122 unlock_user(p, path_or_fd, 0); 123 } 124 125 execve_end: 126 for (gp = guest_argp, q = argp; *q; gp += sizeof(abi_ulong), q++) { 127 if (get_user_ual(addr, gp) || !addr) { 128 break; 129 } 130 unlock_user(*q, addr, 0); 131 } 132 133 for (gp = guest_envp, q = envp; *q; gp += sizeof(abi_ulong), q++) { 134 if (get_user_ual(addr, gp) || !addr) { 135 break; 136 } 137 unlock_user(*q, addr, 0); 138 } 139 140 g_free(qarg0); 141 g_free(envp); 142 143 return ret; 144 } 145 146 #include <sys/procctl.h> 147 148 static abi_long 149 t2h_procctl_cmd(int target_cmd, int *host_cmd) 150 { 151 switch (target_cmd) { 152 case TARGET_PROC_SPROTECT: 153 *host_cmd = PROC_SPROTECT; 154 break; 155 156 case TARGET_PROC_REAP_ACQUIRE: 157 *host_cmd = PROC_REAP_ACQUIRE; 158 break; 159 160 case TARGET_PROC_REAP_RELEASE: 161 *host_cmd = PROC_REAP_RELEASE; 162 break; 163 164 case TARGET_PROC_REAP_STATUS: 165 *host_cmd = PROC_REAP_STATUS; 166 break; 167 168 case TARGET_PROC_REAP_KILL: 169 *host_cmd = PROC_REAP_KILL; 170 break; 171 172 default: 173 return -TARGET_EINVAL; 174 } 175 176 return 0; 177 } 178 179 static abi_long 180 h2t_reaper_status(struct procctl_reaper_status *host_rs, 181 abi_ulong target_rs_addr) 182 { 183 struct target_procctl_reaper_status *target_rs; 184 185 if (!lock_user_struct(VERIFY_WRITE, target_rs, target_rs_addr, 0)) { 186 return -TARGET_EFAULT; 187 } 188 __put_user(host_rs->rs_flags, &target_rs->rs_flags); 189 __put_user(host_rs->rs_children, &target_rs->rs_children); 190 __put_user(host_rs->rs_descendants, &target_rs->rs_descendants); 191 __put_user(host_rs->rs_reaper, &target_rs->rs_reaper); 192 __put_user(host_rs->rs_pid, &target_rs->rs_pid); 193 unlock_user_struct(target_rs, target_rs_addr, 1); 194 195 return 0; 196 } 197 198 static abi_long 199 t2h_reaper_kill(abi_ulong target_rk_addr, struct procctl_reaper_kill *host_rk) 200 { 201 struct target_procctl_reaper_kill *target_rk; 202 203 if (!lock_user_struct(VERIFY_READ, target_rk, target_rk_addr, 1)) { 204 return -TARGET_EFAULT; 205 } 206 __get_user(host_rk->rk_sig, &target_rk->rk_sig); 207 __get_user(host_rk->rk_flags, &target_rk->rk_flags); 208 __get_user(host_rk->rk_subtree, &target_rk->rk_subtree); 209 __get_user(host_rk->rk_killed, &target_rk->rk_killed); 210 __get_user(host_rk->rk_fpid, &target_rk->rk_fpid); 211 unlock_user_struct(target_rk, target_rk_addr, 0); 212 213 return 0; 214 } 215 216 static abi_long 217 h2t_reaper_kill(struct procctl_reaper_kill *host_rk, abi_ulong target_rk_addr) 218 { 219 struct target_procctl_reaper_kill *target_rk; 220 221 if (!lock_user_struct(VERIFY_WRITE, target_rk, target_rk_addr, 0)) { 222 return -TARGET_EFAULT; 223 } 224 __put_user(host_rk->rk_sig, &target_rk->rk_sig); 225 __put_user(host_rk->rk_flags, &target_rk->rk_flags); 226 __put_user(host_rk->rk_subtree, &target_rk->rk_subtree); 227 __put_user(host_rk->rk_killed, &target_rk->rk_killed); 228 __put_user(host_rk->rk_fpid, &target_rk->rk_fpid); 229 unlock_user_struct(target_rk, target_rk_addr, 1); 230 231 return 0; 232 } 233 234 static abi_long 235 h2t_procctl_reaper_pidinfo(struct procctl_reaper_pidinfo *host_pi, 236 abi_ulong target_pi_addr) 237 { 238 struct target_procctl_reaper_pidinfo *target_pi; 239 240 if (!lock_user_struct(VERIFY_WRITE, target_pi, target_pi_addr, 0)) { 241 return -TARGET_EFAULT; 242 } 243 __put_user(host_pi->pi_pid, &target_pi->pi_pid); 244 __put_user(host_pi->pi_subtree, &target_pi->pi_subtree); 245 __put_user(host_pi->pi_flags, &target_pi->pi_flags); 246 unlock_user_struct(target_pi, target_pi_addr, 1); 247 248 return 0; 249 } 250 251 abi_long 252 do_freebsd_procctl(void *cpu_env, int idtype, abi_ulong arg2, abi_ulong arg3, 253 abi_ulong arg4, abi_ulong arg5, abi_ulong arg6) 254 { 255 abi_long error = 0, target_rp_pids; 256 void *data; 257 int host_cmd, flags; 258 uint32_t u, target_rp_count; 259 g_autofree union { 260 struct procctl_reaper_status rs; 261 struct procctl_reaper_pids rp; 262 struct procctl_reaper_kill rk; 263 } host; 264 struct target_procctl_reaper_pids *target_rp; 265 id_t id; /* 64-bit */ 266 int target_cmd; 267 abi_ulong target_arg; 268 269 #if TARGET_ABI_BITS == 32 270 /* See if we need to align the register pairs. */ 271 if (regpairs_aligned(cpu_env)) { 272 id = (id_t)target_arg64(arg3, arg4); 273 target_cmd = (int)arg5; 274 target_arg = arg6; 275 } else { 276 id = (id_t)target_arg64(arg2, arg3); 277 target_cmd = (int)arg4; 278 target_arg = arg5; 279 } 280 #else 281 id = (id_t)arg2; 282 target_cmd = (int)arg3; 283 target_arg = arg4; 284 #endif 285 286 error = t2h_procctl_cmd(target_cmd, &host_cmd); 287 if (error) { 288 return error; 289 } 290 switch (host_cmd) { 291 case PROC_SPROTECT: 292 data = &flags; 293 break; 294 295 case PROC_REAP_ACQUIRE: 296 case PROC_REAP_RELEASE: 297 if (target_arg == 0) { 298 data = NULL; 299 } else { 300 error = -TARGET_EINVAL; 301 } 302 break; 303 304 case PROC_REAP_STATUS: 305 data = &host.rs; 306 break; 307 308 case PROC_REAP_GETPIDS: 309 if (!lock_user_struct(VERIFY_READ, target_rp, target_arg, 1)) { 310 return -TARGET_EFAULT; 311 } 312 __get_user(target_rp_count, &target_rp->rp_count); 313 __get_user(target_rp_pids, &target_rp->rp_pids); 314 unlock_user_struct(target_rp, target_arg, 0); 315 host.rp.rp_count = target_rp_count; 316 host.rp.rp_pids = g_try_new(struct procctl_reaper_pidinfo, 317 target_rp_count); 318 319 if (host.rp.rp_pids == NULL) { 320 error = -TARGET_ENOMEM; 321 } else { 322 data = &host.rp; 323 } 324 break; 325 326 case PROC_REAP_KILL: 327 error = t2h_reaper_kill(target_arg, &host.rk); 328 break; 329 } 330 331 if (error) { 332 return error; 333 } 334 error = get_errno(procctl(idtype, id, host_cmd, data)); 335 336 if (error) { 337 return error; 338 } 339 switch (host_cmd) { 340 case PROC_SPROTECT: 341 if (put_user_s32(flags, target_arg)) { 342 return -TARGET_EFAULT; 343 } 344 break; 345 346 case PROC_REAP_STATUS: 347 error = h2t_reaper_status(&host.rs, target_arg); 348 break; 349 350 case PROC_REAP_GETPIDS: 351 /* copyout reaper pidinfo */ 352 for (u = 0; u < target_rp_count; u++) { 353 error = h2t_procctl_reaper_pidinfo(&host.rp.rp_pids[u], 354 target_rp_pids + 355 (u * sizeof(struct target_procctl_reaper_pidinfo))); 356 if (error) { 357 break; 358 } 359 } 360 break; 361 362 case PROC_REAP_KILL: 363 error = h2t_reaper_kill(&host.rk, target_arg); 364 break; 365 } 366 367 return error; 368 } 369