cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vboxguest_linux.c (13034B)


      1/* SPDX-License-Identifier: GPL-2.0 */
      2/*
      3 * vboxguest linux pci driver, char-dev and input-device code,
      4 *
      5 * Copyright (C) 2006-2016 Oracle Corporation
      6 */
      7
      8#include <linux/cred.h>
      9#include <linux/input.h>
     10#include <linux/kernel.h>
     11#include <linux/miscdevice.h>
     12#include <linux/module.h>
     13#include <linux/pci.h>
     14#include <linux/poll.h>
     15#include <linux/vbox_utils.h>
     16#include "vboxguest_core.h"
     17
     18/** The device name. */
     19#define DEVICE_NAME		"vboxguest"
     20/** The device name for the device node open to everyone. */
     21#define DEVICE_NAME_USER	"vboxuser"
     22/** VirtualBox PCI vendor ID. */
     23#define VBOX_VENDORID		0x80ee
     24/** VMMDev PCI card product ID. */
     25#define VMMDEV_DEVICEID		0xcafe
     26
     27/** Mutex protecting the global vbg_gdev pointer used by vbg_get/put_gdev. */
     28static DEFINE_MUTEX(vbg_gdev_mutex);
     29/** Global vbg_gdev pointer used by vbg_get/put_gdev. */
     30static struct vbg_dev *vbg_gdev;
     31
     32static u32 vbg_misc_device_requestor(struct inode *inode)
     33{
     34	u32 requestor = VMMDEV_REQUESTOR_USERMODE |
     35			VMMDEV_REQUESTOR_CON_DONT_KNOW |
     36			VMMDEV_REQUESTOR_TRUST_NOT_GIVEN;
     37
     38	if (from_kuid(current_user_ns(), current_uid()) == 0)
     39		requestor |= VMMDEV_REQUESTOR_USR_ROOT;
     40	else
     41		requestor |= VMMDEV_REQUESTOR_USR_USER;
     42
     43	if (in_egroup_p(inode->i_gid))
     44		requestor |= VMMDEV_REQUESTOR_GRP_VBOX;
     45
     46	return requestor;
     47}
     48
     49static int vbg_misc_device_open(struct inode *inode, struct file *filp)
     50{
     51	struct vbg_session *session;
     52	struct vbg_dev *gdev;
     53
     54	/* misc_open sets filp->private_data to our misc device */
     55	gdev = container_of(filp->private_data, struct vbg_dev, misc_device);
     56
     57	session = vbg_core_open_session(gdev, vbg_misc_device_requestor(inode));
     58	if (IS_ERR(session))
     59		return PTR_ERR(session);
     60
     61	filp->private_data = session;
     62	return 0;
     63}
     64
     65static int vbg_misc_device_user_open(struct inode *inode, struct file *filp)
     66{
     67	struct vbg_session *session;
     68	struct vbg_dev *gdev;
     69
     70	/* misc_open sets filp->private_data to our misc device */
     71	gdev = container_of(filp->private_data, struct vbg_dev,
     72			    misc_device_user);
     73
     74	session = vbg_core_open_session(gdev, vbg_misc_device_requestor(inode) |
     75					      VMMDEV_REQUESTOR_USER_DEVICE);
     76	if (IS_ERR(session))
     77		return PTR_ERR(session);
     78
     79	filp->private_data = session;
     80	return 0;
     81}
     82
     83/**
     84 * Close device.
     85 * Return: 0 on success, negated errno on failure.
     86 * @inode:		Pointer to inode info structure.
     87 * @filp:		Associated file pointer.
     88 */
     89static int vbg_misc_device_close(struct inode *inode, struct file *filp)
     90{
     91	vbg_core_close_session(filp->private_data);
     92	filp->private_data = NULL;
     93	return 0;
     94}
     95
     96/**
     97 * Device I/O Control entry point.
     98 * Return: 0 on success, negated errno on failure.
     99 * @filp:		Associated file pointer.
    100 * @req:		The request specified to ioctl().
    101 * @arg:		The argument specified to ioctl().
    102 */
    103static long vbg_misc_device_ioctl(struct file *filp, unsigned int req,
    104				  unsigned long arg)
    105{
    106	struct vbg_session *session = filp->private_data;
    107	size_t returned_size, size;
    108	struct vbg_ioctl_hdr hdr;
    109	bool is_vmmdev_req;
    110	int ret = 0;
    111	void *buf;
    112
    113	if (copy_from_user(&hdr, (void *)arg, sizeof(hdr)))
    114		return -EFAULT;
    115
    116	if (hdr.version != VBG_IOCTL_HDR_VERSION)
    117		return -EINVAL;
    118
    119	if (hdr.size_in < sizeof(hdr) ||
    120	    (hdr.size_out && hdr.size_out < sizeof(hdr)))
    121		return -EINVAL;
    122
    123	size = max(hdr.size_in, hdr.size_out);
    124	if (_IOC_SIZE(req) && _IOC_SIZE(req) != size)
    125		return -EINVAL;
    126	if (size > SZ_16M)
    127		return -E2BIG;
    128
    129	/*
    130	 * IOCTL_VMMDEV_REQUEST needs the buffer to be below 4G to avoid
    131	 * the need for a bounce-buffer and another copy later on.
    132	 */
    133	is_vmmdev_req = (req & ~IOCSIZE_MASK) == VBG_IOCTL_VMMDEV_REQUEST(0) ||
    134			 req == VBG_IOCTL_VMMDEV_REQUEST_BIG ||
    135			 req == VBG_IOCTL_VMMDEV_REQUEST_BIG_ALT;
    136
    137	if (is_vmmdev_req)
    138		buf = vbg_req_alloc(size, VBG_IOCTL_HDR_TYPE_DEFAULT,
    139				    session->requestor);
    140	else
    141		buf = kmalloc(size, GFP_KERNEL);
    142	if (!buf)
    143		return -ENOMEM;
    144
    145	*((struct vbg_ioctl_hdr *)buf) = hdr;
    146	if (copy_from_user(buf + sizeof(hdr), (void *)arg + sizeof(hdr),
    147			   hdr.size_in - sizeof(hdr))) {
    148		ret = -EFAULT;
    149		goto out;
    150	}
    151	if (hdr.size_in < size)
    152		memset(buf + hdr.size_in, 0, size -  hdr.size_in);
    153
    154	ret = vbg_core_ioctl(session, req, buf);
    155	if (ret)
    156		goto out;
    157
    158	returned_size = ((struct vbg_ioctl_hdr *)buf)->size_out;
    159	if (returned_size > size) {
    160		vbg_debug("%s: too much output data %zu > %zu\n",
    161			  __func__, returned_size, size);
    162		returned_size = size;
    163	}
    164	if (copy_to_user((void *)arg, buf, returned_size) != 0)
    165		ret = -EFAULT;
    166
    167out:
    168	if (is_vmmdev_req)
    169		vbg_req_free(buf, size);
    170	else
    171		kfree(buf);
    172
    173	return ret;
    174}
    175
    176/** The file_operations structures. */
    177static const struct file_operations vbg_misc_device_fops = {
    178	.owner			= THIS_MODULE,
    179	.open			= vbg_misc_device_open,
    180	.release		= vbg_misc_device_close,
    181	.unlocked_ioctl		= vbg_misc_device_ioctl,
    182#ifdef CONFIG_COMPAT
    183	.compat_ioctl		= vbg_misc_device_ioctl,
    184#endif
    185};
    186static const struct file_operations vbg_misc_device_user_fops = {
    187	.owner			= THIS_MODULE,
    188	.open			= vbg_misc_device_user_open,
    189	.release		= vbg_misc_device_close,
    190	.unlocked_ioctl		= vbg_misc_device_ioctl,
    191#ifdef CONFIG_COMPAT
    192	.compat_ioctl		= vbg_misc_device_ioctl,
    193#endif
    194};
    195
    196/**
    197 * Called when the input device is first opened.
    198 *
    199 * Sets up absolute mouse reporting.
    200 */
    201static int vbg_input_open(struct input_dev *input)
    202{
    203	struct vbg_dev *gdev = input_get_drvdata(input);
    204	u32 feat = VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE | VMMDEV_MOUSE_NEW_PROTOCOL;
    205
    206	return vbg_core_set_mouse_status(gdev, feat);
    207}
    208
    209/**
    210 * Called if all open handles to the input device are closed.
    211 *
    212 * Disables absolute reporting.
    213 */
    214static void vbg_input_close(struct input_dev *input)
    215{
    216	struct vbg_dev *gdev = input_get_drvdata(input);
    217
    218	vbg_core_set_mouse_status(gdev, 0);
    219}
    220
    221/**
    222 * Creates the kernel input device.
    223 *
    224 * Return: 0 on success, negated errno on failure.
    225 */
    226static int vbg_create_input_device(struct vbg_dev *gdev)
    227{
    228	struct input_dev *input;
    229
    230	input = devm_input_allocate_device(gdev->dev);
    231	if (!input)
    232		return -ENOMEM;
    233
    234	input->id.bustype = BUS_PCI;
    235	input->id.vendor = VBOX_VENDORID;
    236	input->id.product = VMMDEV_DEVICEID;
    237	input->open = vbg_input_open;
    238	input->close = vbg_input_close;
    239	input->dev.parent = gdev->dev;
    240	input->name = "VirtualBox mouse integration";
    241
    242	input_set_abs_params(input, ABS_X, VMMDEV_MOUSE_RANGE_MIN,
    243			     VMMDEV_MOUSE_RANGE_MAX, 0, 0);
    244	input_set_abs_params(input, ABS_Y, VMMDEV_MOUSE_RANGE_MIN,
    245			     VMMDEV_MOUSE_RANGE_MAX, 0, 0);
    246	input_set_capability(input, EV_KEY, BTN_MOUSE);
    247	input_set_drvdata(input, gdev);
    248
    249	gdev->input = input;
    250
    251	return input_register_device(gdev->input);
    252}
    253
    254static ssize_t host_version_show(struct device *dev,
    255				 struct device_attribute *attr, char *buf)
    256{
    257	struct vbg_dev *gdev = dev_get_drvdata(dev);
    258
    259	return sprintf(buf, "%s\n", gdev->host_version);
    260}
    261
    262static ssize_t host_features_show(struct device *dev,
    263				 struct device_attribute *attr, char *buf)
    264{
    265	struct vbg_dev *gdev = dev_get_drvdata(dev);
    266
    267	return sprintf(buf, "%#x\n", gdev->host_features);
    268}
    269
    270static DEVICE_ATTR_RO(host_version);
    271static DEVICE_ATTR_RO(host_features);
    272
    273/**
    274 * Does the PCI detection and init of the device.
    275 *
    276 * Return: 0 on success, negated errno on failure.
    277 */
    278static int vbg_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
    279{
    280	struct device *dev = &pci->dev;
    281	resource_size_t io, io_len, mmio, mmio_len;
    282	struct vmmdev_memory *vmmdev;
    283	struct vbg_dev *gdev;
    284	int ret;
    285
    286	gdev = devm_kzalloc(dev, sizeof(*gdev), GFP_KERNEL);
    287	if (!gdev)
    288		return -ENOMEM;
    289
    290	ret = pci_enable_device(pci);
    291	if (ret != 0) {
    292		vbg_err("vboxguest: Error enabling device: %d\n", ret);
    293		return ret;
    294	}
    295
    296	ret = -ENODEV;
    297
    298	io = pci_resource_start(pci, 0);
    299	io_len = pci_resource_len(pci, 0);
    300	if (!io || !io_len) {
    301		vbg_err("vboxguest: Error IO-port resource (0) is missing\n");
    302		goto err_disable_pcidev;
    303	}
    304	if (devm_request_region(dev, io, io_len, DEVICE_NAME) == NULL) {
    305		vbg_err("vboxguest: Error could not claim IO resource\n");
    306		ret = -EBUSY;
    307		goto err_disable_pcidev;
    308	}
    309
    310	mmio = pci_resource_start(pci, 1);
    311	mmio_len = pci_resource_len(pci, 1);
    312	if (!mmio || !mmio_len) {
    313		vbg_err("vboxguest: Error MMIO resource (1) is missing\n");
    314		goto err_disable_pcidev;
    315	}
    316
    317	if (devm_request_mem_region(dev, mmio, mmio_len, DEVICE_NAME) == NULL) {
    318		vbg_err("vboxguest: Error could not claim MMIO resource\n");
    319		ret = -EBUSY;
    320		goto err_disable_pcidev;
    321	}
    322
    323	vmmdev = devm_ioremap(dev, mmio, mmio_len);
    324	if (!vmmdev) {
    325		vbg_err("vboxguest: Error ioremap failed; MMIO addr=%pap size=%pap\n",
    326			&mmio, &mmio_len);
    327		goto err_disable_pcidev;
    328	}
    329
    330	/* Validate MMIO region version and size. */
    331	if (vmmdev->version != VMMDEV_MEMORY_VERSION ||
    332	    vmmdev->size < 32 || vmmdev->size > mmio_len) {
    333		vbg_err("vboxguest: Bogus VMMDev memory; version=%08x (expected %08x) size=%d (expected <= %d)\n",
    334			vmmdev->version, VMMDEV_MEMORY_VERSION,
    335			vmmdev->size, (int)mmio_len);
    336		goto err_disable_pcidev;
    337	}
    338
    339	gdev->io_port = io;
    340	gdev->mmio = vmmdev;
    341	gdev->dev = dev;
    342	gdev->misc_device.minor = MISC_DYNAMIC_MINOR;
    343	gdev->misc_device.name = DEVICE_NAME;
    344	gdev->misc_device.fops = &vbg_misc_device_fops;
    345	gdev->misc_device_user.minor = MISC_DYNAMIC_MINOR;
    346	gdev->misc_device_user.name = DEVICE_NAME_USER;
    347	gdev->misc_device_user.fops = &vbg_misc_device_user_fops;
    348
    349	ret = vbg_core_init(gdev, VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
    350	if (ret)
    351		goto err_disable_pcidev;
    352
    353	ret = vbg_create_input_device(gdev);
    354	if (ret) {
    355		vbg_err("vboxguest: Error creating input device: %d\n", ret);
    356		goto err_vbg_core_exit;
    357	}
    358
    359	ret = devm_request_irq(dev, pci->irq, vbg_core_isr, IRQF_SHARED,
    360			       DEVICE_NAME, gdev);
    361	if (ret) {
    362		vbg_err("vboxguest: Error requesting irq: %d\n", ret);
    363		goto err_vbg_core_exit;
    364	}
    365
    366	ret = misc_register(&gdev->misc_device);
    367	if (ret) {
    368		vbg_err("vboxguest: Error misc_register %s failed: %d\n",
    369			DEVICE_NAME, ret);
    370		goto err_vbg_core_exit;
    371	}
    372
    373	ret = misc_register(&gdev->misc_device_user);
    374	if (ret) {
    375		vbg_err("vboxguest: Error misc_register %s failed: %d\n",
    376			DEVICE_NAME_USER, ret);
    377		goto err_unregister_misc_device;
    378	}
    379
    380	mutex_lock(&vbg_gdev_mutex);
    381	if (!vbg_gdev)
    382		vbg_gdev = gdev;
    383	else
    384		ret = -EBUSY;
    385	mutex_unlock(&vbg_gdev_mutex);
    386
    387	if (ret) {
    388		vbg_err("vboxguest: Error more then 1 vbox guest pci device\n");
    389		goto err_unregister_misc_device_user;
    390	}
    391
    392	pci_set_drvdata(pci, gdev);
    393	device_create_file(dev, &dev_attr_host_version);
    394	device_create_file(dev, &dev_attr_host_features);
    395
    396	vbg_info("vboxguest: misc device minor %d, IRQ %d, I/O port %x, MMIO at %pap (size %pap)\n",
    397		 gdev->misc_device.minor, pci->irq, gdev->io_port,
    398		 &mmio, &mmio_len);
    399
    400	return 0;
    401
    402err_unregister_misc_device_user:
    403	misc_deregister(&gdev->misc_device_user);
    404err_unregister_misc_device:
    405	misc_deregister(&gdev->misc_device);
    406err_vbg_core_exit:
    407	vbg_core_exit(gdev);
    408err_disable_pcidev:
    409	pci_disable_device(pci);
    410
    411	return ret;
    412}
    413
    414static void vbg_pci_remove(struct pci_dev *pci)
    415{
    416	struct vbg_dev *gdev = pci_get_drvdata(pci);
    417
    418	mutex_lock(&vbg_gdev_mutex);
    419	vbg_gdev = NULL;
    420	mutex_unlock(&vbg_gdev_mutex);
    421
    422	device_remove_file(gdev->dev, &dev_attr_host_features);
    423	device_remove_file(gdev->dev, &dev_attr_host_version);
    424	misc_deregister(&gdev->misc_device_user);
    425	misc_deregister(&gdev->misc_device);
    426	vbg_core_exit(gdev);
    427	pci_disable_device(pci);
    428}
    429
    430struct vbg_dev *vbg_get_gdev(void)
    431{
    432	mutex_lock(&vbg_gdev_mutex);
    433
    434	/*
    435	 * Note on success we keep the mutex locked until vbg_put_gdev(),
    436	 * this stops vbg_pci_remove from removing the device from underneath
    437	 * vboxsf. vboxsf will only hold a reference for a short while.
    438	 */
    439	if (vbg_gdev)
    440		return vbg_gdev;
    441
    442	mutex_unlock(&vbg_gdev_mutex);
    443	return ERR_PTR(-ENODEV);
    444}
    445EXPORT_SYMBOL(vbg_get_gdev);
    446
    447void vbg_put_gdev(struct vbg_dev *gdev)
    448{
    449	WARN_ON(gdev != vbg_gdev);
    450	mutex_unlock(&vbg_gdev_mutex);
    451}
    452EXPORT_SYMBOL(vbg_put_gdev);
    453
    454/**
    455 * Callback for mouse events.
    456 *
    457 * This is called at the end of the ISR, after leaving the event spinlock, if
    458 * VMMDEV_EVENT_MOUSE_POSITION_CHANGED was raised by the host.
    459 *
    460 * @gdev:		The device extension.
    461 */
    462void vbg_linux_mouse_event(struct vbg_dev *gdev)
    463{
    464	int rc;
    465
    466	/* Report events to the kernel input device */
    467	gdev->mouse_status_req->mouse_features = 0;
    468	gdev->mouse_status_req->pointer_pos_x = 0;
    469	gdev->mouse_status_req->pointer_pos_y = 0;
    470	rc = vbg_req_perform(gdev, gdev->mouse_status_req);
    471	if (rc >= 0) {
    472		input_report_abs(gdev->input, ABS_X,
    473				 gdev->mouse_status_req->pointer_pos_x);
    474		input_report_abs(gdev->input, ABS_Y,
    475				 gdev->mouse_status_req->pointer_pos_y);
    476		input_sync(gdev->input);
    477	}
    478}
    479
    480static const struct pci_device_id vbg_pci_ids[] = {
    481	{ .vendor = VBOX_VENDORID, .device = VMMDEV_DEVICEID },
    482	{}
    483};
    484MODULE_DEVICE_TABLE(pci,  vbg_pci_ids);
    485
    486static struct pci_driver vbg_pci_driver = {
    487	.name		= DEVICE_NAME,
    488	.id_table	= vbg_pci_ids,
    489	.probe		= vbg_pci_probe,
    490	.remove		= vbg_pci_remove,
    491};
    492
    493module_pci_driver(vbg_pci_driver);
    494
    495MODULE_AUTHOR("Oracle Corporation");
    496MODULE_DESCRIPTION("Oracle VM VirtualBox Guest Additions for Linux Module");
    497MODULE_LICENSE("GPL");