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

xenbus_dev_backend.c (3082B)


      1// SPDX-License-Identifier: GPL-2.0
      2#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      3
      4#include <linux/slab.h>
      5#include <linux/types.h>
      6#include <linux/mm.h>
      7#include <linux/fs.h>
      8#include <linux/miscdevice.h>
      9#include <linux/init.h>
     10#include <linux/capability.h>
     11
     12#include <xen/xen.h>
     13#include <xen/page.h>
     14#include <xen/xenbus.h>
     15#include <xen/xenbus_dev.h>
     16#include <xen/grant_table.h>
     17#include <xen/events.h>
     18#include <asm/xen/hypervisor.h>
     19
     20#include "xenbus.h"
     21
     22static int xenbus_backend_open(struct inode *inode, struct file *filp)
     23{
     24	if (!capable(CAP_SYS_ADMIN))
     25		return -EPERM;
     26
     27	return nonseekable_open(inode, filp);
     28}
     29
     30static long xenbus_alloc(domid_t domid)
     31{
     32	struct evtchn_alloc_unbound arg;
     33	int err = -EEXIST;
     34
     35	xs_suspend();
     36
     37	/* If xenstored_ready is nonzero, that means we have already talked to
     38	 * xenstore and set up watches. These watches will be restored by
     39	 * xs_resume, but that requires communication over the port established
     40	 * below that is not visible to anyone until the ioctl returns.
     41	 *
     42	 * This can be resolved by splitting the ioctl into two parts
     43	 * (postponing the resume until xenstored is active) but this is
     44	 * unnecessarily complex for the intended use where xenstored is only
     45	 * started once - so return -EEXIST if it's already running.
     46	 */
     47	if (xenstored_ready)
     48		goto out_err;
     49
     50	gnttab_grant_foreign_access_ref(GNTTAB_RESERVED_XENSTORE, domid,
     51			virt_to_gfn(xen_store_interface), 0 /* writable */);
     52
     53	arg.dom = DOMID_SELF;
     54	arg.remote_dom = domid;
     55
     56	err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &arg);
     57	if (err)
     58		goto out_err;
     59
     60	if (xen_store_evtchn > 0)
     61		xb_deinit_comms();
     62
     63	xen_store_evtchn = arg.port;
     64
     65	xs_resume();
     66
     67	return arg.port;
     68
     69 out_err:
     70	xs_suspend_cancel();
     71	return err;
     72}
     73
     74static long xenbus_backend_ioctl(struct file *file, unsigned int cmd,
     75				 unsigned long data)
     76{
     77	if (!capable(CAP_SYS_ADMIN))
     78		return -EPERM;
     79
     80	switch (cmd) {
     81	case IOCTL_XENBUS_BACKEND_EVTCHN:
     82		if (xen_store_evtchn > 0)
     83			return xen_store_evtchn;
     84		return -ENODEV;
     85	case IOCTL_XENBUS_BACKEND_SETUP:
     86		return xenbus_alloc(data);
     87	default:
     88		return -ENOTTY;
     89	}
     90}
     91
     92static int xenbus_backend_mmap(struct file *file, struct vm_area_struct *vma)
     93{
     94	size_t size = vma->vm_end - vma->vm_start;
     95
     96	if (!capable(CAP_SYS_ADMIN))
     97		return -EPERM;
     98
     99	if ((size > PAGE_SIZE) || (vma->vm_pgoff != 0))
    100		return -EINVAL;
    101
    102	if (remap_pfn_range(vma, vma->vm_start,
    103			    virt_to_pfn(xen_store_interface),
    104			    size, vma->vm_page_prot))
    105		return -EAGAIN;
    106
    107	return 0;
    108}
    109
    110static const struct file_operations xenbus_backend_fops = {
    111	.open = xenbus_backend_open,
    112	.mmap = xenbus_backend_mmap,
    113	.unlocked_ioctl = xenbus_backend_ioctl,
    114};
    115
    116static struct miscdevice xenbus_backend_dev = {
    117	.minor = MISC_DYNAMIC_MINOR,
    118	.name = "xen/xenbus_backend",
    119	.fops = &xenbus_backend_fops,
    120};
    121
    122static int __init xenbus_backend_init(void)
    123{
    124	int err;
    125
    126	if (!xen_initial_domain())
    127		return -ENODEV;
    128
    129	err = misc_register(&xenbus_backend_dev);
    130	if (err)
    131		pr_err("Could not register xenbus backend device\n");
    132	return err;
    133}
    134device_initcall(xenbus_backend_init);