summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/vmd/config.c36
-rw-r--r--usr.sbin/vmd/vmd.c13
-rw-r--r--usr.sbin/vmd/vmd.h11
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 *);