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