diff options
Diffstat (limited to 'drivers/xen')
| -rw-r--r-- | drivers/xen/events/events_base.c | 1 | ||||
| -rw-r--r-- | drivers/xen/gntalloc.c | 19 | ||||
| -rw-r--r-- | drivers/xen/gntdev.c | 8 | ||||
| -rw-r--r-- | drivers/xen/grant-dma-ops.c | 5 | ||||
| -rw-r--r-- | drivers/xen/grant-table.c | 1 | ||||
| -rw-r--r-- | drivers/xen/mcelog.c | 6 | ||||
| -rw-r--r-- | drivers/xen/platform-pci.c | 8 | ||||
| -rw-r--r-- | drivers/xen/privcmd.c | 7 | ||||
| -rw-r--r-- | drivers/xen/pvcalls-front.c | 88 | ||||
| -rw-r--r-- | drivers/xen/sys-hypervisor.c | 8 | ||||
| -rw-r--r-- | drivers/xen/xen-acpi-pad.c | 6 | ||||
| -rw-r--r-- | drivers/xen/xen-balloon.c | 6 | ||||
| -rw-r--r-- | drivers/xen/xen-front-pgdir-shbuf.c | 12 | ||||
| -rw-r--r-- | drivers/xen/xenbus/xenbus_probe.c | 13 | ||||
| -rw-r--r-- | drivers/xen/xenbus/xenbus_xs.c | 9 |
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); |
