linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Norbert Slusarek <nslusarek@gmx.net>
To: gregkh@linuxfoundation.org, arnd@arndb.de, jhansen@vmware.com
Cc: linux-kernel@vger.kernel.org
Subject: [PATCH RESEND] misc/vmw_vmci: bail out earlier on too big queue allocation
Date: Mon, 23 Nov 2020 22:01:00 +0100	[thread overview]
Message-ID: <trinity-56749cfc-536b-45e2-8e6f-621754c07824-1606165260518@3c-app-gmx-bs09> (raw)

From: Norbert Slusarek <nslusarek@gmx.net>
Date: Mon, 23 Nov 2020 21:53:41 +0100
Subject: [PATCH RESEND] misc/vmw_vmci: bail out earlier on too big queue allocation

For the allocation of a queue pair in qp_host_alloc_queue() an arbitrary value
can be passed for produce_size, which can lead to miscalculation of memory we'd
like to allocate in one take. A warning is triggered at __alloc_pages_nodemask()
in mm/page_alloc.c:4737 which aborts the false allocation, but it results in a
VMware machine freezing for an infinite time.

Signed-off-by: Norbert Slusarek <nslusarek@gmx.net>
---

Resend because of email and formatting issues.

To provide an accurate explanation of the problem, I'll describe my observations
and include a PoC you can run yourself. The value for produce_size (0x7ffe7001)
wasn't chosen randomly, it's the least value which can trigger the warning. With
this value, calculations are done in qp_host_alloc_queue() before
calling kzalloc() with queue_size + queue_page_size. The calculation of
queue_size involves taking the size of *queue->kernel_if, which on 5.10-rc4 has
the size of 72 bytes and on 5.4.79 it's 168 bytes. While on 5.10-rc4 the size
argument for kzalloc() won't surpass the maximum value of 4096*1024 for an
individual allocation (for produce_size = 0x7ffe7001 -> kzalloc(4194216)), it
will be greater on the stable 5.4.79 kernel (for produce_size = 0x7ffe7001 ->
kzalloc(4194312)). This will ultimately lead to a warning on the stable 5.4
kernel, but not on the upstream kernel, so ideally my patch would be backported
to stable kernels. Eventhough the warning in __alloc_pages_nodemask() already
aborts the oversized allocation of memory, VMware will hang for an infinite
time, hence I wanted to provide this simple patch. We shouldn't rely on the page
allocator to abort it anyways, it's better to keep it clean and check for a too
large allocation before calling kzalloc(). When I ran the PoC in QEMU and on a
host machine, I didn't experience any freezes at all, but the warning gets
triggered.

PoC (run on 5.4 stable kernel and VMCI driver loaded for /dev/vmci):

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <endian.h>
#include <stdint.h>
#include <string.h>
#include <sys/syscall.h>
#include <sys/types.h>

#define VMADDR_CID_LOCAL		1
#define IOCTL_VMCI_VERSION2		1959
#define IOCTL_VMCI_INIT_CONTEXT		1952
#define IOCTL_VMCI_QUEUEPAIR_ALLOC	1960
#define VMCI_VERSION_PREHOSTQP		0x80000
#define VMCI_NO_PRIVILEGE_FLAGS		0

struct vmci_handle {
	unsigned int context;
	unsigned int resource;
};

struct vmci_qp_alloc_info {
	struct vmci_handle handle;
	unsigned int peer;
	unsigned int flags;
	unsigned long produce_size;
	unsigned long consume_size;
	unsigned long ppn_va;
	unsigned long num_ppns;
	int result;
	unsigned int version;
};

struct vmci_init_blk {
	int cid;
	int flags;
};

int main(void)
{
	int fd, flag;

	fd = syscall(__NR_openat, -100, "/dev/vmci", O_RDWR, 0);

	flag = VMCI_VERSION_PREHOSTQP;
        syscall(__NR_ioctl, fd, IOCTL_VMCI_VERSION2, &flag);

	struct vmci_init_blk cxt = {
		.cid = VMADDR_CID_LOCAL,
		.flags = VMCI_NO_PRIVILEGE_FLAGS
	};
	syscall(__NR_ioctl, fd, IOCTL_VMCI_INIT_CONTEXT, &cxt);

	struct vmci_qp_alloc_info qp = {
		.handle.context = VMADDR_CID_LOCAL,
		.handle.resource = 0,
		.peer = 0,
		.flags = 0,
		.produce_size = 0x7ffe7001,
		.consume_size = 0,
		.ppn_va = 0,
		.num_ppns = 0,
		.result = -1,
		.version = 0
	};
	syscall(__NR_ioctl, fd, IOCTL_VMCI_QUEUEPAIR_ALLOC, &qp);

	return 0;
}

---
 drivers/misc/vmw_vmci/vmci_queue_pair.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c
index c49065887e8f..997ff32475b2 100644
--- a/drivers/misc/vmw_vmci/vmci_queue_pair.c
+++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c
@@ -526,6 +526,7 @@ static struct vmci_queue *qp_host_alloc_queue(u64 size)
 	struct vmci_queue *queue;
 	size_t queue_page_size;
 	u64 num_pages;
+	unsigned int order;
 	const size_t queue_size = sizeof(*queue) + sizeof(*(queue->kernel_if));

 	if (size > SIZE_MAX - PAGE_SIZE)
@@ -537,6 +538,10 @@ static struct vmci_queue *qp_host_alloc_queue(u64 size)

 	queue_page_size = num_pages * sizeof(*queue->kernel_if->u.h.page);

+	order = get_order(queue_size + queue_page_size);
+	if (order >= MAX_ORDER)
+		return NULL;
+
 	queue = kzalloc(queue_size + queue_page_size, GFP_KERNEL);
 	if (queue) {
 		queue->q_header = NULL;
--
2.29.2

             reply	other threads:[~2020-11-23 21:01 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-23 21:01 Norbert Slusarek [this message]
2020-12-01 20:19 ` [PATCH RESEND] misc/vmw_vmci: bail out earlier on too big queue allocation Arnd Bergmann
2020-12-02 10:05   ` Stefano Garzarella
2020-12-07 14:40     ` Jorgen Hansen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=trinity-56749cfc-536b-45e2-8e6f-621754c07824-1606165260518@3c-app-gmx-bs09 \
    --to=nslusarek@gmx.net \
    --cc=arnd@arndb.de \
    --cc=gregkh@linuxfoundation.org \
    --cc=jhansen@vmware.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).