1 /* $OpenBSD: control.c,v 1.30 2018/12/04 08:15:09 claudio 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 * unix - for the control socket. 71 * recvfd - for the proc fd exchange. 72 * sendfd - for send and receive. 73 */ 74 if (pledge("stdio unix recvfd sendfd", NULL) == -1) 75 fatal("pledge"); 76 } 77 78 int 79 control_dispatch_vmd(int fd, struct privsep_proc *p, struct imsg *imsg) 80 { 81 struct ctl_conn *c; 82 struct privsep *ps = p->p_ps; 83 84 switch (imsg->hdr.type) { 85 case IMSG_VMDOP_START_VM_RESPONSE: 86 case IMSG_VMDOP_PAUSE_VM_RESPONSE: 87 case IMSG_VMDOP_SEND_VM_RESPONSE: 88 case IMSG_VMDOP_RECEIVE_VM_RESPONSE: 89 case IMSG_VMDOP_UNPAUSE_VM_RESPONSE: 90 case IMSG_VMDOP_TERMINATE_VM_RESPONSE: 91 case IMSG_VMDOP_GET_INFO_VM_DATA: 92 case IMSG_VMDOP_GET_INFO_VM_END_DATA: 93 case IMSG_CTL_FAIL: 94 case IMSG_CTL_OK: 95 if ((c = control_connbyfd(imsg->hdr.peerid)) == NULL) { 96 log_warnx("%s: lost control connection: fd %d", 97 __func__, imsg->hdr.peerid); 98 return (0); 99 } 100 imsg_compose_event(&c->iev, imsg->hdr.type, 101 0, 0, imsg->fd, imsg->data, IMSG_DATA_SIZE(imsg)); 102 break; 103 case IMSG_VMDOP_CONFIG: 104 config_getconfig(ps->ps_env, imsg); 105 proc_compose(ps, PROC_PARENT, IMSG_VMDOP_DONE, NULL, 0); 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 proc_compose(ps, PROC_PARENT, IMSG_VMDOP_DONE, NULL, 0); 174 175 return (0); 176 } 177 178 int 179 control_reset(struct control_sock *cs) 180 { 181 /* Updating owner of the control socket */ 182 if (chown(cs->cs_name, cs->cs_uid, cs->cs_gid) == -1) 183 return (-1); 184 185 return (0); 186 } 187 188 int 189 control_listen(struct control_sock *cs) 190 { 191 if (cs->cs_name == NULL) 192 return (0); 193 194 if (listen(cs->cs_fd, CONTROL_BACKLOG) == -1) { 195 log_warn("%s: listen", __func__); 196 return (-1); 197 } 198 199 event_set(&cs->cs_ev, cs->cs_fd, EV_READ, 200 control_accept, cs); 201 event_add(&cs->cs_ev, NULL); 202 evtimer_set(&cs->cs_evt, control_accept, cs); 203 204 return (0); 205 } 206 207 /* ARGSUSED */ 208 void 209 control_accept(int listenfd, short event, void *arg) 210 { 211 struct control_sock *cs = arg; 212 int connfd; 213 socklen_t len; 214 struct sockaddr_un sun; 215 struct ctl_conn *c; 216 217 event_add(&cs->cs_ev, NULL); 218 if ((event & EV_TIMEOUT)) 219 return; 220 221 len = sizeof(sun); 222 if ((connfd = accept4(listenfd, 223 (struct sockaddr *)&sun, &len, SOCK_NONBLOCK)) == -1) { 224 /* 225 * Pause accept if we are out of file descriptors, or 226 * libevent will haunt us here too. 227 */ 228 if (errno == ENFILE || errno == EMFILE) { 229 struct timeval evtpause = { 1, 0 }; 230 231 event_del(&cs->cs_ev); 232 evtimer_add(&cs->cs_evt, &evtpause); 233 } else if (errno != EWOULDBLOCK && errno != EINTR && 234 errno != ECONNABORTED) 235 log_warn("%s: accept", __func__); 236 return; 237 } 238 239 if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { 240 log_warn("%s", __func__); 241 close(connfd); 242 return; 243 } 244 245 if (getsockopt(connfd, SOL_SOCKET, SO_PEERCRED, 246 &c->peercred, &len) != 0) { 247 log_warn("%s: failed to get peer credentials", __func__); 248 close(connfd); 249 free(c); 250 return; 251 } 252 253 imsg_init(&c->iev.ibuf, connfd); 254 c->iev.handler = control_dispatch_imsg; 255 c->iev.events = EV_READ; 256 c->iev.data = cs; 257 event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, 258 c->iev.handler, c->iev.data); 259 event_add(&c->iev.ev, NULL); 260 261 TAILQ_INSERT_TAIL(&ctl_conns, c, entry); 262 } 263 264 struct ctl_conn * 265 control_connbyfd(int fd) 266 { 267 struct ctl_conn *c; 268 269 TAILQ_FOREACH(c, &ctl_conns, entry) { 270 if (c->iev.ibuf.fd == fd) 271 break; 272 } 273 274 return (c); 275 } 276 277 void 278 control_close(int fd, struct control_sock *cs) 279 { 280 struct ctl_conn *c; 281 282 if ((c = control_connbyfd(fd)) == NULL) { 283 log_warn("%s: fd %d: not found", __func__, fd); 284 return; 285 } 286 287 msgbuf_clear(&c->iev.ibuf.w); 288 TAILQ_REMOVE(&ctl_conns, c, entry); 289 290 event_del(&c->iev.ev); 291 close(c->iev.ibuf.fd); 292 293 /* Some file descriptors are available again. */ 294 if (evtimer_pending(&cs->cs_evt, NULL)) { 295 evtimer_del(&cs->cs_evt); 296 event_add(&cs->cs_ev, NULL); 297 } 298 299 free(c); 300 } 301 302 /* ARGSUSED */ 303 void 304 control_dispatch_imsg(int fd, short event, void *arg) 305 { 306 struct control_sock *cs = arg; 307 struct privsep *ps = cs->cs_env; 308 struct ctl_conn *c; 309 struct imsg imsg; 310 struct vmop_create_params vmc; 311 struct vmop_id vid; 312 int n, v, ret = 0; 313 314 if ((c = control_connbyfd(fd)) == NULL) { 315 log_warn("%s: fd %d: not found", __func__, fd); 316 return; 317 } 318 319 if (event & EV_READ) { 320 if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) || 321 n == 0) { 322 control_close(fd, cs); 323 return; 324 } 325 } 326 if (event & EV_WRITE) { 327 if (msgbuf_write(&c->iev.ibuf.w) <= 0 && errno != EAGAIN) { 328 control_close(fd, cs); 329 return; 330 } 331 } 332 333 for (;;) { 334 if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { 335 control_close(fd, cs); 336 return; 337 } 338 339 if (n == 0) 340 break; 341 342 switch (imsg.hdr.type) { 343 case IMSG_VMDOP_GET_INFO_VM_REQUEST: 344 case IMSG_VMDOP_WAIT_VM_REQUEST: 345 case IMSG_VMDOP_TERMINATE_VM_REQUEST: 346 case IMSG_VMDOP_START_VM_REQUEST: 347 case IMSG_VMDOP_PAUSE_VM: 348 case IMSG_VMDOP_UNPAUSE_VM: 349 break; 350 default: 351 if (c->peercred.uid != 0) { 352 log_warnx("denied request %d from uid %d", 353 imsg.hdr.type, c->peercred.uid); 354 ret = EPERM; 355 goto fail; 356 } 357 break; 358 } 359 360 control_imsg_forward(&imsg); 361 362 switch (imsg.hdr.type) { 363 case IMSG_CTL_NOTIFY: 364 if (c->flags & CTL_CONN_NOTIFY) { 365 log_debug("%s: " 366 "client requested notify more than once", 367 __func__); 368 ret = EINVAL; 369 goto fail; 370 } 371 c->flags |= CTL_CONN_NOTIFY; 372 break; 373 case IMSG_CTL_VERBOSE: 374 if (IMSG_DATA_SIZE(&imsg) < sizeof(v)) 375 goto fail; 376 memcpy(&v, imsg.data, sizeof(v)); 377 log_setverbose(v); 378 379 /* FALLTHROUGH */ 380 case IMSG_VMDOP_RECEIVE_VM_REQUEST: 381 case IMSG_VMDOP_SEND_VM_REQUEST: 382 case IMSG_VMDOP_LOAD: 383 case IMSG_VMDOP_RELOAD: 384 case IMSG_CTL_RESET: 385 if (proc_compose_imsg(ps, PROC_PARENT, -1, 386 imsg.hdr.type, fd, imsg.fd, 387 imsg.data, IMSG_DATA_SIZE(&imsg)) == -1) 388 goto fail; 389 break; 390 case IMSG_VMDOP_START_VM_REQUEST: 391 if (IMSG_DATA_SIZE(&imsg) < sizeof(vmc)) 392 goto fail; 393 memcpy(&vmc, imsg.data, sizeof(vmc)); 394 vmc.vmc_owner.uid = c->peercred.uid; 395 vmc.vmc_owner.gid = -1; 396 397 if (proc_compose_imsg(ps, PROC_PARENT, -1, 398 imsg.hdr.type, fd, -1, &vmc, sizeof(vmc)) == -1) { 399 control_close(fd, cs); 400 return; 401 } 402 break; 403 case IMSG_VMDOP_WAIT_VM_REQUEST: 404 case IMSG_VMDOP_TERMINATE_VM_REQUEST: 405 if (IMSG_DATA_SIZE(&imsg) < sizeof(vid)) 406 goto fail; 407 memcpy(&vid, imsg.data, sizeof(vid)); 408 vid.vid_uid = c->peercred.uid; 409 410 if (proc_compose_imsg(ps, PROC_PARENT, -1, 411 imsg.hdr.type, fd, -1, &vid, sizeof(vid)) == -1) { 412 log_debug("%s: proc_compose_imsg failed", 413 __func__); 414 control_close(fd, cs); 415 return; 416 } 417 break; 418 case IMSG_VMDOP_GET_INFO_VM_REQUEST: 419 if (IMSG_DATA_SIZE(&imsg) != 0) 420 goto fail; 421 if (proc_compose_imsg(ps, PROC_PARENT, -1, 422 imsg.hdr.type, fd, -1, NULL, 0) == -1) { 423 control_close(fd, cs); 424 return; 425 } 426 break; 427 case IMSG_VMDOP_PAUSE_VM: 428 case IMSG_VMDOP_UNPAUSE_VM: 429 if (IMSG_DATA_SIZE(&imsg) < sizeof(vid)) 430 goto fail; 431 memcpy(&vid, imsg.data, sizeof(vid)); 432 vid.vid_uid = c->peercred.uid; 433 log_debug("%s id: %d, name: %s, uid: %d", 434 __func__, vid.vid_id, vid.vid_name, 435 vid.vid_uid); 436 437 if (proc_compose_imsg(ps, PROC_PARENT, -1, 438 imsg.hdr.type, fd, imsg.fd, 439 &vid, sizeof(vid)) == -1) 440 goto fail; 441 break; 442 default: 443 log_debug("%s: error handling imsg %d", 444 __func__, imsg.hdr.type); 445 control_close(fd, cs); 446 break; 447 } 448 imsg_free(&imsg); 449 } 450 451 imsg_event_add(&c->iev); 452 return; 453 454 fail: 455 if (ret == 0) 456 ret = EINVAL; 457 imsg_compose_event(&c->iev, IMSG_CTL_FAIL, 458 0, 0, -1, &ret, sizeof(ret)); 459 imsg_flush(&c->iev.ibuf); 460 control_close(fd, cs); 461 } 462 463 void 464 control_imsg_forward(struct imsg *imsg) 465 { 466 struct ctl_conn *c; 467 468 TAILQ_FOREACH(c, &ctl_conns, entry) 469 if (c->flags & CTL_CONN_NOTIFY) 470 imsg_compose_event(&c->iev, imsg->hdr.type, 471 imsg->hdr.peerid, imsg->hdr.pid, -1, imsg->data, 472 imsg->hdr.len - IMSG_HEADER_SIZE); 473 } 474