priv.c revision 1.1
1/*	$OpenBSD: priv.c,v 1.1 2016/10/04 17:17:30 reyk Exp $	*/
2
3/*
4 * Copyright (c) 2016 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/stat.h>
22#include <sys/socket.h>
23#include <sys/un.h>
24#include <sys/ioctl.h>
25#include <sys/tree.h>
26
27#include <net/if.h>
28
29#include <errno.h>
30#include <event.h>
31#include <fcntl.h>
32#include <stdlib.h>
33#include <stdio.h>
34#include <string.h>
35#include <unistd.h>
36#include <signal.h>
37
38#include "proc.h"
39#include "vmd.h"
40
41int	 priv_dispatch_parent(int, struct privsep_proc *, struct imsg *);
42void	 priv_run(struct privsep *, struct privsep_proc *, void *);
43
44int	 priv_getiftype(char *, char *, unsigned int *);
45int	 priv_findname(const char *, const char **);
46
47static struct privsep_proc procs[] = {
48	{ "parent",	PROC_PARENT,	priv_dispatch_parent }
49};
50
51void
52priv(struct privsep *ps, struct privsep_proc *p)
53{
54	proc_run(ps, p, procs, nitems(procs), priv_run, NULL);
55}
56
57void
58priv_run(struct privsep *ps, struct privsep_proc *p, void *arg)
59{
60	struct vmd		*env = ps->ps_env;
61
62	/*
63	 * no pledge(2) in the "priv" process:
64	 * write ioctls are not permitted by pledge.
65	 */
66
67	/* Open our own socket for generic interface ioctls */
68	if ((env->vmd_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
69		fatal("socket");
70}
71
72int
73priv_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
74{
75	const char		*desct[] = { "tap", "switch", "bridge", NULL };
76	struct privsep		*ps = p->p_ps;
77	struct vmop_ifreq	 vfr;
78	struct vmd		*env = ps->ps_env;
79	struct ifreq		 ifr;
80	char			 type[IF_NAMESIZE];
81	unsigned int		 unit;
82
83	switch (imsg->hdr.type) {
84	case IMSG_VMDOP_PRIV_IFDESCR:
85		IMSG_SIZE_CHECK(imsg, &vfr);
86		memcpy(&vfr, imsg->data, sizeof(vfr));
87
88		/* We should not get malicious requests from the parent */
89		if (priv_getiftype(vfr.vfr_name, type, &unit) == -1 ||
90		    priv_findname(type, desct) == -1)
91			fatalx("%s: rejected priv operation on interface: %s",
92			    __func__, vfr.vfr_name);
93
94		strlcpy(ifr.ifr_name, vfr.vfr_name, sizeof(ifr.ifr_name));
95		ifr.ifr_data = (caddr_t)vfr.vfr_value;
96		if (ioctl(env->vmd_fd, SIOCSIFDESCR, &ifr) < 0)
97			log_warn("SIOCSIFDESCR");
98		break;
99	default:
100		return (-1);
101	}
102
103	return (0);
104}
105
106int
107priv_getiftype(char *ifname, char *type, unsigned int *unitptr)
108{
109	const char	*errstr;
110	size_t		 span;
111	unsigned int	 unit;
112
113	/* Extract the name part */
114	span = strcspn(ifname, "0123456789");
115	if (span == 0 || span >= strlen(ifname) || span >= (IF_NAMESIZE - 1))
116		return (-1);
117	memcpy(type, ifname, span);
118	type[span] = 0;
119
120	/* Now parse the unit (we don't strictly validate the format here) */
121	unit = strtonum(ifname + span, 0, UINT_MAX, &errstr);
122	if (errstr != NULL)
123		return (-1);
124	if (unitptr != NULL)
125		*unitptr = unit;
126
127	return (0);
128}
129
130int
131priv_findname(const char *name, const char **names)
132{
133	unsigned int	 i;
134
135	for (i = 0; names[i] != NULL; i++) {
136		if (strcmp(name, names[i]) == 0)
137			return (0);
138	}
139
140	return (-1);
141}
142
143/*
144 * Called from the process peer
145 */
146
147int
148vm_priv_ifconfig(struct privsep *ps, struct vmd_vm *vm)
149{
150	struct vm_create_params	*vcp = &vm->vm_params;
151	unsigned int		 i;
152	struct vmop_ifreq	 vfr;
153
154	for (i = 0; i < VMM_MAX_NICS_PER_VM; i++) {
155		if (vm->vm_ifnames[i] == NULL)
156			break;
157
158		if (strlcpy(vfr.vfr_name, vm->vm_ifnames[i],
159		    sizeof(vfr.vfr_name)) >= sizeof(vfr.vfr_name))
160			return (-1);
161
162		/* Description can be truncated */
163		(void)snprintf(vfr.vfr_value, sizeof(vfr.vfr_value),
164		    "vm%u-if%u-%s", vm->vm_vmid, i, vcp->vcp_name);
165
166		proc_compose(ps, PROC_PRIV, IMSG_VMDOP_PRIV_IFDESCR,
167		    &vfr, sizeof(vfr));
168
169		/* XXX Add interface to bridge/switch */
170	}
171
172	return (0);
173}
174