GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/vmd/vmd.c Lines: 0 704 0.0 %
Date: 2017-11-07 Branches: 0 501 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: vmd.c,v 1.69 2017/09/08 06:24:31 mlarkin 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
51
int	 main(int, char **);
52
int	 vmd_configure(void);
53
void	 vmd_sighdlr(int sig, short event, void *arg);
54
void	 vmd_shutdown(void);
55
int	 vmd_control_run(void);
56
int	 vmd_dispatch_control(int, struct privsep_proc *, struct imsg *);
57
int	 vmd_dispatch_vmm(int, struct privsep_proc *, struct imsg *);
58
int	 check_vmh(struct vm_dump_header *);
59
60
struct vmd	*env;
61
62
static 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 */
70
static struct privsep_proc *proc_priv = &procs[0];
71
static struct passwd proc_privpw;
72
73
int
74
vmd_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, vmc.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
292
int
293
vmd_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",
398
		    __func__, vmr.vmr_id);
399
		if ((vm = vm_getbyvmid(vmr.vmr_id)) == NULL)
400
			break;
401
		if (vmr.vmr_result == 0) {
402
			if (vm->vm_from_config) {
403
				log_debug("%s: about to stop vm id %d",
404
				    __func__, vm->vm_vmid);
405
				vm_stop(vm, 0);
406
			} else {
407
				log_debug("%s: about to remove vm %d",
408
				    __func__, vm->vm_vmid);
409
				vm_remove(vm);
410
			}
411
		} else if (vmr.vmr_result == EAGAIN) {
412
			/* Stop VM instance but keep the tty open */
413
			log_debug("%s: about to stop vm id %d with tty open",
414
			    __func__, vm->vm_vmid);
415
			vm_stop(vm, 1);
416
			config_setvm(ps, vm, (uint32_t)-1, 0);
417
		}
418
		break;
419
	case IMSG_VMDOP_GET_INFO_VM_DATA:
420
		IMSG_SIZE_CHECK(imsg, &vir);
421
		memcpy(&vir, imsg->data, sizeof(vir));
422
		if ((vm = vm_getbyvmid(vir.vir_info.vir_id)) != NULL) {
423
			memset(vir.vir_ttyname, 0, sizeof(vir.vir_ttyname));
424
			if (vm->vm_ttyname != NULL)
425
				strlcpy(vir.vir_ttyname, vm->vm_ttyname,
426
				    sizeof(vir.vir_ttyname));
427
			if (vm->vm_shutdown) {
428
				/* XXX there might be a nicer way */
429
				(void)strlcat(vir.vir_info.vir_name,
430
				    " - stopping",
431
				    sizeof(vir.vir_info.vir_name));
432
			}
433
			/* get the user id who started the vm */
434
			vir.vir_uid = vm->vm_uid;
435
			vir.vir_gid = vm->vm_params.vmc_gid;
436
		}
437
		if (proc_compose_imsg(ps, PROC_CONTROL, -1, imsg->hdr.type,
438
		    imsg->hdr.peerid, -1, &vir, sizeof(vir)) == -1) {
439
			log_debug("%s: GET_INFO_VM failed for vm %d, removing",
440
			    __func__, vm->vm_vmid);
441
			vm_remove(vm);
442
			return (-1);
443
		}
444
		break;
445
	case IMSG_VMDOP_GET_INFO_VM_END_DATA:
446
		/*
447
		 * PROC_VMM has responded with the *running* VMs, now we
448
		 * append the others. These use the special value 0 for their
449
		 * kernel id to indicate that they are not running.
450
		 */
451
		TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) {
452
			if (!vm->vm_running) {
453
				memset(&vir, 0, sizeof(vir));
454
				vir.vir_info.vir_id = vm->vm_vmid;
455
				strlcpy(vir.vir_info.vir_name,
456
				    vm->vm_params.vmc_params.vcp_name,
457
				    VMM_MAX_NAME_LEN);
458
				vir.vir_info.vir_memory_size =
459
				    vm->vm_params.vmc_params.vcp_memranges[0].vmr_size;
460
				vir.vir_info.vir_ncpus =
461
				    vm->vm_params.vmc_params.vcp_ncpus;
462
				/* get the configured user id for this vm */
463
				vir.vir_uid = vm->vm_params.vmc_uid;
464
				vir.vir_gid = vm->vm_params.vmc_gid;
465
				if (proc_compose_imsg(ps, PROC_CONTROL, -1,
466
				    IMSG_VMDOP_GET_INFO_VM_DATA,
467
				    imsg->hdr.peerid, -1, &vir,
468
				    sizeof(vir)) == -1) {
469
					log_debug("%s: GET_INFO_VM_END failed",
470
					    __func__);
471
					vm_remove(vm);
472
					return (-1);
473
				}
474
			}
475
		}
476
		IMSG_SIZE_CHECK(imsg, &res);
477
		proc_forward_imsg(ps, imsg, PROC_CONTROL, -1);
478
		break;
479
	default:
480
		return (-1);
481
	}
482
483
	return (0);
484
}
485
486
int
487
check_vmh(struct vm_dump_header *vmh) {
488
	int i;
489
	unsigned int code, leaf;
490
	unsigned int a, b, c, d;
491
492
493
	if (vmh->vmh_version != VM_DUMP_VERSION) {
494
		log_warnx("%s: incompatible dump version", __func__);
495
		return (-1);
496
	}
497
498
	for (i = 0; i < VM_DUMP_HEADER_CPUID_COUNT; i++) {
499
		code = vmh->vmh_cpuids[i].code;
500
		leaf = vmh->vmh_cpuids[i].leaf;
501
		if (leaf != 0x00) {
502
			log_debug("%s: invalid leaf 0x%x for code 0x%x",
503
			    __func__, leaf, code);
504
			return (-1);
505
		}
506
507
		switch(code) {
508
		case 0x00:
509
		CPUID_LEAF(code, leaf, a, b, c, d);
510
		if (vmh->vmh_cpuids[i].a > a) {
511
			log_debug("%s: incompatible cpuid level", __func__);
512
			return (-1);
513
		}
514
		if (!(vmh->vmh_cpuids[i].b == b &&
515
		    vmh->vmh_cpuids[i].c == c &&
516
		    vmh->vmh_cpuids[i].d == d)) {
517
			log_debug("%s: incompatible cpu brand", __func__);
518
			return (-1);
519
		}
520
		break;
521
522
		case 0x01:
523
		CPUID_LEAF(code, leaf, a, b, c, d);
524
		if ((vmh->vmh_cpuids[i].c & c & VMM_CPUIDECX_MASK) !=
525
		    (vmh->vmh_cpuids[i].c & VMM_CPUIDECX_MASK)) {
526
			log_debug("%s: incompatible cpu features "
527
			    "code: 0x%x leaf: 0x%x  reg: c", __func__,
528
			    code, leaf);
529
			return (-1);
530
		}
531
		if ((vmh->vmh_cpuids[i].d & d & VMM_CPUIDEDX_MASK) !=
532
		    (vmh->vmh_cpuids[i].d & VMM_CPUIDEDX_MASK)) {
533
			log_debug("%s: incompatible cpu features "
534
			    "code: 0x%x leaf: 0x%x  reg: d", __func__,
535
			    code, leaf);
536
			return (-1);
537
		}
538
		break;
539
540
		case 0x07:
541
		CPUID_LEAF(code, leaf, a, b, c, d);
542
		if ((vmh->vmh_cpuids[i].b & b & VMM_SEFF0EBX_MASK) !=
543
		    (vmh->vmh_cpuids[i].b & VMM_SEFF0EBX_MASK)) {
544
			log_debug("%s: incompatible cpu features "
545
			    "code: 0x%x leaf: 0x%x  reg: c", __func__,
546
			    code, leaf);
547
			return (-1);
548
		}
549
		if ((vmh->vmh_cpuids[i].c & c & VMM_SEFF0ECX_MASK) !=
550
		    (vmh->vmh_cpuids[i].c & VMM_SEFF0ECX_MASK)) {
551
			log_debug("%s: incompatible cpu features "
552
			    "code: 0x%x leaf: 0x%x  reg: d", __func__,
553
			    code, leaf);
554
			return (-1);
555
		}
556
		break;
557
558
		case 0x0d:
559
		CPUID_LEAF(code, leaf, a, b, c, d);
560
		if (vmh->vmh_cpuids[i].b > b) {
561
			log_debug("%s: incompatible cpu: insufficient "
562
			    "max save area for enabled XCR0 features",
563
			    __func__);
564
			return (-1);
565
		}
566
		if (vmh->vmh_cpuids[i].c > c) {
567
			log_debug("%s: incompatible cpu: insufficient "
568
			    "max save area for supported XCR0 features",
569
			    __func__);
570
			return (-1);
571
		}
572
		break;
573
574
		case 0x80000001:
575
		CPUID_LEAF(code, leaf, a, b, c, d);
576
		if ((vmh->vmh_cpuids[i].a & a) != vmh->vmh_cpuids[i].a) {
577
			log_debug("%s: incompatible cpu features "
578
			    "code: 0x%x leaf: 0x%x  reg: a", __func__,
579
			    code, leaf);
580
			return (-1);
581
		}
582
		if ((vmh->vmh_cpuids[i].c & c) != vmh->vmh_cpuids[i].c) {
583
			log_debug("%s: incompatible cpu features "
584
			    "code: 0x%x leaf: 0x%x  reg: c", __func__,
585
			    code, leaf);
586
			return (-1);
587
		}
588
		if ((vmh->vmh_cpuids[i].d & d) != vmh->vmh_cpuids[i].d) {
589
			log_debug("%s: incompatible cpu features "
590
			    "code: 0x%x leaf: 0x%x  reg: d", __func__,
591
			    code, leaf);
592
			return (-1);
593
		}
594
		break;
595
596
		default:
597
		log_debug("%s: unknown code 0x%x", __func__, code);
598
		return (-1);
599
		}
600
	}
601
602
	return (0);
603
}
604
605
void
606
vmd_sighdlr(int sig, short event, void *arg)
607
{
608
	if (privsep_process != PROC_PARENT)
609
		return;
610
	log_debug("%s: handling signal", __func__);
611
612
	switch (sig) {
613
	case SIGHUP:
614
		log_info("%s: reload requested with SIGHUP", __func__);
615
616
		/*
617
		 * This is safe because libevent uses async signal handlers
618
		 * that run in the event loop and not in signal context.
619
		 */
620
		(void)vmd_reload(0, NULL);
621
		break;
622
	case SIGPIPE:
623
		log_info("%s: ignoring SIGPIPE", __func__);
624
		break;
625
	case SIGUSR1:
626
		log_info("%s: ignoring SIGUSR1", __func__);
627
		break;
628
	case SIGTERM:
629
	case SIGINT:
630
		vmd_shutdown();
631
		break;
632
	default:
633
		fatalx("unexpected signal");
634
	}
635
}
636
637
__dead void
638
usage(void)
639
{
640
	extern char *__progname;
641
	fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n",
642
	    __progname);
643
	exit(1);
644
}
645
646
int
647
main(int argc, char **argv)
648
{
649
	struct privsep		*ps;
650
	int			 ch;
651
	const char		*conffile = VMD_CONF;
652
	enum privsep_procid	 proc_id = PROC_PARENT;
653
	int			 proc_instance = 0;
654
	const char		*errp, *title = NULL;
655
	int			 argc0 = argc;
656
657
	/* log to stderr until daemonized */
658
	log_init(1, LOG_DAEMON);
659
660
	if ((env = calloc(1, sizeof(*env))) == NULL)
661
		fatal("calloc: env");
662
663
	while ((ch = getopt(argc, argv, "D:P:I:df:vn")) != -1) {
664
		switch (ch) {
665
		case 'D':
666
			if (cmdline_symset(optarg) < 0)
667
				log_warnx("could not parse macro definition %s",
668
				    optarg);
669
			break;
670
		case 'd':
671
			env->vmd_debug = 2;
672
			break;
673
		case 'f':
674
			conffile = optarg;
675
			break;
676
		case 'v':
677
			env->vmd_verbose++;
678
			break;
679
		case 'n':
680
			env->vmd_noaction = 1;
681
			break;
682
		case 'P':
683
			title = optarg;
684
			proc_id = proc_getid(procs, nitems(procs), title);
685
			if (proc_id == PROC_MAX)
686
				fatalx("invalid process name");
687
			break;
688
		case 'I':
689
			proc_instance = strtonum(optarg, 0,
690
			    PROC_MAX_INSTANCES, &errp);
691
			if (errp)
692
				fatalx("invalid process instance");
693
			break;
694
		default:
695
			usage();
696
		}
697
	}
698
699
	argc -= optind;
700
	if (argc > 0)
701
		usage();
702
703
	if (env->vmd_noaction && !env->vmd_debug)
704
		env->vmd_debug = 1;
705
706
	/* check for root privileges */
707
	if (env->vmd_noaction == 0) {
708
		if (geteuid())
709
			fatalx("need root privileges");
710
	}
711
712
	ps = &env->vmd_ps;
713
	ps->ps_env = env;
714
	env->vmd_fd = -1;
715
716
	if (config_init(env) == -1)
717
		fatal("failed to initialize configuration");
718
719
	if ((ps->ps_pw = getpwnam(VMD_USER)) == NULL)
720
		fatal("unknown user %s", VMD_USER);
721
722
	/* First proc runs as root without pledge but in default chroot */
723
	proc_priv->p_pw = &proc_privpw; /* initialized to all 0 */
724
	proc_priv->p_chroot = ps->ps_pw->pw_dir; /* from VMD_USER */
725
726
	/* Open /dev/vmm */
727
	if (env->vmd_noaction == 0) {
728
		env->vmd_fd = open(VMM_NODE, O_RDWR);
729
		if (env->vmd_fd == -1)
730
			fatal("%s", VMM_NODE);
731
	}
732
733
	/* Configure the control socket */
734
	ps->ps_csock.cs_name = SOCKET_NAME;
735
	TAILQ_INIT(&ps->ps_rcsocks);
736
737
	/* Configuration will be parsed after forking the children */
738
	env->vmd_conffile = conffile;
739
740
	log_init(env->vmd_debug, LOG_DAEMON);
741
	log_setverbose(env->vmd_verbose);
742
743
	if (env->vmd_noaction)
744
		ps->ps_noaction = 1;
745
	ps->ps_instance = proc_instance;
746
	if (title != NULL)
747
		ps->ps_title[proc_id] = title;
748
749
	/* only the parent returns */
750
	proc_init(ps, procs, nitems(procs), argc0, argv, proc_id);
751
752
	log_procinit("parent");
753
	if (!env->vmd_debug && daemon(0, 0) == -1)
754
		fatal("can't daemonize");
755
756
	if (ps->ps_noaction == 0)
757
		log_info("startup");
758
759
	event_init();
760
761
	signal_set(&ps->ps_evsigint, SIGINT, vmd_sighdlr, ps);
762
	signal_set(&ps->ps_evsigterm, SIGTERM, vmd_sighdlr, ps);
763
	signal_set(&ps->ps_evsighup, SIGHUP, vmd_sighdlr, ps);
764
	signal_set(&ps->ps_evsigpipe, SIGPIPE, vmd_sighdlr, ps);
765
	signal_set(&ps->ps_evsigusr1, SIGUSR1, vmd_sighdlr, ps);
766
767
	signal_add(&ps->ps_evsigint, NULL);
768
	signal_add(&ps->ps_evsigterm, NULL);
769
	signal_add(&ps->ps_evsighup, NULL);
770
	signal_add(&ps->ps_evsigpipe, NULL);
771
	signal_add(&ps->ps_evsigusr1, NULL);
772
773
	if (!env->vmd_noaction)
774
		proc_connect(ps);
775
776
	if (vmd_configure() == -1)
777
		fatalx("configuration failed");
778
779
	event_dispatch();
780
781
	log_debug("parent exiting");
782
783
	return (0);
784
}
785
786
int
787
vmd_configure(void)
788
{
789
	struct vmd_vm		*vm;
790
	struct vmd_switch	*vsw;
791
792
	if ((env->vmd_ptmfd = open(PATH_PTMDEV, O_RDWR|O_CLOEXEC)) == -1)
793
		fatal("open %s", PATH_PTMDEV);
794
795
	/*
796
	 * pledge in the parent process:
797
	 * stdio - for malloc and basic I/O including events.
798
	 * rpath - for reload to open and read the configuration files.
799
	 * wpath - for opening disk images and tap devices.
800
	 * tty - for openpty.
801
	 * proc - run kill to terminate its children safely.
802
	 * sendfd - for disks, interfaces and other fds.
803
	 * recvfd - for send and receive.
804
	 * getpw - lookup user or group id by name.
805
	 * chown, fattr - change tty ownership
806
	 */
807
	if (pledge("stdio rpath wpath proc tty recvfd sendfd getpw"
808
	    " chown fattr", NULL) == -1)
809
		fatal("pledge");
810
811
	if (parse_config(env->vmd_conffile) == -1) {
812
		proc_kill(&env->vmd_ps);
813
		exit(1);
814
	}
815
816
	if (env->vmd_noaction) {
817
		fprintf(stderr, "configuration OK\n");
818
		proc_kill(&env->vmd_ps);
819
		exit(0);
820
	}
821
822
	TAILQ_FOREACH(vsw, env->vmd_switches, sw_entry) {
823
		if (vsw->sw_running)
824
			continue;
825
		if (vm_priv_brconfig(&env->vmd_ps, vsw) == -1) {
826
			log_warn("%s: failed to create switch %s",
827
			    __func__, vsw->sw_name);
828
			switch_remove(vsw);
829
			return (-1);
830
		}
831
	}
832
833
	TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) {
834
		if (vm->vm_disabled) {
835
			log_debug("%s: not creating vm %s (disabled)",
836
			    __func__,
837
			    vm->vm_params.vmc_params.vcp_name);
838
			continue;
839
		}
840
		if (config_setvm(&env->vmd_ps, vm, -1, 0) == -1)
841
			return (-1);
842
	}
843
844
	/* Send shared global configuration to all children */
845
	if (config_setconfig(env) == -1)
846
		return (-1);
847
848
	return (0);
849
}
850
851
int
852
vmd_reload(unsigned int reset, const char *filename)
853
{
854
	struct vmd_vm		*vm, *next_vm;
855
	struct vmd_switch	*vsw;
856
	int			 reload = 0;
857
858
	/* Switch back to the default config file */
859
	if (filename == NULL || *filename == '\0') {
860
		filename = env->vmd_conffile;
861
		reload = 1;
862
	}
863
864
	log_debug("%s: level %d config file %s", __func__, reset, filename);
865
866
	if (reset) {
867
		/* Purge the configuration */
868
		config_purge(env, reset);
869
		config_setreset(env, reset);
870
	} else {
871
		/*
872
		 * Load or reload the configuration.
873
		 *
874
		 * Reloading removes all non-running VMs before processing the
875
		 * config file, whereas loading only adds to the existing list
876
		 * of VMs.
877
		 */
878
879
		if (reload) {
880
			TAILQ_FOREACH_SAFE(vm, env->vmd_vms, vm_entry, next_vm) {
881
				if (vm->vm_running == 0) {
882
					log_debug("%s: calling vm_remove",
883
					    __func__);
884
					vm_remove(vm);
885
				}
886
			}
887
888
			/* Update shared global configuration in all children */
889
			if (config_setconfig(env) == -1)
890
				return (-1);
891
		}
892
893
		if (parse_config(filename) == -1) {
894
			log_debug("%s: failed to load config file %s",
895
			    __func__, filename);
896
			return (-1);
897
		}
898
899
		TAILQ_FOREACH(vsw, env->vmd_switches, sw_entry) {
900
			if (vsw->sw_running)
901
				continue;
902
			if (vm_priv_brconfig(&env->vmd_ps, vsw) == -1) {
903
				log_warn("%s: failed to create switch %s",
904
				    __func__, vsw->sw_name);
905
				switch_remove(vsw);
906
				return (-1);
907
			}
908
		}
909
910
		TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) {
911
			if (vm->vm_running == 0) {
912
				if (vm->vm_disabled) {
913
					log_debug("%s: not creating vm %s"
914
					    " (disabled)", __func__,
915
					    vm->vm_params.vmc_params.vcp_name);
916
					continue;
917
				}
918
				if (config_setvm(&env->vmd_ps, vm, -1, 0) == -1)
919
					return (-1);
920
			} else {
921
				log_debug("%s: not creating vm \"%s\": "
922
				    "(running)", __func__,
923
				    vm->vm_params.vmc_params.vcp_name);
924
			}
925
		}
926
	}
927
928
	return (0);
929
}
930
931
void
932
vmd_shutdown(void)
933
{
934
	struct vmd_vm *vm, *vm_next;
935
936
	log_debug("%s: performing shutdown", __func__);
937
	TAILQ_FOREACH_SAFE(vm, env->vmd_vms, vm_entry, vm_next) {
938
		vm_remove(vm);
939
	}
940
941
	proc_kill(&env->vmd_ps);
942
	free(env);
943
944
	log_warnx("parent terminating");
945
	exit(0);
946
}
947
948
struct vmd_vm *
949
vm_getbyvmid(uint32_t vmid)
950
{
951
	struct vmd_vm	*vm;
952
953
	if (vmid == 0)
954
		return (NULL);
955
	TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) {
956
		if (vm->vm_vmid == vmid)
957
			return (vm);
958
	}
959
960
	return (NULL);
961
}
962
963
struct vmd_vm *
964
vm_getbyid(uint32_t id)
965
{
966
	struct vmd_vm	*vm;
967
968
	if (id == 0)
969
		return (NULL);
970
	TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) {
971
		if (vm->vm_params.vmc_params.vcp_id == id)
972
			return (vm);
973
	}
974
975
	return (NULL);
976
}
977
978
uint32_t
979
vm_id2vmid(uint32_t id, struct vmd_vm *vm)
980
{
981
	if (vm == NULL && (vm = vm_getbyid(id)) == NULL)
982
		return (0);
983
	dprintf("%s: vmm id %u is vmid %u", __func__,
984
	    id, vm->vm_vmid);
985
	return (vm->vm_vmid);
986
}
987
988
uint32_t
989
vm_vmid2id(uint32_t vmid, struct vmd_vm *vm)
990
{
991
	if (vm == NULL && (vm = vm_getbyvmid(vmid)) == NULL)
992
		return (0);
993
	dprintf("%s: vmid %u is vmm id %u", __func__,
994
	    vmid, vm->vm_params.vmc_params.vcp_id);
995
	return (vm->vm_params.vmc_params.vcp_id);
996
}
997
998
struct vmd_vm *
999
vm_getbyname(const char *name)
1000
{
1001
	struct vmd_vm	*vm;
1002
1003
	if (name == NULL)
1004
		return (NULL);
1005
	TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) {
1006
		if (strcmp(vm->vm_params.vmc_params.vcp_name, name) == 0)
1007
			return (vm);
1008
	}
1009
1010
	return (NULL);
1011
}
1012
1013
struct vmd_vm *
1014
vm_getbypid(pid_t pid)
1015
{
1016
	struct vmd_vm	*vm;
1017
1018
	TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) {
1019
		if (vm->vm_pid == pid)
1020
			return (vm);
1021
	}
1022
1023
	return (NULL);
1024
}
1025
1026
void
1027
vm_stop(struct vmd_vm *vm, int keeptty)
1028
{
1029
	unsigned int	 i;
1030
1031
	if (vm == NULL)
1032
		return;
1033
1034
	log_debug("%s: stopping vm %d", __func__, vm->vm_vmid);
1035
	vm->vm_running = 0;
1036
	vm->vm_shutdown = 0;
1037
1038
	if (vm->vm_iev.ibuf.fd != -1) {
1039
		event_del(&vm->vm_iev.ev);
1040
		close(vm->vm_iev.ibuf.fd);
1041
	}
1042
	for (i = 0; i < VMM_MAX_DISKS_PER_VM; i++) {
1043
		if (vm->vm_disks[i] != -1) {
1044
			close(vm->vm_disks[i]);
1045
			vm->vm_disks[i] = -1;
1046
		}
1047
	}
1048
	for (i = 0; i < VMM_MAX_NICS_PER_VM; i++) {
1049
		if (vm->vm_ifs[i].vif_fd != -1) {
1050
			close(vm->vm_ifs[i].vif_fd);
1051
			vm->vm_ifs[i].vif_fd = -1;
1052
		}
1053
		free(vm->vm_ifs[i].vif_name);
1054
		free(vm->vm_ifs[i].vif_switch);
1055
		free(vm->vm_ifs[i].vif_group);
1056
		vm->vm_ifs[i].vif_name = NULL;
1057
		vm->vm_ifs[i].vif_switch = NULL;
1058
		vm->vm_ifs[i].vif_group = NULL;
1059
	}
1060
	if (vm->vm_kernel != -1) {
1061
		close(vm->vm_kernel);
1062
		vm->vm_kernel = -1;
1063
	}
1064
	vm->vm_uid = 0;
1065
	if (!keeptty)
1066
		vm_closetty(vm);
1067
}
1068
1069
void
1070
vm_remove(struct vmd_vm *vm)
1071
{
1072
	if (vm == NULL)
1073
		return;
1074
1075
	log_debug("%s: removing vm id %d from running config",
1076
	    __func__, vm->vm_vmid);
1077
	TAILQ_REMOVE(env->vmd_vms, vm, vm_entry);
1078
	log_debug("%s: calling vm_stop", __func__);
1079
	vm_stop(vm, 0);
1080
	free(vm);
1081
}
1082
1083
int
1084
vm_register(struct privsep *ps, struct vmop_create_params *vmc,
1085
    struct vmd_vm **ret_vm, uint32_t id, uid_t uid)
1086
{
1087
	struct vmd_vm		*vm = NULL;
1088
	struct vm_create_params	*vcp = &vmc->vmc_params;
1089
	static const uint8_t	 zero_mac[ETHER_ADDR_LEN];
1090
	uint32_t		 rng;
1091
	unsigned int		 i;
1092
	struct vmd_switch	*sw;
1093
	char			*s;
1094
1095
	errno = 0;
1096
	*ret_vm = NULL;
1097
1098
	if ((vm = vm_getbyname(vcp->vcp_name)) != NULL ||
1099
	    (vm = vm_getbyvmid(vcp->vcp_id)) != NULL) {
1100
		if (vm_checkperm(vm, uid) != 0 || vmc->vmc_flags != 0) {
1101
			errno = EPERM;
1102
			goto fail;
1103
		}
1104
		*ret_vm = vm;
1105
		errno = EALREADY;
1106
		goto fail;
1107
	}
1108
1109
	/*
1110
	 * non-root users can only start existing VMs
1111
	 * XXX there could be a mechanism to allow overriding some options
1112
	 */
1113
	if (vm_checkperm(NULL, uid) != 0) {
1114
		errno = EPERM;
1115
		goto fail;
1116
	}
1117
	if (vmc->vmc_flags == 0) {
1118
		errno = ENOENT;
1119
		goto fail;
1120
	}
1121
	if (vcp->vcp_ncpus == 0)
1122
		vcp->vcp_ncpus = 1;
1123
	if (vcp->vcp_memranges[0].vmr_size == 0)
1124
		vcp->vcp_memranges[0].vmr_size = VM_DEFAULT_MEMORY;
1125
	if (vcp->vcp_ncpus > VMM_MAX_VCPUS_PER_VM) {
1126
		log_warnx("invalid number of CPUs");
1127
		goto fail;
1128
	} else if (vcp->vcp_ndisks > VMM_MAX_DISKS_PER_VM) {
1129
		log_warnx("invalid number of disks");
1130
		goto fail;
1131
	} else if (vcp->vcp_nnics > VMM_MAX_NICS_PER_VM) {
1132
		log_warnx("invalid number of interfaces");
1133
		goto fail;
1134
	} else if (strlen(vcp->vcp_kernel) == 0 && vcp->vcp_ndisks == 0) {
1135
		log_warnx("no kernel or disk specified");
1136
		goto fail;
1137
	} else if (strlen(vcp->vcp_name) == 0) {
1138
		log_warnx("invalid VM name");
1139
		goto fail;
1140
	} else if (*vcp->vcp_name == '-' || *vcp->vcp_name == '.' ||
1141
		   *vcp->vcp_name == '_') {
1142
		log_warnx("Invalid VM name");
1143
		goto fail;
1144
	} else {
1145
		for (s = vcp->vcp_name; *s != '\0'; ++s) {
1146
			if (!(isalnum(*s) || *s == '.' || *s == '-' ||
1147
			      *s == '_')) {
1148
				log_warnx("Invalid VM name");
1149
				goto fail;
1150
			}
1151
		}
1152
	}
1153
1154
	if ((vm = calloc(1, sizeof(*vm))) == NULL)
1155
		goto fail;
1156
1157
	memcpy(&vm->vm_params, vmc, sizeof(vm->vm_params));
1158
	vmc = &vm->vm_params;
1159
	vcp = &vmc->vmc_params;
1160
	vm->vm_pid = -1;
1161
	vm->vm_tty = -1;
1162
	vm->vm_receive_fd = -1;
1163
	vm->vm_paused = 0;
1164
1165
	for (i = 0; i < vcp->vcp_ndisks; i++)
1166
		vm->vm_disks[i] = -1;
1167
	for (i = 0; i < vcp->vcp_nnics; i++) {
1168
		vm->vm_ifs[i].vif_fd = -1;
1169
1170
		if ((sw = switch_getbyname(vmc->vmc_ifswitch[i])) != NULL) {
1171
			/* overwrite the rdomain, if configured on the switch */
1172
			if (sw->sw_flags & VMIFF_RDOMAIN)
1173
				vmc->vmc_ifrdomain[i] = sw->sw_rdomain;
1174
1175
			/* inherit per-interface flags from the switch */
1176
			vmc->vmc_ifflags[i] |= (sw->sw_flags & VMIFF_OPTMASK);
1177
		}
1178
1179
		/*
1180
		 * If the MAC address is zero, always randomize it in vmd(8)
1181
		 * because we cannot rely on the guest OS to do the right
1182
		 * thing like OpenBSD does.  Based on ether_fakeaddr()
1183
		 * from the kernel, incremented by one to differentiate
1184
		 * the source.
1185
		 */
1186
		if (memcmp(zero_mac, &vcp->vcp_macs[i], ETHER_ADDR_LEN) == 0) {
1187
			rng = arc4random();
1188
			vcp->vcp_macs[i][0] = 0xfe;
1189
			vcp->vcp_macs[i][1] = 0xe1;
1190
			vcp->vcp_macs[i][2] = 0xba + 1;
1191
			vcp->vcp_macs[i][3] = 0xd0 | ((i + 1) & 0xf);
1192
			vcp->vcp_macs[i][4] = rng;
1193
			vcp->vcp_macs[i][5] = rng >> 8;
1194
		}
1195
	}
1196
	vm->vm_kernel = -1;
1197
	vm->vm_iev.ibuf.fd = -1;
1198
1199
	if (++env->vmd_nvm == 0)
1200
		fatalx("too many vms");
1201
1202
	/* Assign a new internal Id if not specified */
1203
	vm->vm_vmid = id == 0 ? env->vmd_nvm : id;
1204
1205
	log_debug("%s: registering vm %d", __func__, vm->vm_vmid);
1206
	TAILQ_INSERT_TAIL(env->vmd_vms, vm, vm_entry);
1207
1208
	*ret_vm = vm;
1209
	return (0);
1210
 fail:
1211
	if (errno == 0)
1212
		errno = EINVAL;
1213
	return (-1);
1214
}
1215
1216
int
1217
vm_checkperm(struct vmd_vm *vm, uid_t uid)
1218
{
1219
	struct group	*gr;
1220
	struct passwd	*pw;
1221
	char		**grmem;
1222
1223
	/* root has no restrictions */
1224
	if (uid == 0)
1225
		return (0);
1226
1227
	if (vm == NULL)
1228
		return (-1);
1229
1230
	/* check supplementary groups */
1231
	if (vm->vm_params.vmc_gid != -1 &&
1232
	    (pw = getpwuid(uid)) != NULL &&
1233
	    (gr = getgrgid(vm->vm_params.vmc_gid)) != NULL) {
1234
		for (grmem = gr->gr_mem; *grmem; grmem++)
1235
			if (strcmp(*grmem, pw->pw_name) == 0)
1236
				return (0);
1237
	}
1238
1239
	/* check user */
1240
	if ((vm->vm_running && vm->vm_uid == uid) ||
1241
	    (!vm->vm_running && vm->vm_params.vmc_uid == uid))
1242
		return (0);
1243
1244
	return (-1);
1245
}
1246
1247
int
1248
vm_opentty(struct vmd_vm *vm)
1249
{
1250
	struct ptmget		 ptm;
1251
	struct stat		 st;
1252
	struct group		*gr;
1253
	uid_t			 uid;
1254
	gid_t			 gid;
1255
	mode_t			 mode;
1256
1257
	/*
1258
	 * Open tty with pre-opened PTM fd
1259
	 */
1260
	if ((ioctl(env->vmd_ptmfd, PTMGET, &ptm) == -1))
1261
		return (-1);
1262
1263
	vm->vm_tty = ptm.cfd;
1264
	close(ptm.sfd);
1265
	if ((vm->vm_ttyname = strdup(ptm.sn)) == NULL)
1266
		goto fail;
1267
1268
	uid = vm->vm_uid;
1269
	gid = vm->vm_params.vmc_gid;
1270
1271
	if (vm->vm_params.vmc_gid != -1) {
1272
		mode = 0660;
1273
	} else if ((gr = getgrnam("tty")) != NULL) {
1274
		gid = gr->gr_gid;
1275
		mode = 0620;
1276
	} else {
1277
		mode = 0600;
1278
		gid = 0;
1279
	}
1280
1281
	log_debug("%s: vm %s tty %s uid %d gid %d mode %o",
1282
	    __func__, vm->vm_params.vmc_params.vcp_name,
1283
	    vm->vm_ttyname, uid, gid, mode);
1284
1285
	/*
1286
	 * Change ownership and mode of the tty as required.
1287
	 * Loosely based on the implementation of sshpty.c
1288
	 */
1289
	if (stat(vm->vm_ttyname, &st) == -1)
1290
		goto fail;
1291
1292
	if (st.st_uid != uid || st.st_gid != gid) {
1293
		if (chown(vm->vm_ttyname, uid, gid) == -1) {
1294
			log_warn("chown %s %d %d failed, uid %d",
1295
			    vm->vm_ttyname, uid, gid, getuid());
1296
1297
			/* Ignore failure on read-only filesystems */
1298
			if (!((errno == EROFS) &&
1299
			    (st.st_uid == uid || st.st_uid == 0)))
1300
				goto fail;
1301
		}
1302
	}
1303
1304
	if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) {
1305
		if (chmod(vm->vm_ttyname, mode) == -1) {
1306
			log_warn("chmod %s %o failed, uid %d",
1307
			    vm->vm_ttyname, mode, getuid());
1308
1309
			/* Ignore failure on read-only filesystems */
1310
			if (!((errno == EROFS) &&
1311
			    (st.st_uid == uid || st.st_uid == 0)))
1312
				goto fail;
1313
		}
1314
	}
1315
1316
	return (0);
1317
 fail:
1318
	vm_closetty(vm);
1319
	return (-1);
1320
}
1321
1322
void
1323
vm_closetty(struct vmd_vm *vm)
1324
{
1325
	if (vm->vm_tty != -1) {
1326
		/* Release and close the tty */
1327
		if (fchown(vm->vm_tty, 0, 0) == -1)
1328
			log_warn("chown %s 0 0 failed", vm->vm_ttyname);
1329
		if (fchmod(vm->vm_tty, 0666) == -1)
1330
			log_warn("chmod %s 0666 failed", vm->vm_ttyname);
1331
		close(vm->vm_tty);
1332
		vm->vm_tty = -1;
1333
	}
1334
	free(vm->vm_ttyname);
1335
	vm->vm_ttyname = NULL;
1336
}
1337
1338
void
1339
switch_remove(struct vmd_switch *vsw)
1340
{
1341
	struct vmd_if	*vif;
1342
1343
	if (vsw == NULL)
1344
		return;
1345
1346
	TAILQ_REMOVE(env->vmd_switches, vsw, sw_entry);
1347
1348
	while ((vif = TAILQ_FIRST(&vsw->sw_ifs)) != NULL) {
1349
		free(vif->vif_name);
1350
		free(vif->vif_switch);
1351
		TAILQ_REMOVE(&vsw->sw_ifs, vif, vif_entry);
1352
		free(vif);
1353
	}
1354
1355
	free(vsw->sw_group);
1356
	free(vsw->sw_name);
1357
	free(vsw);
1358
}
1359
1360
struct vmd_switch *
1361
switch_getbyname(const char *name)
1362
{
1363
	struct vmd_switch	*vsw;
1364
1365
	if (name == NULL)
1366
		return (NULL);
1367
	TAILQ_FOREACH(vsw, env->vmd_switches, sw_entry) {
1368
		if (strcmp(vsw->sw_name, name) == 0)
1369
			return (vsw);
1370
	}
1371
1372
	return (NULL);
1373
}
1374
1375
char *
1376
get_string(uint8_t *ptr, size_t len)
1377
{
1378
	size_t	 i;
1379
1380
	for (i = 0; i < len; i++)
1381
		if (!isprint(ptr[i]))
1382
			break;
1383
1384
	return strndup(ptr, i);
1385
}
1386
1387
uint32_t
1388
prefixlen2mask(uint8_t prefixlen)
1389
{
1390
	if (prefixlen == 0)
1391
		return (0);
1392
1393
	if (prefixlen > 32)
1394
		prefixlen = 32;
1395
1396
	return (htonl(0xffffffff << (32 - prefixlen)));
1397
}