From d2ac291e7dfa2bcb373ed243fabf7a10c9c3a1a0 Mon Sep 17 00:00:00 2001 From: maxv Date: Sun, 27 Oct 2019 20:17:36 +0000 Subject: [PATCH] Change the way root_owner works: consider the calling process as root_owner not if it has root privileges, but if the /dev/nvmm device was opened with write permissions. Introduce the undocumented nvmm_root_init() function to achieve that. The goal is to simplify the logic and have more granularity, eg if we want a monitoring agent to access VMs but don't want to give this agent real root access on the system. --- lib/libnvmm/libnvmm.c | 25 ++++++++++++++++++++++++- lib/libnvmm/nvmm.h | 3 ++- sys/dev/nvmm/nvmm.c | 29 ++++++++++++++--------------- 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/lib/libnvmm/libnvmm.c b/lib/libnvmm/libnvmm.c index 45275f2be681..e61a929b5a5f 100644 --- a/lib/libnvmm/libnvmm.c +++ b/lib/libnvmm/libnvmm.c @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm.c,v 1.17 2019/10/27 07:08:15 maxv Exp $ */ +/* $NetBSD: libnvmm.c,v 1.18 2019/10/27 20:17:36 maxv Exp $ */ /* * Copyright (c) 2018-2019 The NetBSD Foundation, Inc. @@ -179,6 +179,29 @@ nvmm_init(void) return 0; } +int +nvmm_root_init(void) +{ + if (nvmm_fd != -1) + return 0; + nvmm_fd = open("/dev/nvmm", O_WRONLY | O_CLOEXEC); + if (nvmm_fd == -1) + return -1; + if (nvmm_capability(&__capability) == -1) { + close(nvmm_fd); + nvmm_fd = -1; + return -1; + } + if (__capability.version != NVMM_KERN_VERSION) { + close(nvmm_fd); + nvmm_fd = -1; + errno = EPROGMISMATCH; + return -1; + } + + return 0; +} + int nvmm_capability(struct nvmm_capability *cap) { diff --git a/lib/libnvmm/nvmm.h b/lib/libnvmm/nvmm.h index 02e0be032bf5..ed4ac7783233 100644 --- a/lib/libnvmm/nvmm.h +++ b/lib/libnvmm/nvmm.h @@ -1,4 +1,4 @@ -/* $NetBSD: nvmm.h,v 1.15 2019/10/27 07:08:15 maxv Exp $ */ +/* $NetBSD: nvmm.h,v 1.16 2019/10/27 20:17:36 maxv Exp $ */ /* * Copyright (c) 2018-2019 The NetBSD Foundation, Inc. @@ -90,6 +90,7 @@ struct nvmm_mem { typedef uint64_t nvmm_prot_t; int nvmm_init(void); +int nvmm_root_init(void); int nvmm_capability(struct nvmm_capability *); diff --git a/sys/dev/nvmm/nvmm.c b/sys/dev/nvmm/nvmm.c index 1a7b7d089779..411d02c25ba7 100644 --- a/sys/dev/nvmm/nvmm.c +++ b/sys/dev/nvmm/nvmm.c @@ -1,4 +1,4 @@ -/* $NetBSD: nvmm.c,v 1.23 2019/10/23 07:01:11 maxv Exp $ */ +/* $NetBSD: nvmm.c,v 1.24 2019/10/27 20:17:36 maxv Exp $ */ /* * Copyright (c) 2018-2019 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: nvmm.c,v 1.23 2019/10/23 07:01:11 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: nvmm.c,v 1.24 2019/10/27 20:17:36 maxv Exp $"); #include #include @@ -889,7 +889,7 @@ out: /* -------------------------------------------------------------------------- */ static int -nvmm_ctl_mach_info(struct nvmm_ioc_ctl *args) +nvmm_ctl_mach_info(struct nvmm_owner *owner, struct nvmm_ioc_ctl *args) { struct nvmm_ctl_mach_info ctl; struct nvmm_machine *mach; @@ -903,7 +903,7 @@ nvmm_ctl_mach_info(struct nvmm_ioc_ctl *args) if (error) return error; - error = nvmm_machine_get(&root_owner, ctl.machid, &mach, true); + error = nvmm_machine_get(owner, ctl.machid, &mach, true); if (error) return error; @@ -930,16 +930,9 @@ nvmm_ctl_mach_info(struct nvmm_ioc_ctl *args) static int nvmm_ctl(struct nvmm_owner *owner, struct nvmm_ioc_ctl *args) { - int error; - - error = kauth_authorize_device(curlwp->l_cred, KAUTH_DEVICE_NVMM_CTL, - NULL, NULL, NULL, NULL); - if (error) - return error; - switch (args->op) { case NVMM_CTL_MACH_INFO: - return nvmm_ctl_mach_info(args); + return nvmm_ctl_mach_info(owner, args); default: return EINVAL; } @@ -1047,8 +1040,12 @@ nvmm_open(dev_t dev, int flags, int type, struct lwp *l) if (error) return error; - owner = kmem_alloc(sizeof(*owner), KM_SLEEP); - owner->pid = l->l_proc->p_pid; + if (OFLAGS(flags) & O_WRONLY) { + owner = &root_owner; + } else { + owner = kmem_alloc(sizeof(*owner), KM_SLEEP); + owner->pid = l->l_proc->p_pid; + } return fd_clone(fp, fd, flags, &nvmm_fileops, owner); } @@ -1060,7 +1057,9 @@ nvmm_close(file_t *fp) KASSERT(owner != NULL); nvmm_kill_machines(owner); - kmem_free(owner, sizeof(*owner)); + if (owner != &root_owner) { + kmem_free(owner, sizeof(*owner)); + } fp->f_data = NULL; return 0;