summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2020-05-20 21:46:06 +0200
committerHans de Goede <hdegoede@redhat.com>2020-05-20 21:46:06 +0200
commit5ae89dbdd00f98fbb5b7fd99f4799326b5360937 (patch)
treeb3b94b3301b61184161050e607f2075fa141d028
parentf2c63d1549c928c31aaa468a79063b76b0d2f4fa (diff)
downloadkernel-5ae89dbdd00f98fbb5b7fd99f4799326b5360937.tar.gz
kernel-5ae89dbdd00f98fbb5b7fd99f4799326b5360937.tar.xz
kernel-5ae89dbdd00f98fbb5b7fd99f4799326b5360937.zip
Fix automatic guest resolution resizing of VirtualBox VMs (rhbz 1789545)
Fix Sony laptop hang on resume from suspend (rhbz 1830150)
-rw-r--r--0001-platform-x86-sony-laptop-SNC-calls-should-handle-BUF.patch114
-rw-r--r--kernel.spec10
-rw-r--r--vboxguest-fixes.patch843
3 files changed, 967 insertions, 0 deletions
diff --git a/0001-platform-x86-sony-laptop-SNC-calls-should-handle-BUF.patch b/0001-platform-x86-sony-laptop-SNC-calls-should-handle-BUF.patch
new file mode 100644
index 000000000..dcae360a7
--- /dev/null
+++ b/0001-platform-x86-sony-laptop-SNC-calls-should-handle-BUF.patch
@@ -0,0 +1,114 @@
+From 47828d22539f76c8c9dcf2a55f18ea3a8039d8ef Mon Sep 17 00:00:00 2001
+From: Mattia Dongili <malattia@linux.it>
+Date: Fri, 8 May 2020 09:14:04 +0900
+Subject: [PATCH] platform/x86: sony-laptop: SNC calls should handle BUFFER
+ types
+
+After commit 6d232b29cfce ("ACPICA: Dispatcher: always generate buffer
+objects for ASL create_field() operator") ACPICA creates buffers even
+when new fields are small enough to fit into an integer.
+Many SNC calls counted on the old behaviour.
+Since sony-laptop already handles the INTEGER/BUFFER case in
+sony_nc_buffer_call, switch sony_nc_int_call to use its more generic
+function instead.
+
+Fixes: 6d232b29cfce ("ACPICA: Dispatcher: always generate buffer objects for ASL create_field() operator")
+Reported-by: Dominik Mierzejewski <dominik@greysector.net>
+Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=207491
+Reported-by: William Bader <williambader@hotmail.com>
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1830150
+Signed-off-by: Mattia Dongili <malattia@linux.it>
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+---
+ drivers/platform/x86/sony-laptop.c | 53 +++++++++++++-----------------
+ 1 file changed, 23 insertions(+), 30 deletions(-)
+
+diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
+index 51309f7ceede..6932cd11e660 100644
+--- a/drivers/platform/x86/sony-laptop.c
++++ b/drivers/platform/x86/sony-laptop.c
+@@ -757,33 +757,6 @@ static union acpi_object *__call_snc_method(acpi_handle handle, char *method,
+ return result;
+ }
+
+-static int sony_nc_int_call(acpi_handle handle, char *name, int *value,
+- int *result)
+-{
+- union acpi_object *object = NULL;
+- if (value) {
+- u64 v = *value;
+- object = __call_snc_method(handle, name, &v);
+- } else
+- object = __call_snc_method(handle, name, NULL);
+-
+- if (!object)
+- return -EINVAL;
+-
+- if (object->type != ACPI_TYPE_INTEGER) {
+- pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n",
+- ACPI_TYPE_INTEGER, object->type);
+- kfree(object);
+- return -EINVAL;
+- }
+-
+- if (result)
+- *result = object->integer.value;
+-
+- kfree(object);
+- return 0;
+-}
+-
+ #define MIN(a, b) (a > b ? b : a)
+ static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value,
+ void *buffer, size_t buflen)
+@@ -795,17 +768,20 @@ static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value,
+ if (!object)
+ return -EINVAL;
+
+- if (object->type == ACPI_TYPE_BUFFER) {
++ if (!buffer) {
++ /* do nothing */
++ } else if (object->type == ACPI_TYPE_BUFFER) {
+ len = MIN(buflen, object->buffer.length);
++ memset(buffer, 0, buflen);
+ memcpy(buffer, object->buffer.pointer, len);
+
+ } else if (object->type == ACPI_TYPE_INTEGER) {
+ len = MIN(buflen, sizeof(object->integer.value));
++ memset(buffer, 0, buflen);
+ memcpy(buffer, &object->integer.value, len);
+
+ } else {
+- pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n",
+- ACPI_TYPE_BUFFER, object->type);
++ pr_warn("Unexpected acpi_object: 0x%x\n", object->type);
+ ret = -EINVAL;
+ }
+
+@@ -813,6 +789,23 @@ static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value,
+ return ret;
+ }
+
++static int sony_nc_int_call(acpi_handle handle, char *name, int *value, int
++ *result)
++{
++ int ret;
++
++ if (value) {
++ u64 v = *value;
++
++ ret = sony_nc_buffer_call(handle, name, &v, result,
++ sizeof(*result));
++ } else {
++ ret = sony_nc_buffer_call(handle, name, NULL, result,
++ sizeof(*result));
++ }
++ return ret;
++}
++
+ struct sony_nc_handles {
+ u16 cap[0x10];
+ struct device_attribute devattr;
+--
+2.26.2
+
diff --git a/kernel.spec b/kernel.spec
index 7beaaa5a8..ca3ea72c0 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -918,6 +918,12 @@ Patch517: RFC-PCI-tegra-Revert-raw_violation_fixup-for-tegra124.patch
# CVE-2020-12888 rhbz 1836245 1836244
Patch518: vfio-pci-block-user-access-to-disabled-device-MMIO.patch
+# rhbz 1789545
+Patch519: vboxguest-fixes.patch
+
+# rhbz 1830150
+Patch520: 0001-platform-x86-sony-laptop-SNC-calls-should-handle-BUF.patch
+
# END OF PATCH DEFINITIONS
%endif
@@ -3014,6 +3020,10 @@ fi
#
#
%changelog
+* Wed May 20 2020 Hans de Goede <hdegoede@redhat.com>
+- Fix automatic guest resolution resizing of VirtualBox VMs (rhbz 1789545)
+- Fix Sony laptop hang on resume from suspend (rhbz 1830150)
+
* Wed May 20 2020 Justin M. Forbes <jforbes@fedoraproject.org> - 5.6.14-300
- Linux v5.6.14
- Fix CVE-2020-12888 (rhbz 1836245 1836244)
diff --git a/vboxguest-fixes.patch b/vboxguest-fixes.patch
new file mode 100644
index 000000000..90c95b374
--- /dev/null
+++ b/vboxguest-fixes.patch
@@ -0,0 +1,843 @@
+From ba5ea5d9d5d2ade5156cf2bc452ff6d1f5c4db37 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 19 May 2020 12:21:30 +0200
+Subject: [PATCH 1/8] virt: vbox: Fix VBGL_IOCTL_VMMDEV_REQUEST_BIG and _LOG
+ req numbers to match upstream
+
+Until this commit the mainline kernel version (this version) of the
+vboxguest module contained a bug where it defined
+VBGL_IOCTL_VMMDEV_REQUEST_BIG and VBGL_IOCTL_LOG using
+_IOC(_IOC_READ | _IOC_WRITE, 'V', ...) instead of
+_IO(V, ...) as the out of tree VirtualBox upstream version does.
+
+Since the VirtualBox userspace bits are always built against VirtualBox
+upstream's headers, this means that so far the mainline kernel version
+of the vboxguest module has been failing these 2 ioctls with -ENOTTY.
+I guess that VBGL_IOCTL_VMMDEV_REQUEST_BIG is never used causing us to
+not hit that one and sofar the vboxguest driver has failed to actually
+log any log messages passed it through VBGL_IOCTL_LOG.
+
+This commit changes the VBGL_IOCTL_VMMDEV_REQUEST_BIG and VBGL_IOCTL_LOG
+defines to match the out of tree VirtualBox upstream vboxguest version,
+while keeping compatibility with the old wrong request defines so as
+to not break the kernel ABI in case someone has been using the old
+request defines.
+
+Fixes: f6ddd094f579 ("virt: Add vboxguest driver for Virtual Box Guest integration UAPI")
+Cc: stable@vger.kernel.org
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/virt/vboxguest/vboxguest_core.c | 4 +++-
+ drivers/virt/vboxguest/vboxguest_core.h | 15 +++++++++++++++
+ drivers/virt/vboxguest/vboxguest_linux.c | 3 ++-
+ include/uapi/linux/vboxguest.h | 4 ++--
+ 4 files changed, 22 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/virt/vboxguest/vboxguest_core.c b/drivers/virt/vboxguest/vboxguest_core.c
+index b690a8a4bf9e..8fab04e76c14 100644
+--- a/drivers/virt/vboxguest/vboxguest_core.c
++++ b/drivers/virt/vboxguest/vboxguest_core.c
+@@ -1520,7 +1520,8 @@ int vbg_core_ioctl(struct vbg_session *session, unsigned int req, void *data)
+
+ /* For VMMDEV_REQUEST hdr->type != VBG_IOCTL_HDR_TYPE_DEFAULT */
+ if (req_no_size == VBG_IOCTL_VMMDEV_REQUEST(0) ||
+- req == VBG_IOCTL_VMMDEV_REQUEST_BIG)
++ req == VBG_IOCTL_VMMDEV_REQUEST_BIG ||
++ req == VBG_IOCTL_VMMDEV_REQUEST_BIG_ALT)
+ return vbg_ioctl_vmmrequest(gdev, session, data);
+
+ if (hdr->type != VBG_IOCTL_HDR_TYPE_DEFAULT)
+@@ -1558,6 +1559,7 @@ int vbg_core_ioctl(struct vbg_session *session, unsigned int req, void *data)
+ case VBG_IOCTL_HGCM_CALL(0):
+ return vbg_ioctl_hgcm_call(gdev, session, f32bit, data);
+ case VBG_IOCTL_LOG(0):
++ case VBG_IOCTL_LOG_ALT(0):
+ return vbg_ioctl_log(data);
+ }
+
+diff --git a/drivers/virt/vboxguest/vboxguest_core.h b/drivers/virt/vboxguest/vboxguest_core.h
+index 4188c12b839f..77c3a9c8255d 100644
+--- a/drivers/virt/vboxguest/vboxguest_core.h
++++ b/drivers/virt/vboxguest/vboxguest_core.h
+@@ -15,6 +15,21 @@
+ #include <linux/vboxguest.h>
+ #include "vmmdev.h"
+
++/*
++ * The mainline kernel version (this version) of the vboxguest module
++ * contained a bug where it defined VBGL_IOCTL_VMMDEV_REQUEST_BIG and
++ * VBGL_IOCTL_LOG using _IOC(_IOC_READ | _IOC_WRITE, 'V', ...) instead
++ * of _IO(V, ...) as the out of tree VirtualBox upstream version does.
++ *
++ * These _ALT definitions keep compatibility with the wrong defines the
++ * mainline kernel version used for a while.
++ * Note the VirtualBox userspace bits have always been built against
++ * VirtualBox upstream's headers, so this is likely not necessary. But
++ * we must never break our ABI so we keep these around to be 100% sure.
++ */
++#define VBG_IOCTL_VMMDEV_REQUEST_BIG_ALT _IOC(_IOC_READ | _IOC_WRITE, 'V', 3, 0)
++#define VBG_IOCTL_LOG_ALT(s) _IOC(_IOC_READ | _IOC_WRITE, 'V', 9, s)
++
+ struct vbg_session;
+
+ /** VBox guest memory balloon. */
+diff --git a/drivers/virt/vboxguest/vboxguest_linux.c b/drivers/virt/vboxguest/vboxguest_linux.c
+index 6e8c0f1c1056..32c2c52f7e84 100644
+--- a/drivers/virt/vboxguest/vboxguest_linux.c
++++ b/drivers/virt/vboxguest/vboxguest_linux.c
+@@ -131,7 +131,8 @@ static long vbg_misc_device_ioctl(struct file *filp, unsigned int req,
+ * the need for a bounce-buffer and another copy later on.
+ */
+ is_vmmdev_req = (req & ~IOCSIZE_MASK) == VBG_IOCTL_VMMDEV_REQUEST(0) ||
+- req == VBG_IOCTL_VMMDEV_REQUEST_BIG;
++ req == VBG_IOCTL_VMMDEV_REQUEST_BIG ||
++ req == VBG_IOCTL_VMMDEV_REQUEST_BIG_ALT;
+
+ if (is_vmmdev_req)
+ buf = vbg_req_alloc(size, VBG_IOCTL_HDR_TYPE_DEFAULT,
+diff --git a/include/uapi/linux/vboxguest.h b/include/uapi/linux/vboxguest.h
+index 9cec58a6a5ea..f79d7abe27db 100644
+--- a/include/uapi/linux/vboxguest.h
++++ b/include/uapi/linux/vboxguest.h
+@@ -103,7 +103,7 @@ VMMDEV_ASSERT_SIZE(vbg_ioctl_driver_version_info, 24 + 20);
+
+
+ /* IOCTL to perform a VMM Device request larger then 1KB. */
+-#define VBG_IOCTL_VMMDEV_REQUEST_BIG _IOC(_IOC_READ | _IOC_WRITE, 'V', 3, 0)
++#define VBG_IOCTL_VMMDEV_REQUEST_BIG _IO('V', 3)
+
+
+ /** VBG_IOCTL_HGCM_CONNECT data structure. */
+@@ -198,7 +198,7 @@ struct vbg_ioctl_log {
+ } u;
+ };
+
+-#define VBG_IOCTL_LOG(s) _IOC(_IOC_READ | _IOC_WRITE, 'V', 9, s)
++#define VBG_IOCTL_LOG(s) _IO('V', 9)
+
+
+ /** VBG_IOCTL_WAIT_FOR_EVENTS data structure. */
+--
+2.26.2
+
+From 14dc3b46e666343c55e5b253ed3dd4c57b13e778 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 19 May 2020 13:23:06 +0200
+Subject: [PATCH 2/8] virt: vbox: Fix guest capabilities mask check
+
+Check the passed in capabilities against VMMDEV_GUEST_CAPABILITIES_MASK
+instead of against VMMDEV_EVENT_VALID_EVENT_MASK.
+This tightens the allowed mask from 0x7ff to 0x7.
+
+Fixes: 0ba002bc4393 ("virt: Add vboxguest driver for Virtual Box Guest integration")
+Cc: stable@vger.kernel.org
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/virt/vboxguest/vboxguest_core.c | 2 +-
+ drivers/virt/vboxguest/vmmdev.h | 2 ++
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/virt/vboxguest/vboxguest_core.c b/drivers/virt/vboxguest/vboxguest_core.c
+index 8fab04e76c14..18ebd7a6af98 100644
+--- a/drivers/virt/vboxguest/vboxguest_core.c
++++ b/drivers/virt/vboxguest/vboxguest_core.c
+@@ -1444,7 +1444,7 @@ static int vbg_ioctl_change_guest_capabilities(struct vbg_dev *gdev,
+ or_mask = caps->u.in.or_mask;
+ not_mask = caps->u.in.not_mask;
+
+- if ((or_mask | not_mask) & ~VMMDEV_EVENT_VALID_EVENT_MASK)
++ if ((or_mask | not_mask) & ~VMMDEV_GUEST_CAPABILITIES_MASK)
+ return -EINVAL;
+
+ ret = vbg_set_session_capabilities(gdev, session, or_mask, not_mask,
+diff --git a/drivers/virt/vboxguest/vmmdev.h b/drivers/virt/vboxguest/vmmdev.h
+index 6337b8d75d96..21f408120e3f 100644
+--- a/drivers/virt/vboxguest/vmmdev.h
++++ b/drivers/virt/vboxguest/vmmdev.h
+@@ -206,6 +206,8 @@ VMMDEV_ASSERT_SIZE(vmmdev_mask, 24 + 8);
+ * not.
+ */
+ #define VMMDEV_GUEST_SUPPORTS_GRAPHICS BIT(2)
++/* The mask of valid capabilities, for sanity checking. */
++#define VMMDEV_GUEST_CAPABILITIES_MASK 0x00000007U
+
+ /** struct vmmdev_hypervisorinfo - Hypervisor info structure. */
+ struct vmmdev_hypervisorinfo {
+--
+2.26.2
+
+From 172353a61c23015611a341c2f3f4888d866a560b Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 19 May 2020 14:33:13 +0200
+Subject: [PATCH 3/8] virt: vbox: Rename guest_caps struct members to
+ set_guest_caps
+
+Rename guest_caps[_tracker] struct members to set_guest_caps[_tracker]
+this is a preparation patch for adding support for the
+VBGL_IOCTL_GUEST_CAPS_ACQUIRE ioctl.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/virt/vboxguest/vboxguest_core.c | 20 ++++++++++----------
+ drivers/virt/vboxguest/vboxguest_core.h | 9 +++++----
+ 2 files changed, 15 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/virt/vboxguest/vboxguest_core.c b/drivers/virt/vboxguest/vboxguest_core.c
+index 18ebd7a6af98..aee5eff229f2 100644
+--- a/drivers/virt/vboxguest/vboxguest_core.c
++++ b/drivers/virt/vboxguest/vboxguest_core.c
+@@ -699,17 +699,17 @@ static int vbg_set_session_capabilities(struct vbg_dev *gdev,
+ mutex_lock(&gdev->session_mutex);
+
+ /* Apply the changes to the session mask. */
+- previous = session->guest_caps;
+- session->guest_caps |= or_mask;
+- session->guest_caps &= ~not_mask;
++ previous = session->set_guest_caps;
++ session->set_guest_caps |= or_mask;
++ session->set_guest_caps &= ~not_mask;
+
+ /* If anything actually changed, update the global usage counters. */
+- changed = previous ^ session->guest_caps;
++ changed = previous ^ session->set_guest_caps;
+ if (!changed)
+ goto out;
+
+- vbg_track_bit_usage(&gdev->guest_caps_tracker, changed, previous);
+- or_mask = gdev->guest_caps_tracker.mask;
++ vbg_track_bit_usage(&gdev->set_guest_caps_tracker, changed, previous);
++ or_mask = gdev->set_guest_caps_tracker.mask;
+
+ if (gdev->guest_caps_host == or_mask || !req)
+ goto out;
+@@ -726,9 +726,9 @@ static int vbg_set_session_capabilities(struct vbg_dev *gdev,
+ if (session_termination)
+ goto out;
+
+- vbg_track_bit_usage(&gdev->guest_caps_tracker, changed,
+- session->guest_caps);
+- session->guest_caps = previous;
++ vbg_track_bit_usage(&gdev->set_guest_caps_tracker, changed,
++ session->set_guest_caps);
++ session->set_guest_caps = previous;
+ }
+
+ out:
+@@ -1452,7 +1452,7 @@ static int vbg_ioctl_change_guest_capabilities(struct vbg_dev *gdev,
+ if (ret)
+ return ret;
+
+- caps->u.out.session_caps = session->guest_caps;
++ caps->u.out.session_caps = session->set_guest_caps;
+ caps->u.out.global_caps = gdev->guest_caps_host;
+
+ return 0;
+diff --git a/drivers/virt/vboxguest/vboxguest_core.h b/drivers/virt/vboxguest/vboxguest_core.h
+index 77c3a9c8255d..dc745a033164 100644
+--- a/drivers/virt/vboxguest/vboxguest_core.h
++++ b/drivers/virt/vboxguest/vboxguest_core.h
+@@ -118,11 +118,12 @@ struct vbg_dev {
+ u32 event_filter_host;
+
+ /**
+- * Usage counters for guest capabilities. Indexed by capability bit
++ * Usage counters for guest capabilities requested through
++ * vbg_set_session_capabilities(). Indexed by capability bit
+ * number, one count per session using a capability.
+ * Protected by session_mutex.
+ */
+- struct vbg_bit_usage_tracker guest_caps_tracker;
++ struct vbg_bit_usage_tracker set_guest_caps_tracker;
+ /**
+ * The guest capabilities last reported to the host (or UINT32_MAX).
+ * Protected by session_mutex.
+@@ -164,11 +165,11 @@ struct vbg_session {
+ */
+ u32 event_filter;
+ /**
+- * Guest capabilities for this session.
++ * Guest capabilities set through vbg_set_session_capabilities().
+ * A capability claimed by any guest session will be reported to the
+ * host. Protected by vbg_gdev.session_mutex.
+ */
+- u32 guest_caps;
++ u32 set_guest_caps;
+ /** VMMDEV_REQUESTOR_* flags */
+ u32 requestor;
+ /** Set on CANCEL_ALL_WAITEVENTS, protected by vbg_devevent_spinlock. */
+--
+2.26.2
+
+From c5cf459d4d98a7993f5e00d5d2b826c55bbce562 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 19 May 2020 15:30:29 +0200
+Subject: [PATCH 4/8] virt: vbox: Add vbg_set_host_capabilities() helper
+ function
+
+Add vbg_set_host_capabilities() helper function, this is a preparation
+patch for adding support for the VBGL_IOCTL_GUEST_CAPS_ACQUIRE ioctl.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/virt/vboxguest/vboxguest_core.c | 79 ++++++++++++++-----------
+ 1 file changed, 46 insertions(+), 33 deletions(-)
+
+diff --git a/drivers/virt/vboxguest/vboxguest_core.c b/drivers/virt/vboxguest/vboxguest_core.c
+index aee5eff229f2..15b3cb618c6e 100644
+--- a/drivers/virt/vboxguest/vboxguest_core.c
++++ b/drivers/virt/vboxguest/vboxguest_core.c
+@@ -661,6 +661,48 @@ static int vbg_reset_host_capabilities(struct vbg_dev *gdev)
+ return vbg_status_code_to_errno(rc);
+ }
+
++/**
++ * Set guest capabilities on the host.
++ * Must be called with gdev->session_mutex hold.
++ * Return: 0 or negative errno value.
++ * @gdev: The Guest extension device.
++ * @session: The session.
++ * @session_termination: Set if we're called by the session cleanup code.
++ */
++static int vbg_set_host_capabilities(struct vbg_dev *gdev,
++ struct vbg_session *session,
++ bool session_termination)
++{
++ struct vmmdev_mask *req;
++ u32 caps;
++ int rc;
++
++ WARN_ON(!mutex_is_locked(&gdev->session_mutex));
++
++ caps = gdev->set_guest_caps_tracker.mask;
++
++ if (gdev->guest_caps_host == caps)
++ return 0;
++
++ /* On termination the requestor is the kernel, as we're cleaning up. */
++ req = vbg_req_alloc(sizeof(*req), VMMDEVREQ_SET_GUEST_CAPABILITIES,
++ session_termination ? VBG_KERNEL_REQUEST :
++ session->requestor);
++ if (!req) {
++ gdev->guest_caps_host = U32_MAX;
++ return -ENOMEM;
++ }
++
++ req->or_mask = caps;
++ req->not_mask = ~caps;
++ rc = vbg_req_perform(gdev, req);
++ vbg_req_free(req, sizeof(*req));
++
++ gdev->guest_caps_host = (rc >= 0) ? caps : U32_MAX;
++
++ return vbg_status_code_to_errno(rc);
++}
++
+ /**
+ * Sets the guest capabilities for a session. Takes the session spinlock.
+ * Return: 0 or negative errno value.
+@@ -678,23 +720,8 @@ static int vbg_set_session_capabilities(struct vbg_dev *gdev,
+ u32 or_mask, u32 not_mask,
+ bool session_termination)
+ {
+- struct vmmdev_mask *req;
+ u32 changed, previous;
+- int rc, ret = 0;
+-
+- /*
+- * Allocate a request buffer before taking the spinlock, when
+- * the session is being terminated the requestor is the kernel,
+- * as we're cleaning up.
+- */
+- req = vbg_req_alloc(sizeof(*req), VMMDEVREQ_SET_GUEST_CAPABILITIES,
+- session_termination ? VBG_KERNEL_REQUEST :
+- session->requestor);
+- if (!req) {
+- if (!session_termination)
+- return -ENOMEM;
+- /* Ignore allocation failure, we must do session cleanup. */
+- }
++ int ret = 0;
+
+ mutex_lock(&gdev->session_mutex);
+
+@@ -709,23 +736,10 @@ static int vbg_set_session_capabilities(struct vbg_dev *gdev,
+ goto out;
+
+ vbg_track_bit_usage(&gdev->set_guest_caps_tracker, changed, previous);
+- or_mask = gdev->set_guest_caps_tracker.mask;
+-
+- if (gdev->guest_caps_host == or_mask || !req)
+- goto out;
+-
+- gdev->guest_caps_host = or_mask;
+- req->or_mask = or_mask;
+- req->not_mask = ~or_mask;
+- rc = vbg_req_perform(gdev, req);
+- if (rc < 0) {
+- ret = vbg_status_code_to_errno(rc);
+-
+- /* Failed, roll back (unless it's session termination time). */
+- gdev->guest_caps_host = U32_MAX;
+- if (session_termination)
+- goto out;
+
++ ret = vbg_set_host_capabilities(gdev, session, session_termination);
++ /* Roll back on failure, unless it's session termination time. */
++ if (ret < 0 && !session_termination) {
+ vbg_track_bit_usage(&gdev->set_guest_caps_tracker, changed,
+ session->set_guest_caps);
+ session->set_guest_caps = previous;
+@@ -733,7 +747,6 @@ static int vbg_set_session_capabilities(struct vbg_dev *gdev,
+
+ out:
+ mutex_unlock(&gdev->session_mutex);
+- vbg_req_free(req, sizeof(*req));
+
+ return ret;
+ }
+--
+2.26.2
+
+From 2f33e58bcc8c69f938629dc57c8ad631724f02f0 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 19 May 2020 18:04:30 +0200
+Subject: [PATCH 5/8] virt: vbox: Add support for the new
+ VBG_IOCTL_ACQUIRE_GUEST_CAPABILITIES ioctl
+
+Add support for the new VBG_IOCTL_ACQUIRE_GUEST_CAPABILITIES ioctl, this
+is necessary for automatic resizing of the guest resolution to match the
+VM-window size to work with the new VMSVGA virtual GPU which is now the
+new default in VirtualBox.
+
+BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1789545
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/virt/vboxguest/vboxguest_core.c | 163 +++++++++++++++++++++++-
+ drivers/virt/vboxguest/vboxguest_core.h | 14 ++
+ include/uapi/linux/vboxguest.h | 24 ++++
+ 3 files changed, 200 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/virt/vboxguest/vboxguest_core.c b/drivers/virt/vboxguest/vboxguest_core.c
+index 15b3cb618c6e..4f1addaa3f6f 100644
+--- a/drivers/virt/vboxguest/vboxguest_core.c
++++ b/drivers/virt/vboxguest/vboxguest_core.c
+@@ -679,7 +679,7 @@ static int vbg_set_host_capabilities(struct vbg_dev *gdev,
+
+ WARN_ON(!mutex_is_locked(&gdev->session_mutex));
+
+- caps = gdev->set_guest_caps_tracker.mask;
++ caps = gdev->acquired_guest_caps | gdev->set_guest_caps_tracker.mask;
+
+ if (gdev->guest_caps_host == caps)
+ return 0;
+@@ -703,6 +703,113 @@ static int vbg_set_host_capabilities(struct vbg_dev *gdev,
+ return vbg_status_code_to_errno(rc);
+ }
+
++/**
++ * Acquire (get exclusive access) guest capabilities for a session.
++ * Takes the session mutex.
++ * Return: 0 or negative errno value.
++ * @gdev: The Guest extension device.
++ * @session: The session.
++ * @flags: Flags (VBGL_IOC_AGC_FLAGS_XXX).
++ * @or_mask: The capabilities to add.
++ * @not_mask: The capabilities to remove.
++ * @session_termination: Set if we're called by the session cleanup code.
++ * This tweaks the error handling so we perform
++ * proper session cleanup even if the host
++ * misbehaves.
++ */
++static int vbg_acquire_session_capabilities(struct vbg_dev *gdev,
++ struct vbg_session *session,
++ u32 or_mask, u32 not_mask,
++ u32 flags, bool session_termination)
++{
++ unsigned long irqflags;
++ bool wakeup = false;
++ int ret = 0;
++
++ mutex_lock(&gdev->session_mutex);
++
++ if (gdev->set_guest_caps_tracker.mask & or_mask) {
++ vbg_err("%s error: cannot acquire caps which are currently set\n",
++ __func__);
++ ret = -EINVAL;
++ goto out;
++ }
++
++ /*
++ * Mark any caps in the or_mask as now being in acquire-mode. Note
++ * once caps are in acquire_mode they always stay in this mode.
++ * This impacts event handling, so we take the event-lock.
++ */
++ spin_lock_irqsave(&gdev->event_spinlock, irqflags);
++ gdev->acquire_mode_guest_caps |= or_mask;
++ spin_unlock_irqrestore(&gdev->event_spinlock, irqflags);
++
++ /* If we only have to switch the caps to acquire mode, we're done. */
++ if (flags & VBGL_IOC_AGC_FLAGS_CONFIG_ACQUIRE_MODE)
++ goto out;
++
++ not_mask &= ~or_mask; /* or_mask takes priority over not_mask */
++ not_mask &= session->acquired_guest_caps;
++ or_mask &= ~session->acquired_guest_caps;
++
++ if (or_mask == 0 && not_mask == 0)
++ goto out;
++
++ if (gdev->acquired_guest_caps & or_mask) {
++ ret = -EBUSY;
++ goto out;
++ }
++
++ gdev->acquired_guest_caps |= or_mask;
++ gdev->acquired_guest_caps &= ~not_mask;
++ /* session->acquired_guest_caps impacts event handling, take the lock */
++ spin_lock_irqsave(&gdev->event_spinlock, irqflags);
++ session->acquired_guest_caps |= or_mask;
++ session->acquired_guest_caps &= ~not_mask;
++ spin_unlock_irqrestore(&gdev->event_spinlock, irqflags);
++
++ ret = vbg_set_host_capabilities(gdev, session, session_termination);
++ /* Roll back on failure, unless it's session termination time. */
++ if (ret < 0 && !session_termination) {
++ gdev->acquired_guest_caps &= ~or_mask;
++ gdev->acquired_guest_caps |= not_mask;
++ spin_lock_irqsave(&gdev->event_spinlock, irqflags);
++ session->acquired_guest_caps &= ~or_mask;
++ session->acquired_guest_caps |= not_mask;
++ spin_unlock_irqrestore(&gdev->event_spinlock, irqflags);
++ }
++
++ /*
++ * If we added a capability, check if that means some other thread in
++ * our session should be unblocked because there are events pending
++ * (the result of vbg_get_allowed_event_mask_for_session() may change).
++ *
++ * HACK ALERT! When the seamless support capability is added we generate
++ * a seamless change event so that the ring-3 client can sync with
++ * the seamless state.
++ */
++ if (ret == 0 && or_mask != 0) {
++ spin_lock_irqsave(&gdev->event_spinlock, irqflags);
++
++ if (or_mask & VMMDEV_GUEST_SUPPORTS_SEAMLESS)
++ gdev->pending_events |=
++ VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST;
++
++ if (gdev->pending_events)
++ wakeup = true;
++
++ spin_unlock_irqrestore(&gdev->event_spinlock, irqflags);
++
++ if (wakeup)
++ wake_up(&gdev->event_wq);
++ }
++
++out:
++ mutex_unlock(&gdev->session_mutex);
++
++ return ret;
++}
++
+ /**
+ * Sets the guest capabilities for a session. Takes the session spinlock.
+ * Return: 0 or negative errno value.
+@@ -725,6 +832,13 @@ static int vbg_set_session_capabilities(struct vbg_dev *gdev,
+
+ mutex_lock(&gdev->session_mutex);
+
++ if (gdev->acquire_mode_guest_caps & or_mask) {
++ vbg_err("%s error: cannot set caps which are in acquire_mode\n",
++ __func__);
++ ret = -EBUSY;
++ goto out;
++ }
++
+ /* Apply the changes to the session mask. */
+ previous = session->set_guest_caps;
+ session->set_guest_caps |= or_mask;
+@@ -962,6 +1076,7 @@ void vbg_core_close_session(struct vbg_session *session)
+ struct vbg_dev *gdev = session->gdev;
+ int i, rc;
+
++ vbg_acquire_session_capabilities(gdev, session, 0, U32_MAX, 0, true);
+ vbg_set_session_capabilities(gdev, session, 0, U32_MAX, true);
+ vbg_set_session_event_filter(gdev, session, 0, U32_MAX, true);
+
+@@ -1019,6 +1134,25 @@ static int vbg_ioctl_driver_version_info(
+ return 0;
+ }
+
++/* Must be called with the event_lock held */
++static u32 vbg_get_allowed_event_mask_for_session(struct vbg_dev *gdev,
++ struct vbg_session *session)
++{
++ u32 acquire_mode_caps = gdev->acquire_mode_guest_caps;
++ u32 session_acquired_caps = session->acquired_guest_caps;
++ u32 allowed_events = VMMDEV_EVENT_VALID_EVENT_MASK;
++
++ if ((acquire_mode_caps & VMMDEV_GUEST_SUPPORTS_GRAPHICS) &&
++ !(session_acquired_caps & VMMDEV_GUEST_SUPPORTS_GRAPHICS))
++ allowed_events &= ~VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
++
++ if ((acquire_mode_caps & VMMDEV_GUEST_SUPPORTS_SEAMLESS) &&
++ !(session_acquired_caps & VMMDEV_GUEST_SUPPORTS_SEAMLESS))
++ allowed_events &= ~VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST;
++
++ return allowed_events;
++}
++
+ static bool vbg_wait_event_cond(struct vbg_dev *gdev,
+ struct vbg_session *session,
+ u32 event_mask)
+@@ -1030,6 +1164,7 @@ static bool vbg_wait_event_cond(struct vbg_dev *gdev,
+ spin_lock_irqsave(&gdev->event_spinlock, flags);
+
+ events = gdev->pending_events & event_mask;
++ events &= vbg_get_allowed_event_mask_for_session(gdev, session);
+ wakeup = events || session->cancel_waiters;
+
+ spin_unlock_irqrestore(&gdev->event_spinlock, flags);
+@@ -1044,6 +1179,7 @@ static u32 vbg_consume_events_locked(struct vbg_dev *gdev,
+ {
+ u32 events = gdev->pending_events & event_mask;
+
++ events &= vbg_get_allowed_event_mask_for_session(gdev, session);
+ gdev->pending_events &= ~events;
+ return events;
+ }
+@@ -1445,6 +1581,29 @@ static int vbg_ioctl_change_filter_mask(struct vbg_dev *gdev,
+ false);
+ }
+
++static int vbg_ioctl_acquire_guest_capabilities(struct vbg_dev *gdev,
++ struct vbg_session *session,
++ struct vbg_ioctl_acquire_guest_caps *caps)
++{
++ u32 flags, or_mask, not_mask;
++
++ if (vbg_ioctl_chk(&caps->hdr, sizeof(caps->u.in), 0))
++ return -EINVAL;
++
++ flags = caps->u.in.flags;
++ or_mask = caps->u.in.or_mask;
++ not_mask = caps->u.in.not_mask;
++
++ if (flags & ~VBGL_IOC_AGC_FLAGS_VALID_MASK)
++ return -EINVAL;
++
++ if ((or_mask | not_mask) & ~VMMDEV_GUEST_CAPABILITIES_MASK)
++ return -EINVAL;
++
++ return vbg_acquire_session_capabilities(gdev, session, or_mask,
++ not_mask, flags, false);
++}
++
+ static int vbg_ioctl_change_guest_capabilities(struct vbg_dev *gdev,
+ struct vbg_session *session, struct vbg_ioctl_set_guest_caps *caps)
+ {
+@@ -1554,6 +1713,8 @@ int vbg_core_ioctl(struct vbg_session *session, unsigned int req, void *data)
+ return vbg_ioctl_interrupt_all_wait_events(gdev, session, data);
+ case VBG_IOCTL_CHANGE_FILTER_MASK:
+ return vbg_ioctl_change_filter_mask(gdev, session, data);
++ case VBG_IOCTL_ACQUIRE_GUEST_CAPABILITIES:
++ return vbg_ioctl_acquire_guest_capabilities(gdev, session, data);
+ case VBG_IOCTL_CHANGE_GUEST_CAPABILITIES:
+ return vbg_ioctl_change_guest_capabilities(gdev, session, data);
+ case VBG_IOCTL_CHECK_BALLOON:
+diff --git a/drivers/virt/vboxguest/vboxguest_core.h b/drivers/virt/vboxguest/vboxguest_core.h
+index dc745a033164..ab4bf64e2cec 100644
+--- a/drivers/virt/vboxguest/vboxguest_core.h
++++ b/drivers/virt/vboxguest/vboxguest_core.h
+@@ -117,6 +117,15 @@ struct vbg_dev {
+ */
+ u32 event_filter_host;
+
++ /**
++ * Guest capabilities which have been switched to acquire_mode.
++ */
++ u32 acquire_mode_guest_caps;
++ /**
++ * Guest capabilities acquired by vbg_acquire_session_capabilities().
++ * Only one session can acquire a capability at a time.
++ */
++ u32 acquired_guest_caps;
+ /**
+ * Usage counters for guest capabilities requested through
+ * vbg_set_session_capabilities(). Indexed by capability bit
+@@ -164,6 +173,11 @@ struct vbg_session {
+ * host filter. Protected by vbg_gdev.session_mutex.
+ */
+ u32 event_filter;
++ /**
++ * Guest capabilities acquired by vbg_acquire_session_capabilities().
++ * Only one session can acquire a capability at a time.
++ */
++ u32 acquired_guest_caps;
+ /**
+ * Guest capabilities set through vbg_set_session_capabilities().
+ * A capability claimed by any guest session will be reported to the
+diff --git a/include/uapi/linux/vboxguest.h b/include/uapi/linux/vboxguest.h
+index f79d7abe27db..15125f6ec60d 100644
+--- a/include/uapi/linux/vboxguest.h
++++ b/include/uapi/linux/vboxguest.h
+@@ -257,6 +257,30 @@ VMMDEV_ASSERT_SIZE(vbg_ioctl_change_filter, 24 + 8);
+ _IOWR('V', 12, struct vbg_ioctl_change_filter)
+
+
++/** VBG_IOCTL_ACQUIRE_GUEST_CAPABILITIES data structure. */
++struct vbg_ioctl_acquire_guest_caps {
++ /** The header. */
++ struct vbg_ioctl_hdr hdr;
++ union {
++ struct {
++ /** Flags (VBGL_IOC_AGC_FLAGS_XXX). */
++ __u32 flags;
++ /** Capabilities to set (VMMDEV_GUEST_SUPPORTS_XXX). */
++ __u32 or_mask;
++ /** Capabilities to drop (VMMDEV_GUEST_SUPPORTS_XXX). */
++ __u32 not_mask;
++ } in;
++ } u;
++};
++VMMDEV_ASSERT_SIZE(vbg_ioctl_acquire_guest_caps, 24 + 12);
++
++#define VBGL_IOC_AGC_FLAGS_CONFIG_ACQUIRE_MODE 0x00000001
++#define VBGL_IOC_AGC_FLAGS_VALID_MASK 0x00000001
++
++#define VBG_IOCTL_ACQUIRE_GUEST_CAPABILITIES \
++ _IOWR('V', 13, struct vbg_ioctl_acquire_guest_caps)
++
++
+ /** VBG_IOCTL_CHANGE_GUEST_CAPABILITIES data structure. */
+ struct vbg_ioctl_set_guest_caps {
+ /** The header. */
+--
+2.26.2
+
+From d34852680360e52c39ea901fbc3778d28f229852 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 19 May 2020 11:05:40 +0200
+Subject: [PATCH 6/8] virt: vbox: Add a few new vmmdev request types to the
+ userspace whitelist
+
+Upstream VirtualBox has defined and is using a few new request types for
+vmmdev requests passed through /dev/vboxguest to the hypervisor.
+
+Add the defines for these to vbox_vmmdev_types.h and add add them to the
+whitelists of vmmdev requests which userspace is allowed to make.
+
+BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1789545
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/virt/vboxguest/vboxguest_core.c | 2 ++
+ include/uapi/linux/vbox_vmmdev_types.h | 3 +++
+ 2 files changed, 5 insertions(+)
+
+diff --git a/drivers/virt/vboxguest/vboxguest_core.c b/drivers/virt/vboxguest/vboxguest_core.c
+index 4f1addaa3f6f..ffd76b949276 100644
+--- a/drivers/virt/vboxguest/vboxguest_core.c
++++ b/drivers/virt/vboxguest/vboxguest_core.c
+@@ -1299,7 +1299,9 @@ static int vbg_req_allowed(struct vbg_dev *gdev, struct vbg_session *session,
+ case VMMDEVREQ_VIDEO_ACCEL_ENABLE:
+ case VMMDEVREQ_VIDEO_ACCEL_FLUSH:
+ case VMMDEVREQ_VIDEO_SET_VISIBLE_REGION:
++ case VMMDEVREQ_VIDEO_UPDATE_MONITOR_POSITIONS:
+ case VMMDEVREQ_GET_DISPLAY_CHANGE_REQEX:
++ case VMMDEVREQ_GET_DISPLAY_CHANGE_REQ_MULTI:
+ case VMMDEVREQ_GET_SEAMLESS_CHANGE_REQ:
+ case VMMDEVREQ_GET_VRDPCHANGE_REQ:
+ case VMMDEVREQ_LOG_STRING:
+diff --git a/include/uapi/linux/vbox_vmmdev_types.h b/include/uapi/linux/vbox_vmmdev_types.h
+index c27289fd619a..f8a8d6b3c521 100644
+--- a/include/uapi/linux/vbox_vmmdev_types.h
++++ b/include/uapi/linux/vbox_vmmdev_types.h
+@@ -63,6 +63,7 @@ enum vmmdev_request_type {
+ VMMDEVREQ_SET_GUEST_CAPABILITIES = 56,
+ VMMDEVREQ_VIDEMODE_SUPPORTED2 = 57, /* since version 3.2.0 */
+ VMMDEVREQ_GET_DISPLAY_CHANGE_REQEX = 80, /* since version 4.2.4 */
++ VMMDEVREQ_GET_DISPLAY_CHANGE_REQ_MULTI = 81,
+ VMMDEVREQ_HGCM_CONNECT = 60,
+ VMMDEVREQ_HGCM_DISCONNECT = 61,
+ VMMDEVREQ_HGCM_CALL32 = 62,
+@@ -92,6 +93,8 @@ enum vmmdev_request_type {
+ VMMDEVREQ_WRITE_COREDUMP = 218,
+ VMMDEVREQ_GUEST_HEARTBEAT = 219,
+ VMMDEVREQ_HEARTBEAT_CONFIGURE = 220,
++ VMMDEVREQ_NT_BUG_CHECK = 221,
++ VMMDEVREQ_VIDEO_UPDATE_MONITOR_POSITIONS = 222,
+ /* Ensure the enum is a 32 bit data-type */
+ VMMDEVREQ_SIZEHACK = 0x7fffffff
+ };
+--
+2.26.2
+
+From 92887e49b5f83dd802f3486143a9b619c7b56947 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 19 May 2020 11:24:43 +0200
+Subject: [PATCH 7/8] virt: vbox: Log unknown ioctl requests as error
+
+Every now and then upstream adds new ioctls without notifying us,
+log unknown ioctl requests as an error to catch these.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/virt/vboxguest/vboxguest_core.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/virt/vboxguest/vboxguest_core.c b/drivers/virt/vboxguest/vboxguest_core.c
+index ffd76b949276..e0e343d0ba93 100644
+--- a/drivers/virt/vboxguest/vboxguest_core.c
++++ b/drivers/virt/vboxguest/vboxguest_core.c
+@@ -1739,7 +1739,7 @@ int vbg_core_ioctl(struct vbg_session *session, unsigned int req, void *data)
+ return vbg_ioctl_log(data);
+ }
+
+- vbg_debug("VGDrvCommonIoCtl: Unknown req %#08x\n", req);
++ vbg_err("Userspace made an unknown ioctl req %#08x\n", req);
+ return -ENOTTY;
+ }
+
+--
+2.26.2
+
+From 10a3a8c4a13e608d24db0a4ed4a284470025346d Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 19 May 2020 18:08:07 +0200
+Subject: [PATCH 8/8] virt: vbox: Fix some comments which talk about the
+ "session spinlock"
+
+The session lock is a mutex, not a spinlock, fix the comments to match.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/virt/vboxguest/vboxguest_core.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/virt/vboxguest/vboxguest_core.c b/drivers/virt/vboxguest/vboxguest_core.c
+index e0e343d0ba93..d99c19551d04 100644
+--- a/drivers/virt/vboxguest/vboxguest_core.c
++++ b/drivers/virt/vboxguest/vboxguest_core.c
+@@ -559,7 +559,7 @@ static int vbg_reset_host_event_filter(struct vbg_dev *gdev,
+ * Changes the event filter mask for the given session.
+ *
+ * This is called in response to VBG_IOCTL_CHANGE_FILTER_MASK as well as to
+- * do session cleanup. Takes the session spinlock.
++ * do session cleanup. Takes the session mutex.
+ *
+ * Return: 0 or negative errno value.
+ * @gdev: The Guest extension device.
+@@ -811,7 +811,7 @@ static int vbg_acquire_session_capabilities(struct vbg_dev *gdev,
+ }
+
+ /**
+- * Sets the guest capabilities for a session. Takes the session spinlock.
++ * Sets the guest capabilities for a session. Takes the session mutex.
+ * Return: 0 or negative errno value.
+ * @gdev: The Guest extension device.
+ * @session: The session.
+--
+2.26.2
+