vmd.c revision 1.77
1/* $OpenBSD: vmd.c,v 1.77 2018/01/03 05:39:56 ccardenas Exp $ */ 2 3/* 4 * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/param.h> /* nitems */ 20#include <sys/queue.h> 21#include <sys/wait.h> 22#include <sys/cdefs.h> 23#include <sys/stat.h> 24#include <sys/tty.h> 25#include <sys/ioctl.h> 26 27#include <stdio.h> 28#include <stdlib.h> 29#include <string.h> 30#include <termios.h> 31#include <errno.h> 32#include <event.h> 33#include <fcntl.h> 34#include <pwd.h> 35#include <signal.h> 36#include <syslog.h> 37#include <unistd.h> 38#include <ctype.h> 39#include <pwd.h> 40#include <grp.h> 41 42#include <machine/specialreg.h> 43#include <machine/vmmvar.h> 44 45#include "proc.h" 46#include "atomicio.h" 47#include "vmd.h" 48 49__dead void usage(void); 50 51int main(int, char **); 52int vmd_configure(void); 53void vmd_sighdlr(int sig, short event, void *arg); 54void vmd_shutdown(void); 55int vmd_control_run(void); 56int vmd_dispatch_control(int, struct privsep_proc *, struct imsg *); 57int vmd_dispatch_vmm(int, struct privsep_proc *, struct imsg *); 58int check_vmh(struct vm_dump_header *); 59 60struct vmd *env; 61 62static struct privsep_proc procs[] = { 63 /* Keep "priv" on top as procs[0] */ 64 { "priv", PROC_PRIV, NULL, priv }, 65 { "control", PROC_CONTROL, vmd_dispatch_control, control }, 66 { "vmm", PROC_VMM, vmd_dispatch_vmm, vmm, vmm_shutdown }, 67}; 68 69/* For the privileged process */ 70static struct privsep_proc *proc_priv = &procs[0]; 71static struct passwd proc_privpw; 72 73int 74vmd_dispatch_control(int fd, struct privsep_proc *p, struct imsg *imsg) 75{ 76 struct privsep *ps = p->p_ps; 77 int res = 0, ret = 0, cmd = 0, verbose; 78 unsigned int v = 0; 79 struct vmop_create_params vmc; 80 struct vmop_id vid; 81 struct vm_terminate_params vtp; 82 struct vmop_result vmr; 83 struct vm_dump_header vmh; 84 struct vmd_vm *vm = NULL; 85 char *str = NULL; 86 uint32_t id = 0; 87 88 switch (imsg->hdr.type) { 89 case IMSG_VMDOP_START_VM_REQUEST: 90 IMSG_SIZE_CHECK(imsg, &vmc); 91 memcpy(&vmc, imsg->data, sizeof(vmc)); 92 ret = vm_register(ps, &vmc, &vm, 0, vmc.vmc_uid); 93 if (vmc.vmc_flags == 0) { 94 /* start an existing VM with pre-configured options */ 95 if (!(ret == -1 && errno == EALREADY && 96 vm->vm_running == 0)) { 97 res = errno; 98 cmd = IMSG_VMDOP_START_VM_RESPONSE; 99 } 100 } else if (ret != 0) { 101 res = errno; 102 cmd = IMSG_VMDOP_START_VM_RESPONSE; 103 } 104 if (res == 0 && 105 config_setvm(ps, vm, imsg->hdr.peerid, vm->vm_params.vmc_uid) == -1) { 106 res = errno; 107 cmd = IMSG_VMDOP_START_VM_RESPONSE; 108 } 109 break; 110 case IMSG_VMDOP_TERMINATE_VM_REQUEST: 111 IMSG_SIZE_CHECK(imsg, &vid); 112 memcpy(&vid, imsg->data, sizeof(vid)); 113 if ((id = vid.vid_id) == 0) { 114 /* Lookup vm (id) by name */ 115 if ((vm = vm_getbyname(vid.vid_name)) == NULL) { 116 res = ENOENT; 117 cmd = IMSG_VMDOP_TERMINATE_VM_RESPONSE; 118 break; 119 } else if (vm->vm_shutdown) { 120 res = EALREADY; 121 cmd = IMSG_VMDOP_TERMINATE_VM_RESPONSE; 122 break; 123 } else if (vm->vm_running == 0) { 124 res = EINVAL; 125 cmd = IMSG_VMDOP_TERMINATE_VM_RESPONSE; 126 break; 127 } 128 id = vm->vm_vmid; 129 } else if ((vm = vm_getbyvmid(id)) == NULL) { 130 res = ENOENT; 131 cmd = IMSG_VMDOP_TERMINATE_VM_RESPONSE; 132 break; 133 } 134 if (vm_checkperm(vm, vid.vid_uid) != 0) { 135 res = EPERM; 136 cmd = IMSG_VMDOP_TERMINATE_VM_RESPONSE; 137 break; 138 } 139 memset(&vtp, 0, sizeof(vtp)); 140 vtp.vtp_vm_id = id; 141 if (proc_compose_imsg(ps, PROC_VMM, -1, imsg->hdr.type, 142 imsg->hdr.peerid, -1, &vtp, sizeof(vtp)) == -1) 143 return (-1); 144 break; 145 case IMSG_VMDOP_GET_INFO_VM_REQUEST: 146 proc_forward_imsg(ps, imsg, PROC_VMM, -1); 147 break; 148 case IMSG_VMDOP_LOAD: 149 IMSG_SIZE_CHECK(imsg, str); /* at least one byte for path */ 150 str = get_string((uint8_t *)imsg->data, 151 IMSG_DATA_SIZE(imsg)); 152 case IMSG_VMDOP_RELOAD: 153 if (vmd_reload(0, str) == -1) 154 cmd = IMSG_CTL_FAIL; 155 else 156 cmd = IMSG_CTL_OK; 157 free(str); 158 break; 159 case IMSG_CTL_RESET: 160 IMSG_SIZE_CHECK(imsg, &v); 161 memcpy(&v, imsg->data, sizeof(v)); 162 if (vmd_reload(v, NULL) == -1) 163 cmd = IMSG_CTL_FAIL; 164 else 165 cmd = IMSG_CTL_OK; 166 break; 167 case IMSG_CTL_VERBOSE: 168 IMSG_SIZE_CHECK(imsg, &verbose); 169 memcpy(&verbose, imsg->data, sizeof(verbose)); 170 log_setverbose(verbose); 171 172 proc_forward_imsg(ps, imsg, PROC_VMM, -1); 173 proc_forward_imsg(ps, imsg, PROC_PRIV, -1); 174 cmd = IMSG_CTL_OK; 175 break; 176 case IMSG_VMDOP_PAUSE_VM: 177 case IMSG_VMDOP_UNPAUSE_VM: 178 IMSG_SIZE_CHECK(imsg, &vid); 179 memcpy(&vid, imsg->data, sizeof(vid)); 180 if (vid.vid_id == 0) { 181 if ((vm = vm_getbyname(vid.vid_name)) == NULL) { 182 res = ENOENT; 183 cmd = IMSG_VMDOP_PAUSE_VM_RESPONSE; 184 break; 185 } else { 186 vid.vid_id = vm->vm_vmid; 187 } 188 } 189 proc_compose_imsg(ps, PROC_VMM, -1, imsg->hdr.type, 190 imsg->hdr.peerid, -1, &vid, sizeof(vid)); 191 break; 192 case IMSG_VMDOP_SEND_VM_REQUEST: 193 IMSG_SIZE_CHECK(imsg, &vid); 194 memcpy(&vid, imsg->data, sizeof(vid)); 195 id = vid.vid_id; 196 if (vid.vid_id == 0) { 197 if ((vm = vm_getbyname(vid.vid_name)) == NULL) { 198 res = ENOENT; 199 cmd = IMSG_VMDOP_SEND_VM_RESPONSE; 200 close(imsg->fd); 201 break; 202 } else { 203 vid.vid_id = vm->vm_vmid; 204 } 205 } else if ((vm = vm_getbyvmid(vid.vid_id)) == NULL) { 206 res = ENOENT; 207 cmd = IMSG_VMDOP_SEND_VM_RESPONSE; 208 close(imsg->fd); 209 break; 210 } else { 211 } 212 vmr.vmr_id = vid.vid_id; 213 log_debug("%s: sending fd to vmm", __func__); 214 proc_compose_imsg(ps, PROC_VMM, -1, imsg->hdr.type, 215 imsg->hdr.peerid, imsg->fd, &vid, sizeof(vid)); 216 break; 217 case IMSG_VMDOP_RECEIVE_VM_REQUEST: 218 IMSG_SIZE_CHECK(imsg, &vid); 219 memcpy(&vid, imsg->data, sizeof(vid)); 220 if (imsg->fd == -1) { 221 log_warnx("%s: invalid fd", __func__); 222 return (-1); 223 } 224 if (atomicio(read, imsg->fd, &vmh, sizeof(vmh)) != 225 sizeof(vmh)) { 226 log_warnx("%s: error reading vmh from recevied vm", 227 __func__); 228 res = EIO; 229 close(imsg->fd); 230 cmd = IMSG_VMDOP_START_VM_RESPONSE; 231 break; 232 } 233 if(check_vmh(&vmh)) { 234 res = ENOENT; 235 close(imsg->fd); 236 cmd = IMSG_VMDOP_START_VM_RESPONSE; 237 break; 238 } 239 if (atomicio(read, imsg->fd, &vmc, sizeof(vmc)) != 240 sizeof(vmc)) { 241 log_warnx("%s: error reading vmc from recevied vm", 242 __func__); 243 res = EIO; 244 close(imsg->fd); 245 cmd = IMSG_VMDOP_START_VM_RESPONSE; 246 break; 247 } 248 strlcpy(vmc.vmc_params.vcp_name, vid.vid_name, 249 sizeof(vmc.vmc_params.vcp_name)); 250 vmc.vmc_params.vcp_id = 0; 251 252 ret = vm_register(ps, &vmc, &vm, 0, vmc.vmc_uid); 253 if (ret != 0) { 254 res = errno; 255 cmd = IMSG_VMDOP_START_VM_RESPONSE; 256 close(imsg->fd); 257 } else { 258 vm->vm_received = 1; 259 config_setvm(ps, vm, imsg->hdr.peerid, vmc.vmc_uid); 260 log_debug("%s: sending fd to vmm", __func__); 261 proc_compose_imsg(ps, PROC_VMM, -1, 262 IMSG_VMDOP_RECEIVE_VM_END, vm->vm_vmid, imsg->fd, 263 NULL, 0); 264 } 265 break; 266 default: 267 return (-1); 268 } 269 270 switch (cmd) { 271 case 0: 272 break; 273 case IMSG_VMDOP_START_VM_RESPONSE: 274 case IMSG_VMDOP_TERMINATE_VM_RESPONSE: 275 memset(&vmr, 0, sizeof(vmr)); 276 vmr.vmr_result = res; 277 vmr.vmr_id = id; 278 if (proc_compose_imsg(ps, PROC_CONTROL, -1, cmd, 279 imsg->hdr.peerid, -1, &vmr, sizeof(vmr)) == -1) 280 return (-1); 281 break; 282 default: 283 if (proc_compose_imsg(ps, PROC_CONTROL, -1, cmd, 284 imsg->hdr.peerid, -1, &res, sizeof(res)) == -1) 285 return (-1); 286 break; 287 } 288 289 return (0); 290} 291 292int 293vmd_dispatch_vmm(int fd, struct privsep_proc *p, struct imsg *imsg) 294{ 295 struct vmop_result vmr; 296 struct privsep *ps = p->p_ps; 297 int res = 0; 298 struct vmd_vm *vm; 299 struct vm_create_params *vcp; 300 struct vmop_info_result vir; 301 302 switch (imsg->hdr.type) { 303 case IMSG_VMDOP_PAUSE_VM_RESPONSE: 304 IMSG_SIZE_CHECK(imsg, &vmr); 305 memcpy(&vmr, imsg->data, sizeof(vmr)); 306 if ((vm = vm_getbyvmid(vmr.vmr_id)) == NULL) 307 break; 308 proc_compose_imsg(ps, PROC_CONTROL, -1, 309 imsg->hdr.type, imsg->hdr.peerid, -1, 310 imsg->data, sizeof(imsg->data)); 311 log_info("%s: paused vm %d successfully", 312 vm->vm_params.vmc_params.vcp_name, 313 vm->vm_vmid); 314 break; 315 case IMSG_VMDOP_UNPAUSE_VM_RESPONSE: 316 IMSG_SIZE_CHECK(imsg, &vmr); 317 memcpy(&vmr, imsg->data, sizeof(vmr)); 318 if ((vm = vm_getbyvmid(vmr.vmr_id)) == NULL) 319 break; 320 proc_compose_imsg(ps, PROC_CONTROL, -1, 321 imsg->hdr.type, imsg->hdr.peerid, -1, 322 imsg->data, sizeof(imsg->data)); 323 log_info("%s: unpaused vm %d successfully.", 324 vm->vm_params.vmc_params.vcp_name, 325 vm->vm_vmid); 326 break; 327 case IMSG_VMDOP_START_VM_RESPONSE: 328 IMSG_SIZE_CHECK(imsg, &vmr); 329 memcpy(&vmr, imsg->data, sizeof(vmr)); 330 if ((vm = vm_getbyvmid(imsg->hdr.peerid)) == NULL) 331 break; 332 vm->vm_pid = vmr.vmr_pid; 333 vcp = &vm->vm_params.vmc_params; 334 vcp->vcp_id = vmr.vmr_id; 335 336 /* 337 * If the peerid is not -1, forward the response back to the 338 * the control socket. If it is -1, the request originated 339 * from the parent, not the control socket. 340 */ 341 if (vm->vm_peerid != (uint32_t)-1) { 342 (void)strlcpy(vmr.vmr_ttyname, vm->vm_ttyname, 343 sizeof(vmr.vmr_ttyname)); 344 if (proc_compose_imsg(ps, PROC_CONTROL, -1, 345 imsg->hdr.type, vm->vm_peerid, -1, 346 &vmr, sizeof(vmr)) == -1) { 347 errno = vmr.vmr_result; 348 log_warn("%s: failed to foward vm result", 349 vcp->vcp_name); 350 vm_remove(vm); 351 return (-1); 352 } 353 } 354 355 if (vmr.vmr_result) { 356 errno = vmr.vmr_result; 357 log_warn("%s: failed to start vm", vcp->vcp_name); 358 vm_remove(vm); 359 break; 360 } 361 362 /* Now configure all the interfaces */ 363 if (vm_priv_ifconfig(ps, vm) == -1) { 364 log_warn("%s: failed to configure vm", vcp->vcp_name); 365 vm_remove(vm); 366 break; 367 } 368 369 log_info("%s: started vm %d successfully, tty %s", 370 vcp->vcp_name, vm->vm_vmid, vm->vm_ttyname); 371 break; 372 case IMSG_VMDOP_TERMINATE_VM_RESPONSE: 373 IMSG_SIZE_CHECK(imsg, &vmr); 374 memcpy(&vmr, imsg->data, sizeof(vmr)); 375 log_debug("%s: forwarding TERMINATE VM for vm id %d", 376 __func__, vmr.vmr_id); 377 proc_forward_imsg(ps, imsg, PROC_CONTROL, -1); 378 if ((vm = vm_getbyvmid(vmr.vmr_id)) == NULL) 379 break; 380 if (vmr.vmr_result == 0) { 381 /* Mark VM as shutting down */ 382 vm->vm_shutdown = 1; 383 } 384 break; 385 case IMSG_VMDOP_SEND_VM_RESPONSE: 386 IMSG_SIZE_CHECK(imsg, &vmr); 387 memcpy(&vmr, imsg->data, sizeof(vmr)); 388 if ((vm = vm_getbyvmid(vmr.vmr_id)) == NULL) 389 break; 390 if (!vmr.vmr_result) 391 log_info("%s: sent vm %d successfully.", 392 vm->vm_params.vmc_params.vcp_name, 393 vm->vm_vmid); 394 case IMSG_VMDOP_TERMINATE_VM_EVENT: 395 IMSG_SIZE_CHECK(imsg, &vmr); 396 memcpy(&vmr, imsg->data, sizeof(vmr)); 397 log_debug("%s: handling TERMINATE_EVENT for vm id %d ret %d", 398 __func__, vmr.vmr_id, vmr.vmr_result); 399 if ((vm = vm_getbyvmid(vmr.vmr_id)) == NULL) { 400 log_debug("%s: vm %d is no longer available", 401 __func__, vmr.vmr_id); 402 break; 403 } 404 if (vmr.vmr_result != EAGAIN) { 405 if (vm->vm_from_config) { 406 log_debug("%s: about to stop vm id %d", 407 __func__, vm->vm_vmid); 408 vm_stop(vm, 0); 409 } else { 410 log_debug("%s: about to remove vm %d", 411 __func__, vm->vm_vmid); 412 vm_remove(vm); 413 } 414 } else { 415 /* Stop VM instance but keep the tty open */ 416 log_debug("%s: about to stop vm id %d with tty open", 417 __func__, vm->vm_vmid); 418 vm_stop(vm, 1); 419 config_setvm(ps, vm, (uint32_t)-1, vm->vm_uid); 420 } 421 break; 422 case IMSG_VMDOP_GET_INFO_VM_DATA: 423 IMSG_SIZE_CHECK(imsg, &vir); 424 memcpy(&vir, imsg->data, sizeof(vir)); 425 if ((vm = vm_getbyvmid(vir.vir_info.vir_id)) != NULL) { 426 memset(vir.vir_ttyname, 0, sizeof(vir.vir_ttyname)); 427 if (vm->vm_ttyname != NULL) 428 strlcpy(vir.vir_ttyname, vm->vm_ttyname, 429 sizeof(vir.vir_ttyname)); 430 if (vm->vm_shutdown) { 431 /* XXX there might be a nicer way */ 432 (void)strlcat(vir.vir_info.vir_name, 433 " - stopping", 434 sizeof(vir.vir_info.vir_name)); 435 } 436 /* get the user id who started the vm */ 437 vir.vir_uid = vm->vm_uid; 438 vir.vir_gid = vm->vm_params.vmc_gid; 439 } 440 if (proc_compose_imsg(ps, PROC_CONTROL, -1, imsg->hdr.type, 441 imsg->hdr.peerid, -1, &vir, sizeof(vir)) == -1) { 442 log_debug("%s: GET_INFO_VM failed for vm %d, removing", 443 __func__, vm->vm_vmid); 444 vm_remove(vm); 445 return (-1); 446 } 447 break; 448 case IMSG_VMDOP_GET_INFO_VM_END_DATA: 449 /* 450 * PROC_VMM has responded with the *running* VMs, now we 451 * append the others. These use the special value 0 for their 452 * kernel id to indicate that they are not running. 453 */ 454 TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) { 455 if (!vm->vm_running) { 456 memset(&vir, 0, sizeof(vir)); 457 vir.vir_info.vir_id = vm->vm_vmid; 458 strlcpy(vir.vir_info.vir_name, 459 vm->vm_params.vmc_params.vcp_name, 460 VMM_MAX_NAME_LEN); 461 vir.vir_info.vir_memory_size = 462 vm->vm_params.vmc_params.vcp_memranges[0].vmr_size; 463 vir.vir_info.vir_ncpus = 464 vm->vm_params.vmc_params.vcp_ncpus; 465 /* get the configured user id for this vm */ 466 vir.vir_uid = vm->vm_params.vmc_uid; 467 vir.vir_gid = vm->vm_params.vmc_gid; 468 if (proc_compose_imsg(ps, PROC_CONTROL, -1, 469 IMSG_VMDOP_GET_INFO_VM_DATA, 470 imsg->hdr.peerid, -1, &vir, 471 sizeof(vir)) == -1) { 472 log_debug("%s: GET_INFO_VM_END failed", 473 __func__); 474 vm_remove(vm); 475 return (-1); 476 } 477 } 478 } 479 IMSG_SIZE_CHECK(imsg, &res); 480 proc_forward_imsg(ps, imsg, PROC_CONTROL, -1); 481 break; 482 default: 483 return (-1); 484 } 485 486 return (0); 487} 488 489int 490check_vmh(struct vm_dump_header *vmh) { 491 int i; 492 unsigned int code, leaf; 493 unsigned int a, b, c, d; 494 495 496 if (vmh->vmh_version != VM_DUMP_VERSION) { 497 log_warnx("%s: incompatible dump version", __func__); 498 return (-1); 499 } 500 501 for (i = 0; i < VM_DUMP_HEADER_CPUID_COUNT; i++) { 502 code = vmh->vmh_cpuids[i].code; 503 leaf = vmh->vmh_cpuids[i].leaf; 504 if (leaf != 0x00) { 505 log_debug("%s: invalid leaf 0x%x for code 0x%x", 506 __func__, leaf, code); 507 return (-1); 508 } 509 510 switch(code) { 511 case 0x00: 512 CPUID_LEAF(code, leaf, a, b, c, d); 513 if (vmh->vmh_cpuids[i].a > a) { 514 log_debug("%s: incompatible cpuid level", __func__); 515 return (-1); 516 } 517 if (!(vmh->vmh_cpuids[i].b == b && 518 vmh->vmh_cpuids[i].c == c && 519 vmh->vmh_cpuids[i].d == d)) { 520 log_debug("%s: incompatible cpu brand", __func__); 521 return (-1); 522 } 523 break; 524 525 case 0x01: 526 CPUID_LEAF(code, leaf, a, b, c, d); 527 if ((vmh->vmh_cpuids[i].c & c & VMM_CPUIDECX_MASK) != 528 (vmh->vmh_cpuids[i].c & VMM_CPUIDECX_MASK)) { 529 log_debug("%s: incompatible cpu features " 530 "code: 0x%x leaf: 0x%x reg: c", __func__, 531 code, leaf); 532 return (-1); 533 } 534 if ((vmh->vmh_cpuids[i].d & d & VMM_CPUIDEDX_MASK) != 535 (vmh->vmh_cpuids[i].d & VMM_CPUIDEDX_MASK)) { 536 log_debug("%s: incompatible cpu features " 537 "code: 0x%x leaf: 0x%x reg: d", __func__, 538 code, leaf); 539 return (-1); 540 } 541 break; 542 543 case 0x07: 544 CPUID_LEAF(code, leaf, a, b, c, d); 545 if ((vmh->vmh_cpuids[i].b & b & VMM_SEFF0EBX_MASK) != 546 (vmh->vmh_cpuids[i].b & VMM_SEFF0EBX_MASK)) { 547 log_debug("%s: incompatible cpu features " 548 "code: 0x%x leaf: 0x%x reg: c", __func__, 549 code, leaf); 550 return (-1); 551 } 552 if ((vmh->vmh_cpuids[i].c & c & VMM_SEFF0ECX_MASK) != 553 (vmh->vmh_cpuids[i].c & VMM_SEFF0ECX_MASK)) { 554 log_debug("%s: incompatible cpu features " 555 "code: 0x%x leaf: 0x%x reg: d", __func__, 556 code, leaf); 557 return (-1); 558 } 559 break; 560 561 case 0x0d: 562 CPUID_LEAF(code, leaf, a, b, c, d); 563 if (vmh->vmh_cpuids[i].b > b) { 564 log_debug("%s: incompatible cpu: insufficient " 565 "max save area for enabled XCR0 features", 566 __func__); 567 return (-1); 568 } 569 if (vmh->vmh_cpuids[i].c > c) { 570 log_debug("%s: incompatible cpu: insufficient " 571 "max save area for supported XCR0 features", 572 __func__); 573 return (-1); 574 } 575 break; 576 577 case 0x80000001: 578 CPUID_LEAF(code, leaf, a, b, c, d); 579 if ((vmh->vmh_cpuids[i].a & a) != vmh->vmh_cpuids[i].a) { 580 log_debug("%s: incompatible cpu features " 581 "code: 0x%x leaf: 0x%x reg: a", __func__, 582 code, leaf); 583 return (-1); 584 } 585 if ((vmh->vmh_cpuids[i].c & c) != vmh->vmh_cpuids[i].c) { 586 log_debug("%s: incompatible cpu features " 587 "code: 0x%x leaf: 0x%x reg: c", __func__, 588 code, leaf); 589 return (-1); 590 } 591 if ((vmh->vmh_cpuids[i].d & d) != vmh->vmh_cpuids[i].d) { 592 log_debug("%s: incompatible cpu features " 593 "code: 0x%x leaf: 0x%x reg: d", __func__, 594 code, leaf); 595 return (-1); 596 } 597 break; 598 599 default: 600 log_debug("%s: unknown code 0x%x", __func__, code); 601 return (-1); 602 } 603 } 604 605 return (0); 606} 607 608void 609vmd_sighdlr(int sig, short event, void *arg) 610{ 611 if (privsep_process != PROC_PARENT) 612 return; 613 log_debug("%s: handling signal", __func__); 614 615 switch (sig) { 616 case SIGHUP: 617 log_info("%s: reload requested with SIGHUP", __func__); 618 619 /* 620 * This is safe because libevent uses async signal handlers 621 * that run in the event loop and not in signal context. 622 */ 623 (void)vmd_reload(0, NULL); 624 break; 625 case SIGPIPE: 626 log_info("%s: ignoring SIGPIPE", __func__); 627 break; 628 case SIGUSR1: 629 log_info("%s: ignoring SIGUSR1", __func__); 630 break; 631 case SIGTERM: 632 case SIGINT: 633 vmd_shutdown(); 634 break; 635 default: 636 fatalx("unexpected signal"); 637 } 638} 639 640__dead void 641usage(void) 642{ 643 extern char *__progname; 644 fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n", 645 __progname); 646 exit(1); 647} 648 649int 650main(int argc, char **argv) 651{ 652 struct privsep *ps; 653 int ch; 654 const char *conffile = VMD_CONF; 655 enum privsep_procid proc_id = PROC_PARENT; 656 int proc_instance = 0; 657 const char *errp, *title = NULL; 658 int argc0 = argc; 659 660 /* log to stderr until daemonized */ 661 log_init(1, LOG_DAEMON); 662 663 if ((env = calloc(1, sizeof(*env))) == NULL) 664 fatal("calloc: env"); 665 666 while ((ch = getopt(argc, argv, "D:P:I:df:vn")) != -1) { 667 switch (ch) { 668 case 'D': 669 if (cmdline_symset(optarg) < 0) 670 log_warnx("could not parse macro definition %s", 671 optarg); 672 break; 673 case 'd': 674 env->vmd_debug = 2; 675 break; 676 case 'f': 677 conffile = optarg; 678 break; 679 case 'v': 680 env->vmd_verbose++; 681 break; 682 case 'n': 683 env->vmd_noaction = 1; 684 break; 685 case 'P': 686 title = optarg; 687 proc_id = proc_getid(procs, nitems(procs), title); 688 if (proc_id == PROC_MAX) 689 fatalx("invalid process name"); 690 break; 691 case 'I': 692 proc_instance = strtonum(optarg, 0, 693 PROC_MAX_INSTANCES, &errp); 694 if (errp) 695 fatalx("invalid process instance"); 696 break; 697 default: 698 usage(); 699 } 700 } 701 702 argc -= optind; 703 if (argc > 0) 704 usage(); 705 706 if (env->vmd_noaction && !env->vmd_debug) 707 env->vmd_debug = 1; 708 709 /* check for root privileges */ 710 if (env->vmd_noaction == 0) { 711 if (geteuid()) 712 fatalx("need root privileges"); 713 } 714 715 ps = &env->vmd_ps; 716 ps->ps_env = env; 717 env->vmd_fd = -1; 718 719 if (config_init(env) == -1) 720 fatal("failed to initialize configuration"); 721 722 if ((ps->ps_pw = getpwnam(VMD_USER)) == NULL) 723 fatal("unknown user %s", VMD_USER); 724 725 /* First proc runs as root without pledge but in default chroot */ 726 proc_priv->p_pw = &proc_privpw; /* initialized to all 0 */ 727 proc_priv->p_chroot = ps->ps_pw->pw_dir; /* from VMD_USER */ 728 729 /* Open /dev/vmm */ 730 if (env->vmd_noaction == 0) { 731 env->vmd_fd = open(VMM_NODE, O_RDWR); 732 if (env->vmd_fd == -1) 733 fatal("%s", VMM_NODE); 734 } 735 736 /* Configure the control socket */ 737 ps->ps_csock.cs_name = SOCKET_NAME; 738 TAILQ_INIT(&ps->ps_rcsocks); 739 740 /* Configuration will be parsed after forking the children */ 741 env->vmd_conffile = conffile; 742 743 log_init(env->vmd_debug, LOG_DAEMON); 744 log_setverbose(env->vmd_verbose); 745 746 if (env->vmd_noaction) 747 ps->ps_noaction = 1; 748 ps->ps_instance = proc_instance; 749 if (title != NULL) 750 ps->ps_title[proc_id] = title; 751 752 /* only the parent returns */ 753 proc_init(ps, procs, nitems(procs), argc0, argv, proc_id); 754 755 log_procinit("parent"); 756 if (!env->vmd_debug && daemon(0, 0) == -1) 757 fatal("can't daemonize"); 758 759 if (ps->ps_noaction == 0) 760 log_info("startup"); 761 762 event_init(); 763 764 signal_set(&ps->ps_evsigint, SIGINT, vmd_sighdlr, ps); 765 signal_set(&ps->ps_evsigterm, SIGTERM, vmd_sighdlr, ps); 766 signal_set(&ps->ps_evsighup, SIGHUP, vmd_sighdlr, ps); 767 signal_set(&ps->ps_evsigpipe, SIGPIPE, vmd_sighdlr, ps); 768 signal_set(&ps->ps_evsigusr1, SIGUSR1, vmd_sighdlr, ps); 769 770 signal_add(&ps->ps_evsigint, NULL); 771 signal_add(&ps->ps_evsigterm, NULL); 772 signal_add(&ps->ps_evsighup, NULL); 773 signal_add(&ps->ps_evsigpipe, NULL); 774 signal_add(&ps->ps_evsigusr1, NULL); 775 776 if (!env->vmd_noaction) 777 proc_connect(ps); 778 779 if (vmd_configure() == -1) 780 fatalx("configuration failed"); 781 782 event_dispatch(); 783 784 log_debug("parent exiting"); 785 786 return (0); 787} 788 789int 790vmd_configure(void) 791{ 792 struct vmd_vm *vm; 793 struct vmd_switch *vsw; 794 795 if ((env->vmd_ptmfd = open(PATH_PTMDEV, O_RDWR|O_CLOEXEC)) == -1) 796 fatal("open %s", PATH_PTMDEV); 797 798 /* 799 * pledge in the parent process: 800 * stdio - for malloc and basic I/O including events. 801 * rpath - for reload to open and read the configuration files. 802 * wpath - for opening disk images and tap devices. 803 * tty - for openpty. 804 * proc - run kill to terminate its children safely. 805 * sendfd - for disks, interfaces and other fds. 806 * recvfd - for send and receive. 807 * getpw - lookup user or group id by name. 808 * chown, fattr - change tty ownership 809 */ 810 if (pledge("stdio rpath wpath proc tty recvfd sendfd getpw" 811 " chown fattr", NULL) == -1) 812 fatal("pledge"); 813 814 if (parse_config(env->vmd_conffile) == -1) { 815 proc_kill(&env->vmd_ps); 816 exit(1); 817 } 818 819 if (env->vmd_noaction) { 820 fprintf(stderr, "configuration OK\n"); 821 proc_kill(&env->vmd_ps); 822 exit(0); 823 } 824 825 TAILQ_FOREACH(vsw, env->vmd_switches, sw_entry) { 826 if (vsw->sw_running) 827 continue; 828 if (vm_priv_brconfig(&env->vmd_ps, vsw) == -1) { 829 log_warn("%s: failed to create switch %s", 830 __func__, vsw->sw_name); 831 switch_remove(vsw); 832 return (-1); 833 } 834 } 835 836 TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) { 837 if (vm->vm_disabled) { 838 log_debug("%s: not creating vm %s (disabled)", 839 __func__, 840 vm->vm_params.vmc_params.vcp_name); 841 continue; 842 } 843 if (config_setvm(&env->vmd_ps, vm, -1, vm->vm_params.vmc_uid) == -1) 844 return (-1); 845 } 846 847 /* Send shared global configuration to all children */ 848 if (config_setconfig(env) == -1) 849 return (-1); 850 851 return (0); 852} 853 854int 855vmd_reload(unsigned int reset, const char *filename) 856{ 857 struct vmd_vm *vm, *next_vm; 858 struct vmd_switch *vsw; 859 int reload = 0; 860 861 /* Switch back to the default config file */ 862 if (filename == NULL || *filename == '\0') { 863 filename = env->vmd_conffile; 864 reload = 1; 865 } 866 867 log_debug("%s: level %d config file %s", __func__, reset, filename); 868 869 if (reset) { 870 /* Purge the configuration */ 871 config_purge(env, reset); 872 config_setreset(env, reset); 873 } else { 874 /* 875 * Load or reload the configuration. 876 * 877 * Reloading removes all non-running VMs before processing the 878 * config file, whereas loading only adds to the existing list 879 * of VMs. 880 */ 881 882 if (reload) { 883 TAILQ_FOREACH_SAFE(vm, env->vmd_vms, vm_entry, next_vm) { 884 if (vm->vm_running == 0) { 885 log_debug("%s: calling vm_remove", 886 __func__); 887 vm_remove(vm); 888 } 889 } 890 891 /* Update shared global configuration in all children */ 892 if (config_setconfig(env) == -1) 893 return (-1); 894 } 895 896 if (parse_config(filename) == -1) { 897 log_debug("%s: failed to load config file %s", 898 __func__, filename); 899 return (-1); 900 } 901 902 TAILQ_FOREACH(vsw, env->vmd_switches, sw_entry) { 903 if (vsw->sw_running) 904 continue; 905 if (vm_priv_brconfig(&env->vmd_ps, vsw) == -1) { 906 log_warn("%s: failed to create switch %s", 907 __func__, vsw->sw_name); 908 switch_remove(vsw); 909 return (-1); 910 } 911 } 912 913 TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) { 914 if (vm->vm_running == 0) { 915 if (vm->vm_disabled) { 916 log_debug("%s: not creating vm %s" 917 " (disabled)", __func__, 918 vm->vm_params.vmc_params.vcp_name); 919 continue; 920 } 921 if (config_setvm(&env->vmd_ps, vm, -1, vm->vm_params.vmc_uid) == -1) 922 return (-1); 923 } else { 924 log_debug("%s: not creating vm \"%s\": " 925 "(running)", __func__, 926 vm->vm_params.vmc_params.vcp_name); 927 } 928 } 929 } 930 931 return (0); 932} 933 934void 935vmd_shutdown(void) 936{ 937 struct vmd_vm *vm, *vm_next; 938 939 log_debug("%s: performing shutdown", __func__); 940 TAILQ_FOREACH_SAFE(vm, env->vmd_vms, vm_entry, vm_next) { 941 vm_remove(vm); 942 } 943 944 proc_kill(&env->vmd_ps); 945 free(env); 946 947 log_warnx("parent terminating"); 948 exit(0); 949} 950 951struct vmd_vm * 952vm_getbyvmid(uint32_t vmid) 953{ 954 struct vmd_vm *vm; 955 956 if (vmid == 0) 957 return (NULL); 958 TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) { 959 if (vm->vm_vmid == vmid) 960 return (vm); 961 } 962 963 return (NULL); 964} 965 966struct vmd_vm * 967vm_getbyid(uint32_t id) 968{ 969 struct vmd_vm *vm; 970 971 if (id == 0) 972 return (NULL); 973 TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) { 974 if (vm->vm_params.vmc_params.vcp_id == id) 975 return (vm); 976 } 977 978 return (NULL); 979} 980 981uint32_t 982vm_id2vmid(uint32_t id, struct vmd_vm *vm) 983{ 984 if (vm == NULL && (vm = vm_getbyid(id)) == NULL) 985 return (0); 986 dprintf("%s: vmm id %u is vmid %u", __func__, 987 id, vm->vm_vmid); 988 return (vm->vm_vmid); 989} 990 991uint32_t 992vm_vmid2id(uint32_t vmid, struct vmd_vm *vm) 993{ 994 if (vm == NULL && (vm = vm_getbyvmid(vmid)) == NULL) 995 return (0); 996 dprintf("%s: vmid %u is vmm id %u", __func__, 997 vmid, vm->vm_params.vmc_params.vcp_id); 998 return (vm->vm_params.vmc_params.vcp_id); 999} 1000 1001struct vmd_vm * 1002vm_getbyname(const char *name) 1003{ 1004 struct vmd_vm *vm; 1005 1006 if (name == NULL) 1007 return (NULL); 1008 TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) { 1009 if (strcmp(vm->vm_params.vmc_params.vcp_name, name) == 0) 1010 return (vm); 1011 } 1012 1013 return (NULL); 1014} 1015 1016struct vmd_vm * 1017vm_getbypid(pid_t pid) 1018{ 1019 struct vmd_vm *vm; 1020 1021 TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) { 1022 if (vm->vm_pid == pid) 1023 return (vm); 1024 } 1025 1026 return (NULL); 1027} 1028 1029void 1030vm_stop(struct vmd_vm *vm, int keeptty) 1031{ 1032 unsigned int i; 1033 1034 if (vm == NULL) 1035 return; 1036 1037 log_debug("%s: stopping vm %d", __func__, vm->vm_vmid); 1038 vm->vm_running = 0; 1039 vm->vm_shutdown = 0; 1040 1041 if (vm->vm_iev.ibuf.fd != -1) { 1042 event_del(&vm->vm_iev.ev); 1043 close(vm->vm_iev.ibuf.fd); 1044 } 1045 for (i = 0; i < VMM_MAX_DISKS_PER_VM; i++) { 1046 if (vm->vm_disks[i] != -1) { 1047 close(vm->vm_disks[i]); 1048 vm->vm_disks[i] = -1; 1049 } 1050 } 1051 for (i = 0; i < VMM_MAX_NICS_PER_VM; i++) { 1052 if (vm->vm_ifs[i].vif_fd != -1) { 1053 close(vm->vm_ifs[i].vif_fd); 1054 vm->vm_ifs[i].vif_fd = -1; 1055 } 1056 free(vm->vm_ifs[i].vif_name); 1057 free(vm->vm_ifs[i].vif_switch); 1058 free(vm->vm_ifs[i].vif_group); 1059 vm->vm_ifs[i].vif_name = NULL; 1060 vm->vm_ifs[i].vif_switch = NULL; 1061 vm->vm_ifs[i].vif_group = NULL; 1062 } 1063 if (vm->vm_kernel != -1) { 1064 close(vm->vm_kernel); 1065 vm->vm_kernel = -1; 1066 } 1067 if (vm->vm_cdrom != -1) { 1068 close(vm->vm_cdrom); 1069 vm->vm_cdrom = -1; 1070 } 1071 if (!keeptty) { 1072 vm_closetty(vm); 1073 vm->vm_uid = 0; 1074 } 1075} 1076 1077void 1078vm_remove(struct vmd_vm *vm) 1079{ 1080 if (vm == NULL) 1081 return; 1082 1083 log_debug("%s: removing vm id %d from running config", 1084 __func__, vm->vm_vmid); 1085 TAILQ_REMOVE(env->vmd_vms, vm, vm_entry); 1086 log_debug("%s: calling vm_stop", __func__); 1087 vm_stop(vm, 0); 1088 free(vm); 1089} 1090 1091int 1092vm_register(struct privsep *ps, struct vmop_create_params *vmc, 1093 struct vmd_vm **ret_vm, uint32_t id, uid_t uid) 1094{ 1095 struct vmd_vm *vm = NULL; 1096 struct vm_create_params *vcp = &vmc->vmc_params; 1097 static const uint8_t zero_mac[ETHER_ADDR_LEN]; 1098 uint32_t rng; 1099 unsigned int i; 1100 struct vmd_switch *sw; 1101 char *s; 1102 1103 errno = 0; 1104 *ret_vm = NULL; 1105 1106 if ((vm = vm_getbyname(vcp->vcp_name)) != NULL || 1107 (vm = vm_getbyvmid(vcp->vcp_id)) != NULL) { 1108 if (vm_checkperm(vm, uid) != 0) { 1109 errno = EPERM; 1110 goto fail; 1111 } 1112 *ret_vm = vm; 1113 errno = EALREADY; 1114 goto fail; 1115 } 1116 1117 /* 1118 * non-root users can only start existing VMs 1119 * XXX there could be a mechanism to allow overriding some options 1120 */ 1121 if (vm_checkperm(NULL, uid) != 0) { 1122 errno = EPERM; 1123 goto fail; 1124 } 1125 if (vmc->vmc_flags == 0) { 1126 errno = ENOENT; 1127 goto fail; 1128 } 1129 if (vcp->vcp_ncpus == 0) 1130 vcp->vcp_ncpus = 1; 1131 if (vcp->vcp_memranges[0].vmr_size == 0) 1132 vcp->vcp_memranges[0].vmr_size = VM_DEFAULT_MEMORY; 1133 if (vcp->vcp_ncpus > VMM_MAX_VCPUS_PER_VM) { 1134 log_warnx("invalid number of CPUs"); 1135 goto fail; 1136 } else if (vcp->vcp_ndisks > VMM_MAX_DISKS_PER_VM) { 1137 log_warnx("invalid number of disks"); 1138 goto fail; 1139 } else if (vcp->vcp_nnics > VMM_MAX_NICS_PER_VM) { 1140 log_warnx("invalid number of interfaces"); 1141 goto fail; 1142 } else if (strlen(vcp->vcp_kernel) == 0 && vcp->vcp_ndisks == 0) { 1143 log_warnx("no kernel or disk specified"); 1144 goto fail; 1145 } else if (strlen(vcp->vcp_name) == 0) { 1146 log_warnx("invalid VM name"); 1147 goto fail; 1148 } else if (*vcp->vcp_name == '-' || *vcp->vcp_name == '.' || 1149 *vcp->vcp_name == '_') { 1150 log_warnx("Invalid VM name"); 1151 goto fail; 1152 } else { 1153 for (s = vcp->vcp_name; *s != '\0'; ++s) { 1154 if (!(isalnum(*s) || *s == '.' || *s == '-' || 1155 *s == '_')) { 1156 log_warnx("Invalid VM name"); 1157 goto fail; 1158 } 1159 } 1160 } 1161 1162 if ((vm = calloc(1, sizeof(*vm))) == NULL) 1163 goto fail; 1164 1165 memcpy(&vm->vm_params, vmc, sizeof(vm->vm_params)); 1166 vmc = &vm->vm_params; 1167 vcp = &vmc->vmc_params; 1168 vm->vm_pid = -1; 1169 vm->vm_tty = -1; 1170 vm->vm_receive_fd = -1; 1171 vm->vm_paused = 0; 1172 1173 for (i = 0; i < vcp->vcp_ndisks; i++) 1174 vm->vm_disks[i] = -1; 1175 for (i = 0; i < vcp->vcp_nnics; i++) { 1176 vm->vm_ifs[i].vif_fd = -1; 1177 1178 if ((sw = switch_getbyname(vmc->vmc_ifswitch[i])) != NULL) { 1179 /* inherit per-interface flags from the switch */ 1180 vmc->vmc_ifflags[i] |= (sw->sw_flags & VMIFF_OPTMASK); 1181 } 1182 1183 /* 1184 * If the MAC address is zero, always randomize it in vmd(8) 1185 * because we cannot rely on the guest OS to do the right 1186 * thing like OpenBSD does. Based on ether_fakeaddr() 1187 * from the kernel, incremented by one to differentiate 1188 * the source. 1189 */ 1190 if (memcmp(zero_mac, &vcp->vcp_macs[i], ETHER_ADDR_LEN) == 0) { 1191 rng = arc4random(); 1192 vcp->vcp_macs[i][0] = 0xfe; 1193 vcp->vcp_macs[i][1] = 0xe1; 1194 vcp->vcp_macs[i][2] = 0xba + 1; 1195 vcp->vcp_macs[i][3] = 0xd0 | ((i + 1) & 0xf); 1196 vcp->vcp_macs[i][4] = rng; 1197 vcp->vcp_macs[i][5] = rng >> 8; 1198 } 1199 } 1200 vm->vm_kernel = -1; 1201 vm->vm_cdrom = -1; 1202 vm->vm_iev.ibuf.fd = -1; 1203 1204 if (++env->vmd_nvm == 0) 1205 fatalx("too many vms"); 1206 1207 /* Assign a new internal Id if not specified */ 1208 vm->vm_vmid = id == 0 ? env->vmd_nvm : id; 1209 1210 log_debug("%s: registering vm %d", __func__, vm->vm_vmid); 1211 TAILQ_INSERT_TAIL(env->vmd_vms, vm, vm_entry); 1212 1213 *ret_vm = vm; 1214 return (0); 1215 fail: 1216 if (errno == 0) 1217 errno = EINVAL; 1218 return (-1); 1219} 1220 1221/* 1222 * vm_checkperm 1223 * 1224 * Checks if the user represented by the 'uid' parameter is allowed to 1225 * manipulate the VM described by the 'vm' parameter (or connect to said VM's 1226 * console.) 1227 * 1228 * Parameters: 1229 * vm: the VM whose permission is to be checked 1230 * uid: the user ID of the user making the request 1231 * 1232 * Return values: 1233 * 0: the permission should be granted 1234 * -1: the permission check failed (also returned if vm == null) 1235 */ 1236int 1237vm_checkperm(struct vmd_vm *vm, uid_t uid) 1238{ 1239 struct group *gr; 1240 struct passwd *pw; 1241 char **grmem; 1242 1243 /* root has no restrictions */ 1244 if (uid == 0) 1245 return (0); 1246 1247 if (vm == NULL) 1248 return (-1); 1249 1250 /* check supplementary groups */ 1251 if (vm->vm_params.vmc_gid != -1 && 1252 (pw = getpwuid(uid)) != NULL && 1253 (gr = getgrgid(vm->vm_params.vmc_gid)) != NULL) { 1254 for (grmem = gr->gr_mem; *grmem; grmem++) 1255 if (strcmp(*grmem, pw->pw_name) == 0) 1256 return (0); 1257 } 1258 1259 /* check user */ 1260 if ((vm->vm_running && vm->vm_uid == uid) || 1261 (!vm->vm_running && vm->vm_params.vmc_uid == uid)) 1262 return (0); 1263 1264 return (-1); 1265} 1266 1267int 1268vm_opentty(struct vmd_vm *vm) 1269{ 1270 struct ptmget ptm; 1271 struct stat st; 1272 struct group *gr; 1273 uid_t uid; 1274 gid_t gid; 1275 mode_t mode; 1276 1277 /* 1278 * Open tty with pre-opened PTM fd 1279 */ 1280 if ((ioctl(env->vmd_ptmfd, PTMGET, &ptm) == -1)) 1281 return (-1); 1282 1283 vm->vm_tty = ptm.cfd; 1284 close(ptm.sfd); 1285 if ((vm->vm_ttyname = strdup(ptm.sn)) == NULL) 1286 goto fail; 1287 1288 uid = vm->vm_uid; 1289 gid = vm->vm_params.vmc_gid; 1290 1291 if (vm->vm_params.vmc_gid != -1) { 1292 mode = 0660; 1293 } else if ((gr = getgrnam("tty")) != NULL) { 1294 gid = gr->gr_gid; 1295 mode = 0620; 1296 } else { 1297 mode = 0600; 1298 gid = 0; 1299 } 1300 1301 log_debug("%s: vm %s tty %s uid %d gid %d mode %o", 1302 __func__, vm->vm_params.vmc_params.vcp_name, 1303 vm->vm_ttyname, uid, gid, mode); 1304 1305 /* 1306 * Change ownership and mode of the tty as required. 1307 * Loosely based on the implementation of sshpty.c 1308 */ 1309 if (stat(vm->vm_ttyname, &st) == -1) 1310 goto fail; 1311 1312 if (st.st_uid != uid || st.st_gid != gid) { 1313 if (chown(vm->vm_ttyname, uid, gid) == -1) { 1314 log_warn("chown %s %d %d failed, uid %d", 1315 vm->vm_ttyname, uid, gid, getuid()); 1316 1317 /* Ignore failure on read-only filesystems */ 1318 if (!((errno == EROFS) && 1319 (st.st_uid == uid || st.st_uid == 0))) 1320 goto fail; 1321 } 1322 } 1323 1324 if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) { 1325 if (chmod(vm->vm_ttyname, mode) == -1) { 1326 log_warn("chmod %s %o failed, uid %d", 1327 vm->vm_ttyname, mode, getuid()); 1328 1329 /* Ignore failure on read-only filesystems */ 1330 if (!((errno == EROFS) && 1331 (st.st_uid == uid || st.st_uid == 0))) 1332 goto fail; 1333 } 1334 } 1335 1336 return (0); 1337 fail: 1338 vm_closetty(vm); 1339 return (-1); 1340} 1341 1342void 1343vm_closetty(struct vmd_vm *vm) 1344{ 1345 if (vm->vm_tty != -1) { 1346 /* Release and close the tty */ 1347 if (fchown(vm->vm_tty, 0, 0) == -1) 1348 log_warn("chown %s 0 0 failed", vm->vm_ttyname); 1349 if (fchmod(vm->vm_tty, 0666) == -1) 1350 log_warn("chmod %s 0666 failed", vm->vm_ttyname); 1351 close(vm->vm_tty); 1352 vm->vm_tty = -1; 1353 } 1354 free(vm->vm_ttyname); 1355 vm->vm_ttyname = NULL; 1356} 1357 1358void 1359switch_remove(struct vmd_switch *vsw) 1360{ 1361 if (vsw == NULL) 1362 return; 1363 1364 TAILQ_REMOVE(env->vmd_switches, vsw, sw_entry); 1365 1366 free(vsw->sw_group); 1367 free(vsw->sw_name); 1368 free(vsw); 1369} 1370 1371struct vmd_switch * 1372switch_getbyname(const char *name) 1373{ 1374 struct vmd_switch *vsw; 1375 1376 if (name == NULL) 1377 return (NULL); 1378 TAILQ_FOREACH(vsw, env->vmd_switches, sw_entry) { 1379 if (strcmp(vsw->sw_name, name) == 0) 1380 return (vsw); 1381 } 1382 1383 return (NULL); 1384} 1385 1386char * 1387get_string(uint8_t *ptr, size_t len) 1388{ 1389 size_t i; 1390 1391 for (i = 0; i < len; i++) 1392 if (!isprint(ptr[i])) 1393 break; 1394 1395 return strndup(ptr, i); 1396} 1397 1398uint32_t 1399prefixlen2mask(uint8_t prefixlen) 1400{ 1401 if (prefixlen == 0) 1402 return (0); 1403 1404 if (prefixlen > 32) 1405 prefixlen = 32; 1406 1407 return (htonl(0xffffffff << (32 - prefixlen))); 1408} 1409