diff options
| -rw-r--r-- | usr.sbin/vmd/config.c | 36 | ||||
| -rw-r--r-- | usr.sbin/vmd/vmd.c | 13 | ||||
| -rw-r--r-- | usr.sbin/vmd/vmd.h | 11 |
3 files changed, 57 insertions, 3 deletions
diff --git a/usr.sbin/vmd/config.c b/usr.sbin/vmd/config.c index eb1aa3a91df..373e027b425 100644 --- a/usr.sbin/vmd/config.c +++ b/usr.sbin/vmd/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.51 2018/10/08 16:32:01 reyk Exp $ */ +/* $OpenBSD: config.c,v 1.52 2018/10/15 10:35:41 reyk Exp $ */ /* * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org> @@ -193,6 +193,7 @@ config_setvm(struct privsep *ps, struct vmd_vm *vm, uint32_t peerid, uid_t uid) char base[PATH_MAX]; char expanded[PATH_MAX]; unsigned int unit; + struct timeval tv, rate, since_last; errno = 0; @@ -211,6 +212,39 @@ config_setvm(struct privsep *ps, struct vmd_vm *vm, uint32_t peerid, uid_t uid) } } + /* + * Rate-limit the VM so that it cannot restart in a loop: + * if the VM restarts after less than VM_START_RATE_SEC seconds, + * we increment the limit counter. After VM_START_RATE_LIMIT + * of suchs fast reboots the VM is stopped. + */ + getmonotime(&tv); + if (vm->vm_start_tv.tv_sec) { + timersub(&tv, &vm->vm_start_tv, &since_last); + + rate.tv_sec = VM_START_RATE_SEC; + rate.tv_usec = 0; + if (timercmp(&since_last, &rate, <)) + vm->vm_start_limit++; + else { + /* Reset counter */ + vm->vm_start_limit = 0; + } + + log_debug("%s: vm %u restarted after %lld.%ld seconds," + " limit %d/%d", __func__, vcp->vcp_id, since_last.tv_sec, + since_last.tv_usec, vm->vm_start_limit, + VM_START_RATE_LIMIT); + + if (vm->vm_start_limit >= VM_START_RATE_LIMIT) { + log_warnx("%s: vm %u restarted too quickly", + __func__, vcp->vcp_id); + errno = EPERM; + goto fail; + } + } + vm->vm_start_tv = tv; + for (i = 0; i < VMM_MAX_DISKS_PER_VM; i++) for (j = 0; j < VM_MAX_BASE_PER_DISK; j++) diskfds[i][j] = -1; diff --git a/usr.sbin/vmd/vmd.c b/usr.sbin/vmd/vmd.c index 057b67770c9..8053b02620f 100644 --- a/usr.sbin/vmd/vmd.c +++ b/usr.sbin/vmd/vmd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmd.c,v 1.103 2018/10/08 16:32:01 reyk Exp $ */ +/* $OpenBSD: vmd.c,v 1.104 2018/10/15 10:35:41 reyk Exp $ */ /* * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org> @@ -1921,3 +1921,14 @@ prefixlen2mask(uint8_t prefixlen) return (htonl(0xffffffff << (32 - prefixlen))); } + +void +getmonotime(struct timeval *tv) +{ + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts)) + fatal("clock_gettime"); + + TIMESPEC_TO_TIMEVAL(tv, &ts); +} diff --git a/usr.sbin/vmd/vmd.h b/usr.sbin/vmd/vmd.h index 391b042f2f8..4d7b0380294 100644 --- a/usr.sbin/vmd/vmd.h +++ b/usr.sbin/vmd/vmd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vmd.h,v 1.82 2018/10/08 16:32:01 reyk Exp $ */ +/* $OpenBSD: vmd.h,v 1.83 2018/10/15 10:35:41 reyk Exp $ */ /* * Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org> @@ -55,6 +55,10 @@ #define VMD_SWITCH_TYPE "bridge" #define VM_DEFAULT_MEMORY 512 +/* Rate-limit fast reboots */ +#define VM_START_RATE_SEC 6 /* min. seconds since last reboot */ +#define VM_START_RATE_LIMIT 3 /* max. number of fast reboots */ + /* default user instance limits */ #define VM_DEFAULT_USER_MAXCPU 4 #define VM_DEFAULT_USER_MAXMEM 2048 @@ -261,6 +265,10 @@ struct vmd_vm { int vm_receive_fd; struct vmd_user *vm_user; + /* For rate-limiting */ + struct timeval vm_start_tv; + int vm_start_limit; + TAILQ_ENTRY(vmd_vm) vm_entry; }; TAILQ_HEAD(vmlist, vmd_vm); @@ -364,6 +372,7 @@ void user_inc(struct vm_create_params *, struct vmd_user *, int); int user_checklimit(struct vmd_user *, struct vm_create_params *); char *get_string(uint8_t *, size_t); uint32_t prefixlen2mask(uint8_t); +void getmonotime(struct timeval *); /* priv.c */ void priv(struct privsep *, struct privsep_proc *); |
