1 /* $OpenBSD: control.c,v 1.22 2017/09/08 06:24:31 mlarkin Exp $ */ 2 3 /* 4 * Copyright (c) 2010-2015 Reyk Floeter <reyk@openbsd.org> 5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/param.h> /* nitems */ 21 #include <sys/queue.h> 22 #include <sys/stat.h> 23 #include <sys/socket.h> 24 #include <sys/un.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 <string.h> 34 #include <unistd.h> 35 #include <signal.h> 36 37 #include "proc.h" 38 #include "vmd.h" 39 40 #define CONTROL_BACKLOG 5 41 42 struct ctl_connlist ctl_conns; 43 44 void 45 control_accept(int, short, void *); 46 struct ctl_conn 47 *control_connbyfd(int); 48 void control_close(int, struct control_sock *); 49 void control_dispatch_imsg(int, short, void *); 50 int control_dispatch_vmd(int, struct privsep_proc *, struct imsg *); 51 void control_imsg_forward(struct imsg *); 52 void control_run(struct privsep *, struct privsep_proc *, void *); 53 54 static struct privsep_proc procs[] = { 55 { "parent", PROC_PARENT, control_dispatch_vmd } 56 }; 57 58 void 59 control(struct privsep *ps, struct privsep_proc *p) 60 { 61 proc_run(ps, p, procs, nitems(procs), control_run, NULL); 62 } 63 64 void 65 control_run(struct privsep *ps, struct privsep_proc *p, void *arg) 66 { 67 /* 68 * pledge in the control process: 69 * stdio - for malloc and basic I/O including events. 70 * cpath - for managing the control socket. 71 * unix - for the control socket. 72 * recvfd - for the proc fd exchange. 73 * sendfd - for send and receive. 74 */ 75 if (pledge("stdio cpath unix recvfd sendfd", NULL) == -1) 76 fatal("pledge"); 77 } 78 79 int 80 control_dispatch_vmd(int fd, struct privsep_proc *p, struct imsg *imsg) 81 { 82 struct ctl_conn *c; 83 struct privsep *ps = p->p_ps; 84 85 switch (imsg->hdr.type) { 86 case IMSG_VMDOP_START_VM_RESPONSE: 87 case IMSG_VMDOP_PAUSE_VM_RESPONSE: 88 case IMSG_VMDOP_SEND_VM_RESPONSE: 89 case IMSG_VMDOP_RECEIVE_VM_RESPONSE: 90 case IMSG_VMDOP_UNPAUSE_VM_RESPONSE: 91 case IMSG_VMDOP_TERMINATE_VM_RESPONSE: 92 case IMSG_VMDOP_GET_INFO_VM_DATA: 93 case IMSG_VMDOP_GET_INFO_VM_END_DATA: 94 case IMSG_CTL_FAIL: 95 case IMSG_CTL_OK: 96 if ((c = control_connbyfd(imsg->hdr.peerid)) == NULL) { 97 log_warnx("%s: lost control connection: fd %d", 98 __func__, imsg->hdr.peerid); 99 return (0); 100 } 101 imsg_compose_event(&c->iev, imsg->hdr.type, 102 0, 0, imsg->fd, imsg->data, IMSG_DATA_SIZE(imsg)); 103 break; 104 case IMSG_VMDOP_CONFIG: 105 config_getconfig(ps->ps_env, imsg); 106 break; 107 case IMSG_CTL_RESET: 108 config_getreset(ps->ps_env, imsg); 109 break; 110 default: 111 return (-1); 112 } 113 114 return (0); 115 } 116 117 int 118 control_init(struct privsep *ps, struct control_sock *cs) 119 { 120 struct sockaddr_un sun; 121 int fd; 122 mode_t old_umask, mode; 123 124 if (cs->cs_name == NULL) 125 return (0); 126 127 if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1) { 128 log_warn("%s: socket", __func__); 129 return (-1); 130 } 131 132 sun.sun_family = AF_UNIX; 133 if (strlcpy(sun.sun_path, cs->cs_name, 134 sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) { 135 log_warn("%s: %s name too long", __func__, cs->cs_name); 136 close(fd); 137 return (-1); 138 } 139 140 if (unlink(cs->cs_name) == -1) 141 if (errno != ENOENT) { 142 log_warn("%s: unlink %s", __func__, cs->cs_name); 143 close(fd); 144 return (-1); 145 } 146 147 if (cs->cs_restricted) { 148 old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH); 149 mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; 150 } else { 151 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 152 mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP; 153 } 154 155 if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 156 log_warn("%s: bind: %s", __func__, cs->cs_name); 157 close(fd); 158 (void)umask(old_umask); 159 return (-1); 160 } 161 (void)umask(old_umask); 162 163 if (chmod(cs->cs_name, mode) == -1) { 164 log_warn("%s: chmod", __func__); 165 close(fd); 166 (void)unlink(cs->cs_name); 167 return (-1); 168 } 169 170 cs->cs_fd = fd; 171 cs->cs_env = ps; 172 173 return (0); 174 } 175 176 int 177 control_listen(struct control_sock *cs) 178 { 179 if (cs->cs_name == NULL) 180 return (0); 181 182 if (listen(cs->cs_fd, CONTROL_BACKLOG) == -1) { 183 log_warn("%s: listen", __func__); 184 return (-1); 185 } 186 187 event_set(&cs->cs_ev, cs->cs_fd, EV_READ, 188 control_accept, cs); 189 event_add(&cs->cs_ev, NULL); 190 evtimer_set(&cs->cs_evt, control_accept, cs); 191 192 return (0); 193 } 194 195 void 196 control_cleanup(struct control_sock *cs) 197 { 198 if (cs->cs_name == NULL) 199 return; 200 event_del(&cs->cs_ev); 201 event_del(&cs->cs_evt); 202 } 203 204 /* ARGSUSED */ 205 void 206 control_accept(int listenfd, short event, void *arg) 207 { 208 struct control_sock *cs = arg; 209 int connfd; 210 socklen_t len; 211 struct sockaddr_un sun; 212 struct ctl_conn *c; 213 214 event_add(&cs->cs_ev, NULL); 215 if ((event & EV_TIMEOUT)) 216 return; 217 218 len = sizeof(sun); 219 if ((connfd = accept4(listenfd, 220 (struct sockaddr *)&sun, &len, SOCK_NONBLOCK)) == -1) { 221 /* 222 * Pause accept if we are out of file descriptors, or 223 * libevent will haunt us here too. 224 */ 225 if (errno == ENFILE || errno == EMFILE) { 226 struct timeval evtpause = { 1, 0 }; 227 228 event_del(&cs->cs_ev); 229 evtimer_add(&cs->cs_evt, &evtpause); 230 } else if (errno != EWOULDBLOCK && errno != EINTR && 231 errno != ECONNABORTED) 232 log_warn("%s: accept", __func__); 233 return; 234 } 235 236 if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { 237 log_warn("%s", __func__); 238 close(connfd); 239 return; 240 } 241 242 if (getsockopt(connfd, SOL_SOCKET, SO_PEERCRED, 243 &c->peercred, &len) != 0) { 244 log_warn("%s: failed to get peer credentials", __func__); 245 close(connfd); 246 free(c); 247 return; 248 } 249 250 imsg_init(&c->iev.ibuf, connfd); 251 c->iev.handler = control_dispatch_imsg; 252 c->iev.events = EV_READ; 253 c->iev.data = cs; 254 event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, 255 c->iev.handler, c->iev.data); 256 event_add(&c->iev.ev, NULL); 257 258 TAILQ_INSERT_TAIL(&ctl_conns, c, entry); 259 } 260 261 struct ctl_conn * 262 control_connbyfd(int fd) 263 { 264 struct ctl_conn *c; 265 266 TAILQ_FOREACH(c, &ctl_conns, entry) { 267 if (c->iev.ibuf.fd == fd) 268 break; 269 } 270 271 return (c); 272 } 273 274 void 275 control_close(int fd, struct control_sock *cs) 276 { 277 struct ctl_conn *c; 278 279 if ((c = control_connbyfd(fd)) == NULL) { 280 log_warn("%s: fd %d: not found", __func__, fd); 281 return; 282 } 283 284 msgbuf_clear(&c->iev.ibuf.w); 285 TAILQ_REMOVE(&ctl_conns, c, entry); 286 287 event_del(&c->iev.ev); 288 close(c->iev.ibuf.fd); 289 290 /* Some file descriptors are available again. */ 291 if (evtimer_pending(&cs->cs_evt, NULL)) { 292 evtimer_del(&cs->cs_evt); 293 event_add(&cs->cs_ev, NULL); 294 } 295 296 free(c); 297 } 298 299 /* ARGSUSED */ 300 void 301 control_dispatch_imsg(int fd, short event, void *arg) 302 { 303 struct control_sock *cs = arg; 304 struct privsep *ps = cs->cs_env; 305 struct ctl_conn *c; 306 struct imsg imsg; 307 struct vmop_create_params vmc; 308 struct vmop_id vid; 309 int n, v, ret = 0; 310 311 if ((c = control_connbyfd(fd)) == NULL) { 312 log_warn("%s: fd %d: not found", __func__, fd); 313 return; 314 } 315 316 if (event & EV_READ) { 317 if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) || 318 n == 0) { 319 control_close(fd, cs); 320 return; 321 } 322 } 323 if (event & EV_WRITE) { 324 if (msgbuf_write(&c->iev.ibuf.w) <= 0 && errno != EAGAIN) { 325 control_close(fd, cs); 326 return; 327 } 328 } 329 330 for (;;) { 331 if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { 332 control_close(fd, cs); 333 return; 334 } 335 336 if (n == 0) 337 break; 338 339 switch (imsg.hdr.type) { 340 case IMSG_VMDOP_GET_INFO_VM_REQUEST: 341 case IMSG_VMDOP_TERMINATE_VM_REQUEST: 342 case IMSG_VMDOP_START_VM_REQUEST: 343 break; 344 default: 345 if (c->peercred.uid != 0) { 346 log_warnx("denied request %d from uid %d", 347 imsg.hdr.type, c->peercred.uid); 348 ret = EPERM; 349 goto fail; 350 } 351 break; 352 } 353 354 control_imsg_forward(&imsg); 355 356 switch (imsg.hdr.type) { 357 case IMSG_CTL_NOTIFY: 358 if (c->flags & CTL_CONN_NOTIFY) { 359 log_debug("%s: " 360 "client requested notify more than once", 361 __func__); 362 ret = EINVAL; 363 goto fail; 364 } 365 c->flags |= CTL_CONN_NOTIFY; 366 break; 367 case IMSG_CTL_VERBOSE: 368 if (IMSG_DATA_SIZE(&imsg) < sizeof(v)) 369 goto fail; 370 memcpy(&v, imsg.data, sizeof(v)); 371 log_setverbose(v); 372 373 /* FALLTHROUGH */ 374 case IMSG_VMDOP_RECEIVE_VM_REQUEST: 375 case IMSG_VMDOP_SEND_VM_REQUEST: 376 case IMSG_VMDOP_PAUSE_VM: 377 case IMSG_VMDOP_UNPAUSE_VM: 378 case IMSG_VMDOP_LOAD: 379 case IMSG_VMDOP_RELOAD: 380 case IMSG_CTL_RESET: 381 if (proc_compose_imsg(ps, PROC_PARENT, -1, 382 imsg.hdr.type, fd, imsg.fd, 383 imsg.data, IMSG_DATA_SIZE(&imsg)) == -1) 384 goto fail; 385 break; 386 case IMSG_VMDOP_START_VM_REQUEST: 387 if (IMSG_DATA_SIZE(&imsg) < sizeof(vmc)) 388 goto fail; 389 memcpy(&vmc, imsg.data, sizeof(vmc)); 390 vmc.vmc_uid = c->peercred.uid; 391 vmc.vmc_gid = -1; 392 393 if (proc_compose_imsg(ps, PROC_PARENT, -1, 394 imsg.hdr.type, fd, -1, &vmc, sizeof(vmc)) == -1) { 395 control_close(fd, cs); 396 return; 397 } 398 break; 399 case IMSG_VMDOP_TERMINATE_VM_REQUEST: 400 if (IMSG_DATA_SIZE(&imsg) < sizeof(vid)) 401 goto fail; 402 memcpy(&vid, imsg.data, sizeof(vid)); 403 vid.vid_uid = c->peercred.uid; 404 log_debug("%s id: %d, name: %s, uid: %d", 405 __func__, vid.vid_id, vid.vid_name, 406 vid.vid_uid); 407 408 if (proc_compose_imsg(ps, PROC_PARENT, -1, 409 imsg.hdr.type, fd, -1, &vid, sizeof(vid)) == -1) { 410 log_debug("%s: proc_compose_imsg failed", 411 __func__); 412 control_close(fd, cs); 413 return; 414 } 415 break; 416 case IMSG_VMDOP_GET_INFO_VM_REQUEST: 417 if (IMSG_DATA_SIZE(&imsg) != 0) 418 goto fail; 419 if (proc_compose_imsg(ps, PROC_PARENT, -1, 420 imsg.hdr.type, fd, -1, NULL, 0) == -1) { 421 control_close(fd, cs); 422 return; 423 } 424 break; 425 default: 426 log_debug("%s: error handling imsg %d", 427 __func__, imsg.hdr.type); 428 control_close(fd, cs); 429 break; 430 } 431 imsg_free(&imsg); 432 } 433 434 imsg_event_add(&c->iev); 435 return; 436 437 fail: 438 if (ret == 0) 439 ret = EINVAL; 440 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 441 0, 0, -1, &ret, sizeof(ret)); 442 imsg_flush(&c->iev.ibuf); 443 control_close(fd, cs); 444 } 445 446 void 447 control_imsg_forward(struct imsg *imsg) 448 { 449 struct ctl_conn *c; 450 451 TAILQ_FOREACH(c, &ctl_conns, entry) 452 if (c->flags & CTL_CONN_NOTIFY) 453 imsg_compose_event(&c->iev, imsg->hdr.type, 454 imsg->hdr.peerid, imsg->hdr.pid, -1, imsg->data, 455 imsg->hdr.len - IMSG_HEADER_SIZE); 456 } 457