1
0
mirror of https://git.FreeBSD.org/src.git synced 2026-06-02 11:24:32 +00:00

kern: Introduce RLIMIT_VMM

This change introduces a new per-UID limit for controlling the
number of vmm instances, in anticipation of unprivileged bhyve.
This allows ut to limit the amount of kernel memory allocated
by the vmm driver and prevent potential memory exhaustion attacks.

Differential Revision:	https://reviews.freebsd.org/D53728
Reviewed by:	markj, olce, corvink
MFC after:	3 months
Sponsored by:	The FreeBSD Foundation
Sponsored by:	Klara, Inc.
This commit is contained in:
Bojan Novković
2025-11-07 14:11:03 +01:00
parent 2812c917e0
commit 1092ec8b33
5 changed files with 34 additions and 4 deletions
+15 -3
View File
@@ -18,6 +18,7 @@
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/queue.h>
#include <sys/resourcevar.h>
#include <sys/smp.h>
#include <sys/sx.h>
#include <sys/sysctl.h>
@@ -96,6 +97,10 @@ u_int vm_maxcpu;
SYSCTL_UINT(_hw_vmm, OID_AUTO, maxcpu, CTLFLAG_RDTUN | CTLFLAG_NOFETCH,
&vm_maxcpu, 0, "Maximum number of vCPUs");
u_int vm_maxvmms;
SYSCTL_UINT(_hw_vmm, OID_AUTO, maxvmms, CTLFLAG_RWTUN,
&vm_maxvmms, 0, "Maximum number of VMM instances per user");
static void devmem_destroy(void *arg);
static int devmem_create_cdev(struct vmmdev_softc *sc, int id, char *devmem);
@@ -870,6 +875,7 @@ vmmdev_destroy(struct vmmdev_softc *sc)
int error __diagused;
KASSERT(sc->cdev == NULL, ("%s: cdev not free", __func__));
KASSERT(sc->ucred != NULL, ("%s: missing ucred", __func__));
/*
* Destroy all cdevs:
@@ -898,8 +904,8 @@ vmmdev_destroy(struct vmmdev_softc *sc)
if (sc->vm != NULL)
vm_destroy(sc->vm);
if (sc->ucred != NULL)
crfree(sc->ucred);
chgvmmcnt(sc->ucred->cr_ruidinfo, -1, 0);
crfree(sc->ucred);
sx_xlock(&vmmdev_mtx);
SLIST_REMOVE(&head, sc, vmmdev_softc, link);
@@ -1021,6 +1027,12 @@ vmmdev_create(const char *name, struct ucred *cred)
vmmdev_destroy(sc);
return (error);
}
if (!chgvmmcnt(cred->cr_ruidinfo, 1, vm_maxvmms)) {
sx_xunlock(&vmmdev_mtx);
destroy_dev(cdev);
vmmdev_destroy(sc);
return (ENOMEM);
}
sc->cdev = cdev;
sx_xunlock(&vmmdev_mtx);
return (0);
@@ -1172,7 +1184,7 @@ vmm_handler(module_t mod, int what, void *arg)
}
if (vm_maxcpu == 0)
vm_maxcpu = 1;
vm_maxvmms = 4 * mp_ncpus;
error = vmm_modinit();
if (error == 0)
vmm_initialized = true;
+13
View File
@@ -895,6 +895,9 @@ getrlimitusage_one(struct proc *p, u_int which, int flags, rlim_t *res)
case RLIMIT_PIPEBUF:
*res = ui->ui_pipecnt;
break;
case RLIMIT_VMM:
*res = ui->ui_vmmcnt;
break;
default:
error = EINVAL;
break;
@@ -1643,6 +1646,9 @@ uifree(struct uidinfo *uip)
if (uip->ui_inotifywatchcnt != 0)
printf("freeing uidinfo: uid = %d, inotifywatchcnt = %ld\n",
uip->ui_uid, uip->ui_inotifywatchcnt);
if (uip->ui_vmmcnt != 0)
printf("freeing vmmcnt: uid = %d, vmmcnt = %ld\n",
uip->ui_uid, uip->ui_vmmcnt);
free(uip, M_UIDINFO);
}
@@ -1763,6 +1769,13 @@ chginotifywatchcnt(struct uidinfo *uip, int diff, rlim_t max)
"inotifywatchcnt"));
}
int
chgvmmcnt(struct uidinfo *uip, int diff, rlim_t max)
{
return (chglimit(uip, &uip->ui_vmmcnt, diff, max, "vmmcnt"));
}
static int
sysctl_kern_proc_rlimit_usage(SYSCTL_HANDLER_ARGS)
{
+3 -1
View File
@@ -115,8 +115,9 @@ struct __wrusage {
#define RLIMIT_KQUEUES 13 /* kqueues allocated */
#define RLIMIT_UMTXP 14 /* process-shared umtx */
#define RLIMIT_PIPEBUF 15 /* pipes/fifos buffers */
#define RLIMIT_VMM 16 /* virtual machines */
#define RLIM_NLIMITS 16 /* number of resource limits */
#define RLIM_NLIMITS 17 /* number of resource limits */
#define RLIM_INFINITY ((rlim_t)(((__uint64_t)1 << 63) - 1))
#define RLIM_SAVED_MAX RLIM_INFINITY
@@ -144,6 +145,7 @@ static const char *rlimit_ident[] = {
"kqueues",
"umtx",
"pipebuf",
"vmm",
};
#endif
+2
View File
@@ -124,6 +124,7 @@ struct uidinfo {
long ui_pipecnt; /* (b) consumption of pipe buffers */
long ui_inotifycnt; /* (b) number of inotify descriptors */
long ui_inotifywatchcnt; /* (b) number of inotify watches */
long ui_vmmcnt; /* (b) number of vmm instances */
uid_t ui_uid; /* (a) uid */
u_int ui_ref; /* (b) reference count */
#ifdef RACCT
@@ -148,6 +149,7 @@ int chgumtxcnt(struct uidinfo *uip, int diff, rlim_t maxval);
int chgpipecnt(struct uidinfo *uip, int diff, rlim_t max);
int chginotifycnt(struct uidinfo *uip, int diff, rlim_t maxval);
int chginotifywatchcnt(struct uidinfo *uip, int diff, rlim_t maxval);
int chgvmmcnt(struct uidinfo *uip, int diff, rlim_t max);
int kern_proc_setrlimit(struct thread *td, struct proc *p, u_int which,
struct rlimit *limp);
struct plimit
+1
View File
@@ -64,6 +64,7 @@ static struct {
{"kqueues", " "},
{"umtxp", " "},
{"pipebuf", "B "},
{"virtual-machines", " "},
};
_Static_assert(nitems(rlimit_param) == RLIM_NLIMITS,