summaryrefslogtreecommitdiff
path: root/drivers/xen
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/xen')
-rw-r--r--drivers/xen/events/events_base.c1
-rw-r--r--drivers/xen/gntalloc.c19
-rw-r--r--drivers/xen/gntdev.c8
-rw-r--r--drivers/xen/grant-dma-ops.c5
-rw-r--r--drivers/xen/grant-table.c1
-rw-r--r--drivers/xen/mcelog.c6
-rw-r--r--drivers/xen/platform-pci.c8
-rw-r--r--drivers/xen/privcmd.c7
-rw-r--r--drivers/xen/pvcalls-front.c88
-rw-r--r--drivers/xen/sys-hypervisor.c8
-rw-r--r--drivers/xen/xen-acpi-pad.c6
-rw-r--r--drivers/xen/xen-balloon.c6
-rw-r--r--drivers/xen/xen-front-pgdir-shbuf.c12
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c13
-rw-r--r--drivers/xen/xenbus/xenbus_xs.c9
15 files changed, 151 insertions, 46 deletions
diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
index bc9a41662efc..6ea945508a89 100644
--- a/drivers/xen/events/events_base.c
+++ b/drivers/xen/events/events_base.c
@@ -40,6 +40,7 @@
#include <linux/ktime.h>
#ifdef CONFIG_X86
+#include <asm/cpuid/api.h>
#include <asm/desc.h>
#include <asm/ptrace.h>
#include <asm/idtentry.h>
diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c
index eadedd1e963e..3218686be45b 100644
--- a/drivers/xen/gntalloc.c
+++ b/drivers/xen/gntalloc.c
@@ -70,14 +70,14 @@
#include <xen/gntalloc.h>
#include <xen/events.h>
-static int limit = 1024;
-module_param(limit, int, 0644);
+static unsigned int limit = 1024;
+module_param(limit, uint, 0644);
MODULE_PARM_DESC(limit, "Maximum number of grants that may be allocated by "
"the gntalloc device");
static LIST_HEAD(gref_list);
static DEFINE_MUTEX(gref_mutex);
-static int gref_size;
+static unsigned int gref_size;
struct notify_info {
uint16_t pgoff:12; /* Bits 0-11: Offset of the byte to clear */
@@ -272,6 +272,7 @@ static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv,
int rc = 0;
struct ioctl_gntalloc_alloc_gref op;
uint32_t *gref_ids;
+ unsigned int limit_snapshot;
pr_debug("%s: priv %p\n", __func__, priv);
@@ -280,6 +281,12 @@ static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv,
goto out;
}
+ limit_snapshot = READ_ONCE(limit);
+ if (op.count > limit_snapshot) {
+ rc = -ENOSPC;
+ goto out;
+ }
+
gref_ids = kcalloc(op.count, sizeof(gref_ids[0]), GFP_KERNEL);
if (!gref_ids) {
rc = -ENOMEM;
@@ -292,14 +299,16 @@ static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv,
* are about to enforce, removing them here is a good idea.
*/
do_cleanup();
- if (gref_size + op.count > limit) {
+ limit_snapshot = READ_ONCE(limit);
+ if (gref_size > limit_snapshot ||
+ op.count > limit_snapshot - gref_size) {
mutex_unlock(&gref_mutex);
rc = -ENOSPC;
goto out_free;
}
gref_size += op.count;
op.index = priv->index;
- priv->index += op.count * PAGE_SIZE;
+ priv->index += (uint64_t)op.count * PAGE_SIZE;
mutex_unlock(&gref_mutex);
rc = add_grefs(&op, gref_ids, priv);
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
index 61ea855c4508..1dcc4675580e 100644
--- a/drivers/xen/gntdev.c
+++ b/drivers/xen/gntdev.c
@@ -670,11 +670,15 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv,
mutex_lock(&priv->lock);
gntdev_add_map(priv, map);
op.index = map->index << PAGE_SHIFT;
- mutex_unlock(&priv->lock);
- if (copy_to_user(u, &op, sizeof(op)) != 0)
+ if (copy_to_user(u, &op, sizeof(op)) != 0) {
+ list_del(&map->next);
+ mutex_unlock(&priv->lock);
+ gntdev_put_map(priv, map);
return -EFAULT;
+ }
+ mutex_unlock(&priv->lock);
return 0;
}
diff --git a/drivers/xen/grant-dma-ops.c b/drivers/xen/grant-dma-ops.c
index c2603e700178..2aa1a772a0ff 100644
--- a/drivers/xen/grant-dma-ops.c
+++ b/drivers/xen/grant-dma-ops.c
@@ -319,14 +319,13 @@ static int xen_dt_grant_init_backend_domid(struct device *dev,
struct device_node *np,
domid_t *backend_domid)
{
- struct of_phandle_args iommu_spec = { .args_count = 1 };
+ struct of_phandle_args iommu_spec = {};
if (dev_is_pci(dev)) {
struct pci_dev *pdev = to_pci_dev(dev);
u32 rid = PCI_DEVID(pdev->bus->number, pdev->devfn);
- if (of_map_id(np, rid, "iommu-map", "iommu-map-mask", &iommu_spec.np,
- iommu_spec.args)) {
+ if (of_map_iommu_id(np, rid, &iommu_spec)) {
dev_dbg(dev, "Cannot translate ID\n");
return -ESRCH;
}
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index a6abf1ccd54c..35f879dc5dfb 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -59,6 +59,7 @@
#include <xen/swiotlb-xen.h>
#include <xen/balloon.h>
#ifdef CONFIG_X86
+#include <asm/cpuid/api.h>
#include <asm/xen/cpuid.h>
#endif
#include <xen/mem-reservation.h>
diff --git a/drivers/xen/mcelog.c b/drivers/xen/mcelog.c
index 53a8720f5cae..32ab419bb503 100644
--- a/drivers/xen/mcelog.c
+++ b/drivers/xen/mcelog.c
@@ -54,8 +54,8 @@
#include <asm/xen/hypervisor.h>
static struct mc_info g_mi;
-static struct mcinfo_logical_cpu *g_physinfo;
-static uint32_t ncpus;
+static struct mcinfo_logical_cpu *g_physinfo __ro_after_init;
+static uint32_t ncpus __ro_after_init;
static DEFINE_MUTEX(mcelog_lock);
@@ -182,7 +182,7 @@ static const struct file_operations xen_mce_chrdev_ops = {
.unlocked_ioctl = xen_mce_chrdev_ioctl,
};
-static struct miscdevice xen_mce_chrdev_device = {
+static struct miscdevice xen_mce_chrdev_device __ro_after_init = {
MISC_MCELOG_MINOR,
"mcelog",
&xen_mce_chrdev_ops,
diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c
index 1db82da56db6..f2438232518c 100644
--- a/drivers/xen/platform-pci.c
+++ b/drivers/xen/platform-pci.c
@@ -174,11 +174,9 @@ pci_out:
}
static const struct pci_device_id platform_pci_tbl[] = {
- {PCI_VENDOR_ID_XEN, PCI_DEVICE_ID_XEN_PLATFORM,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_XEN, PCI_DEVICE_ID_XEN_PLATFORM_XS61,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {0,}
+ { PCI_VDEVICE(XEN, PCI_DEVICE_ID_XEN_PLATFORM) },
+ { PCI_VDEVICE(XEN, PCI_DEVICE_ID_XEN_PLATFORM_XS61) },
+ { }
};
static const struct dev_pm_ops platform_pm_ops = {
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
index 15ba592236e8..725a49a0eee7 100644
--- a/drivers/xen/privcmd.c
+++ b/drivers/xen/privcmd.c
@@ -1620,6 +1620,12 @@ static void privcmd_close(struct vm_area_struct *vma)
kvfree(pages);
}
+static int privcmd_may_split(struct vm_area_struct *area, unsigned long addr)
+{
+ /* Forbid splitting, avoids double free via privcmd_close(). */
+ return -EINVAL;
+}
+
static vm_fault_t privcmd_fault(struct vm_fault *vmf)
{
printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n",
@@ -1631,6 +1637,7 @@ static vm_fault_t privcmd_fault(struct vm_fault *vmf)
static const struct vm_operations_struct privcmd_vm_ops = {
.close = privcmd_close,
+ .may_split = privcmd_may_split,
.fault = privcmd_fault
};
diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
index 50ce4820f7ee..3e7aa807c317 100644
--- a/drivers/xen/pvcalls-front.c
+++ b/drivers/xen/pvcalls-front.c
@@ -32,6 +32,7 @@ struct pvcalls_bedata {
struct xen_pvcalls_front_ring ring;
grant_ref_t ref;
int irq;
+ bool disabled;
struct list_head socket_mappings;
spinlock_t socket_lock;
@@ -131,6 +132,20 @@ static inline int get_request(struct pvcalls_bedata *bedata, int *req_id)
return 0;
}
+/*
+ * Wait for the backend's response to req_id, or for the frontend to be
+ * disabled because the backend violated the wire protocol. Returns 0 once
+ * the response has arrived, or -EIO if the frontend was disabled.
+ */
+static int pvcalls_front_wait_rsp(struct pvcalls_bedata *bedata, u32 req_id)
+{
+ wait_event(bedata->inflight_req,
+ READ_ONCE(bedata->rsp[req_id].req_id) == req_id ||
+ READ_ONCE(bedata->disabled));
+
+ return READ_ONCE(bedata->disabled) ? -EIO : 0;
+}
+
static bool pvcalls_front_write_todo(struct sock_mapping *map)
{
struct pvcalls_data_intf *intf = map->active.ring;
@@ -168,7 +183,8 @@ static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id)
struct pvcalls_bedata *bedata;
struct xen_pvcalls_response *rsp;
uint8_t *src, *dst;
- int req_id = 0, more = 0, done = 0;
+ u32 req_id = 0;
+ int more = 0, done = 0;
if (dev == NULL)
return IRQ_HANDLED;
@@ -179,12 +195,31 @@ static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id)
pvcalls_exit();
return IRQ_HANDLED;
}
+ if (READ_ONCE(bedata->disabled)) {
+ pvcalls_exit();
+ return IRQ_HANDLED;
+ }
again:
while (RING_HAS_UNCONSUMED_RESPONSES(&bedata->ring)) {
rsp = RING_GET_RESPONSE(&bedata->ring, bedata->ring.rsp_cons);
req_id = rsp->req_id;
+ if (req_id >= PVCALLS_NR_RSP_PER_RING) {
+ /*
+ * The backend supplied a req_id that would index
+ * bedata->rsp[] out of bounds: a protocol violation
+ * from a malicious or buggy backend. Log once, stop
+ * trusting this backend and disable the frontend rather
+ * than silently dropping the response and continuing.
+ */
+ pr_err_once("pvcalls: backend sent out-of-range req_id %u, disabling frontend\n",
+ req_id);
+ WRITE_ONCE(bedata->disabled, true);
+ bedata->ring.rsp_cons++;
+ done = 1;
+ break;
+ }
if (rsp->cmd == PVCALLS_POLL) {
struct sock_mapping *map = (struct sock_mapping *)(uintptr_t)
rsp->u.poll.id;
@@ -217,7 +252,7 @@ again:
}
RING_FINAL_CHECK_FOR_RESPONSES(&bedata->ring, more);
- if (more)
+ if (more && !READ_ONCE(bedata->disabled))
goto again;
if (done)
wake_up(&bedata->inflight_req);
@@ -330,8 +365,11 @@ int pvcalls_front_socket(struct socket *sock)
if (notify)
notify_remote_via_irq(bedata->irq);
- wait_event(bedata->inflight_req,
- READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
+ ret = pvcalls_front_wait_rsp(bedata, req_id);
+ if (ret) {
+ pvcalls_exit();
+ return ret;
+ }
/* read req_id, then the content */
smp_rmb();
@@ -477,8 +515,11 @@ int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr,
if (notify)
notify_remote_via_irq(bedata->irq);
- wait_event(bedata->inflight_req,
- READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
+ ret = pvcalls_front_wait_rsp(bedata, req_id);
+ if (ret) {
+ pvcalls_exit_sock(sock);
+ return ret;
+ }
/* read req_id, then the content */
smp_rmb();
@@ -711,8 +752,11 @@ int pvcalls_front_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
if (notify)
notify_remote_via_irq(bedata->irq);
- wait_event(bedata->inflight_req,
- READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
+ ret = pvcalls_front_wait_rsp(bedata, req_id);
+ if (ret) {
+ pvcalls_exit_sock(sock);
+ return ret;
+ }
/* read req_id, then the content */
smp_rmb();
@@ -761,8 +805,11 @@ int pvcalls_front_listen(struct socket *sock, int backlog)
if (notify)
notify_remote_via_irq(bedata->irq);
- wait_event(bedata->inflight_req,
- READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
+ ret = pvcalls_front_wait_rsp(bedata, req_id);
+ if (ret) {
+ pvcalls_exit_sock(sock);
+ return ret;
+ }
/* read req_id, then the content */
smp_rmb();
@@ -820,6 +867,14 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock,
}
}
+ if (READ_ONCE(bedata->disabled)) {
+ clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
+ (void *)&map->passive.flags);
+ wake_up(&map->passive.inflight_accept_req);
+ pvcalls_exit_sock(sock);
+ return -EIO;
+ }
+
map2 = kzalloc_obj(*map2);
if (map2 == NULL) {
clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
@@ -880,10 +935,18 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock,
}
if (wait_event_interruptible(bedata->inflight_req,
- READ_ONCE(bedata->rsp[req_id].req_id) == req_id)) {
+ READ_ONCE(bedata->rsp[req_id].req_id) == req_id ||
+ READ_ONCE(bedata->disabled))) {
pvcalls_exit_sock(sock);
return -EINTR;
}
+ if (READ_ONCE(bedata->disabled)) {
+ clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
+ (void *)&map->passive.flags);
+ wake_up(&map->passive.inflight_accept_req);
+ pvcalls_exit_sock(sock);
+ return -EIO;
+ }
/* read req_id, then the content */
smp_rmb();
@@ -1054,7 +1117,8 @@ int pvcalls_front_release(struct socket *sock)
notify_remote_via_irq(bedata->irq);
wait_event(bedata->inflight_req,
- READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
+ READ_ONCE(bedata->rsp[req_id].req_id) == req_id ||
+ READ_ONCE(bedata->disabled));
if (map->active_socket) {
/*
diff --git a/drivers/xen/sys-hypervisor.c b/drivers/xen/sys-hypervisor.c
index b1bb01ba82f8..91923242a5ae 100644
--- a/drivers/xen/sys-hypervisor.c
+++ b/drivers/xen/sys-hypervisor.c
@@ -366,6 +366,8 @@ static ssize_t buildid_show(struct hyp_sysfs_attr *attr, char *buffer)
ret = sprintf(buffer, "<denied>");
return ret;
}
+ if (ret > PAGE_SIZE)
+ return -ENOSPC;
buildid = kmalloc(sizeof(*buildid) + ret, GFP_KERNEL);
if (!buildid)
@@ -373,8 +375,10 @@ static ssize_t buildid_show(struct hyp_sysfs_attr *attr, char *buffer)
buildid->len = ret;
ret = HYPERVISOR_xen_version(XENVER_build_id, buildid);
- if (ret > 0)
- ret = sprintf(buffer, "%s", buildid->buf);
+ if (ret > 0) {
+ /* Build id is binary, not a string. */
+ memcpy(buffer, buildid->buf, ret);
+ }
kfree(buildid);
return ret;
diff --git a/drivers/xen/xen-acpi-pad.c b/drivers/xen/xen-acpi-pad.c
index 75a39862c1df..5b98e0e93807 100644
--- a/drivers/xen/xen-acpi-pad.c
+++ b/drivers/xen/xen-acpi-pad.c
@@ -110,9 +110,13 @@ static void acpi_pad_notify(acpi_handle handle, u32 event,
static int acpi_pad_probe(struct platform_device *pdev)
{
- struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
+ struct acpi_device *device;
acpi_status status;
+ device = ACPI_COMPANION(&pdev->dev);
+ if (!device)
+ return -ENODEV;
+
strcpy(acpi_device_name(device), ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_PROCESSOR_AGGREGATOR_CLASS);
diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c
index b293d7652f15..67b0e2dbe84a 100644
--- a/drivers/xen/xen-balloon.c
+++ b/drivers/xen/xen-balloon.c
@@ -138,7 +138,7 @@ EXPORT_SYMBOL_GPL(xen_balloon_init);
struct device_attribute *attr, \
char *buf) \
{ \
- return sprintf(buf, format, ##args); \
+ return sysfs_emit(buf, format, ##args); \
} \
static DEVICE_ATTR_RO(name)
@@ -155,7 +155,7 @@ static DEVICE_BOOL_ATTR(scrub_pages, 0644, xen_scrub_pages);
static ssize_t target_kb_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- return sprintf(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages));
+ return sysfs_emit(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages));
}
static ssize_t target_kb_store(struct device *dev,
@@ -180,7 +180,7 @@ static DEVICE_ATTR_RW(target_kb);
static ssize_t target_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- return sprintf(buf, "%llu\n",
+ return sysfs_emit(buf, "%llu\n",
(unsigned long long)balloon_stats.target_pages
<< PAGE_SHIFT);
}
diff --git a/drivers/xen/xen-front-pgdir-shbuf.c b/drivers/xen/xen-front-pgdir-shbuf.c
index 9c7d8af6e6a1..428187edf85d 100644
--- a/drivers/xen/xen-front-pgdir-shbuf.c
+++ b/drivers/xen/xen-front-pgdir-shbuf.c
@@ -445,8 +445,10 @@ static int grant_references(struct xen_front_pgdir_shbuf *buf)
unsigned long frame;
cur_ref = gnttab_claim_grant_reference(&priv_gref_head);
- if (cur_ref < 0)
- return cur_ref;
+ if (cur_ref < 0) {
+ ret = cur_ref;
+ goto out_free_refs;
+ }
frame = xen_page_to_gfn(virt_to_page(buf->directory +
PAGE_SIZE * i));
@@ -457,11 +459,13 @@ static int grant_references(struct xen_front_pgdir_shbuf *buf)
if (buf->ops->grant_refs_for_buffer) {
ret = buf->ops->grant_refs_for_buffer(buf, &priv_gref_head, j);
if (ret)
- return ret;
+ goto out_free_refs;
}
+ ret = 0;
+out_free_refs:
gnttab_free_grant_references(priv_gref_head);
- return 0;
+ return ret;
}
/*
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index eb260eceb4d2..fafb2b84fa5c 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -514,7 +514,7 @@ int xenbus_probe_node(struct xen_bus_type *bus,
char devname[XEN_BUS_ID_SIZE];
int err;
struct xenbus_device *xendev;
- size_t stringlen;
+ size_t name_len, type_len;
char *tmpstring;
enum xenbus_state state = xenbus_read_driver_state(NULL, nodename);
@@ -525,8 +525,9 @@ int xenbus_probe_node(struct xen_bus_type *bus,
return 0;
}
- stringlen = strlen(nodename) + 1 + strlen(type) + 1;
- xendev = kzalloc(sizeof(*xendev) + stringlen, GFP_KERNEL);
+ name_len = strlen(nodename);
+ type_len = strlen(type);
+ xendev = kzalloc(sizeof(*xendev) + name_len + 1 + type_len + 1, GFP_KERNEL);
if (!xendev)
return -ENOMEM;
@@ -535,11 +536,11 @@ int xenbus_probe_node(struct xen_bus_type *bus,
/* Copy the strings into the extra space. */
tmpstring = (char *)(xendev + 1);
- strcpy(tmpstring, nodename);
+ memcpy(tmpstring, nodename, name_len);
xendev->nodename = tmpstring;
- tmpstring += strlen(tmpstring) + 1;
- strcpy(tmpstring, type);
+ tmpstring += name_len + 1;
+ memcpy(tmpstring, type, type_len);
xendev->devicetype = tmpstring;
init_completion(&xendev->down);
diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c
index 82b0a34ded70..d1cca4acb6f3 100644
--- a/drivers/xen/xenbus/xenbus_xs.c
+++ b/drivers/xen/xenbus/xenbus_xs.c
@@ -47,6 +47,9 @@
#include <linux/rwsem.h>
#include <linux/mutex.h>
#include <asm/xen/hypervisor.h>
+#ifdef CONFIG_X86
+#include <asm/cpuid/api.h>
+#endif
#include <xen/xenbus.h>
#include <xen/xen.h>
#include "xenbus.h"
@@ -414,6 +417,12 @@ static char **split_strings(char *strings, unsigned int len, unsigned int *num)
{
char *p, **ret;
+ if (len && strings[len - 1]) {
+ pr_err_once("malformed XS_DIRECTORY reply\n");
+ kfree(strings);
+ return ERR_PTR(-EIO);
+ }
+
/* Count the strings. */
*num = count_strings(strings, len);