Commit 4a037ad5 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus-5.12-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip

Pull xen updates from Juergen Gross:
 "A series of Xen related security fixes, all related to limited error
  handling in Xen backend drivers"

* tag 'for-linus-5.12-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip:
  xen-blkback: fix error handling in xen_blkbk_map()
  xen-scsiback: don't "handle" error by BUG()
  xen-netback: don't "handle" error by BUG()
  xen-blkback: don't "handle" error by BUG()
  xen/arm: don't ignore return errors from set_phys_to_machine
  Xen/gntdev: correct error checking in gntdev_map_grant_pages()
  Xen/gntdev: correct dev_bus_addr handling in gntdev_map_grant_pages()
  Xen/x86: also check kernel mapping in set_foreign_p2m_mapping()
  Xen/x86: don't bail early from clear_foreign_p2m_mapping()
parents d310ec03 871997bc
...@@ -95,8 +95,10 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops, ...@@ -95,8 +95,10 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops,
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
if (map_ops[i].status) if (map_ops[i].status)
continue; continue;
set_phys_to_machine(map_ops[i].host_addr >> XEN_PAGE_SHIFT, if (unlikely(!set_phys_to_machine(map_ops[i].host_addr >> XEN_PAGE_SHIFT,
map_ops[i].dev_bus_addr >> XEN_PAGE_SHIFT); map_ops[i].dev_bus_addr >> XEN_PAGE_SHIFT))) {
return -ENOMEM;
}
} }
return 0; return 0;
......
...@@ -712,7 +712,8 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops, ...@@ -712,7 +712,8 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops,
unsigned long mfn, pfn; unsigned long mfn, pfn;
/* Do not add to override if the map failed. */ /* Do not add to override if the map failed. */
if (map_ops[i].status) if (map_ops[i].status != GNTST_okay ||
(kmap_ops && kmap_ops[i].status != GNTST_okay))
continue; continue;
if (map_ops[i].flags & GNTMAP_contains_pte) { if (map_ops[i].flags & GNTMAP_contains_pte) {
...@@ -750,17 +751,15 @@ int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops, ...@@ -750,17 +751,15 @@ int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops,
unsigned long mfn = __pfn_to_mfn(page_to_pfn(pages[i])); unsigned long mfn = __pfn_to_mfn(page_to_pfn(pages[i]));
unsigned long pfn = page_to_pfn(pages[i]); unsigned long pfn = page_to_pfn(pages[i]);
if (mfn == INVALID_P2M_ENTRY || !(mfn & FOREIGN_FRAME_BIT)) { if (mfn != INVALID_P2M_ENTRY && (mfn & FOREIGN_FRAME_BIT))
set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
else
ret = -EINVAL; ret = -EINVAL;
goto out;
}
set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
} }
if (kunmap_ops) if (kunmap_ops)
ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
kunmap_ops, count); kunmap_ops, count) ?: ret;
out:
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(clear_foreign_p2m_mapping); EXPORT_SYMBOL_GPL(clear_foreign_p2m_mapping);
......
...@@ -794,8 +794,13 @@ static int xen_blkbk_map(struct xen_blkif_ring *ring, ...@@ -794,8 +794,13 @@ static int xen_blkbk_map(struct xen_blkif_ring *ring,
pages[i]->persistent_gnt = persistent_gnt; pages[i]->persistent_gnt = persistent_gnt;
} else { } else {
if (gnttab_page_cache_get(&ring->free_pages, if (gnttab_page_cache_get(&ring->free_pages,
&pages[i]->page)) &pages[i]->page)) {
goto out_of_memory; gnttab_page_cache_put(&ring->free_pages,
pages_to_gnt,
segs_to_map);
ret = -ENOMEM;
goto out;
}
addr = vaddr(pages[i]->page); addr = vaddr(pages[i]->page);
pages_to_gnt[segs_to_map] = pages[i]->page; pages_to_gnt[segs_to_map] = pages[i]->page;
pages[i]->persistent_gnt = NULL; pages[i]->persistent_gnt = NULL;
...@@ -811,10 +816,8 @@ static int xen_blkbk_map(struct xen_blkif_ring *ring, ...@@ -811,10 +816,8 @@ static int xen_blkbk_map(struct xen_blkif_ring *ring,
break; break;
} }
if (segs_to_map) { if (segs_to_map)
ret = gnttab_map_refs(map, NULL, pages_to_gnt, segs_to_map); ret = gnttab_map_refs(map, NULL, pages_to_gnt, segs_to_map);
BUG_ON(ret);
}
/* /*
* Now swizzle the MFN in our domain with the MFN from the other domain * Now swizzle the MFN in our domain with the MFN from the other domain
...@@ -830,7 +833,7 @@ static int xen_blkbk_map(struct xen_blkif_ring *ring, ...@@ -830,7 +833,7 @@ static int xen_blkbk_map(struct xen_blkif_ring *ring,
gnttab_page_cache_put(&ring->free_pages, gnttab_page_cache_put(&ring->free_pages,
&pages[seg_idx]->page, 1); &pages[seg_idx]->page, 1);
pages[seg_idx]->handle = BLKBACK_INVALID_HANDLE; pages[seg_idx]->handle = BLKBACK_INVALID_HANDLE;
ret |= 1; ret |= !ret;
goto next; goto next;
} }
pages[seg_idx]->handle = map[new_map_idx].handle; pages[seg_idx]->handle = map[new_map_idx].handle;
...@@ -882,17 +885,18 @@ static int xen_blkbk_map(struct xen_blkif_ring *ring, ...@@ -882,17 +885,18 @@ static int xen_blkbk_map(struct xen_blkif_ring *ring,
} }
segs_to_map = 0; segs_to_map = 0;
last_map = map_until; last_map = map_until;
if (map_until != num) if (!ret && map_until != num)
goto again; goto again;
return ret; out:
for (i = last_map; i < num; i++) {
out_of_memory: /* Don't zap current batch's valid persistent grants. */
pr_alert("%s: out of memory\n", __func__); if(i >= last_map + segs_to_map)
gnttab_page_cache_put(&ring->free_pages, pages_to_gnt, segs_to_map); pages[i]->persistent_gnt = NULL;
for (i = last_map; i < num; i++)
pages[i]->handle = BLKBACK_INVALID_HANDLE; pages[i]->handle = BLKBACK_INVALID_HANDLE;
return -ENOMEM; }
return ret;
} }
static int xen_blkbk_map_seg(struct pending_req *pending_req) static int xen_blkbk_map_seg(struct pending_req *pending_req)
......
...@@ -1343,13 +1343,11 @@ int xenvif_tx_action(struct xenvif_queue *queue, int budget) ...@@ -1343,13 +1343,11 @@ int xenvif_tx_action(struct xenvif_queue *queue, int budget)
return 0; return 0;
gnttab_batch_copy(queue->tx_copy_ops, nr_cops); gnttab_batch_copy(queue->tx_copy_ops, nr_cops);
if (nr_mops != 0) { if (nr_mops != 0)
ret = gnttab_map_refs(queue->tx_map_ops, ret = gnttab_map_refs(queue->tx_map_ops,
NULL, NULL,
queue->pages_to_map, queue->pages_to_map,
nr_mops); nr_mops);
BUG_ON(ret);
}
work_done = xenvif_tx_submit(queue); work_done = xenvif_tx_submit(queue);
......
...@@ -309,44 +309,47 @@ int gntdev_map_grant_pages(struct gntdev_grant_map *map) ...@@ -309,44 +309,47 @@ int gntdev_map_grant_pages(struct gntdev_grant_map *map)
* to the kernel linear addresses of the struct pages. * to the kernel linear addresses of the struct pages.
* These ptes are completely different from the user ptes dealt * These ptes are completely different from the user ptes dealt
* with find_grant_ptes. * with find_grant_ptes.
* Note that GNTMAP_device_map isn't needed here: The
* dev_bus_addr output field gets consumed only from ->map_ops,
* and by not requesting it when mapping we also avoid needing
* to mirror dev_bus_addr into ->unmap_ops (and holding an extra
* reference to the page in the hypervisor).
*/ */
unsigned int flags = (map->flags & ~GNTMAP_device_map) |
GNTMAP_host_map;
for (i = 0; i < map->count; i++) { for (i = 0; i < map->count; i++) {
unsigned long address = (unsigned long) unsigned long address = (unsigned long)
pfn_to_kaddr(page_to_pfn(map->pages[i])); pfn_to_kaddr(page_to_pfn(map->pages[i]));
BUG_ON(PageHighMem(map->pages[i])); BUG_ON(PageHighMem(map->pages[i]));
gnttab_set_map_op(&map->kmap_ops[i], address, gnttab_set_map_op(&map->kmap_ops[i], address, flags,
map->flags | GNTMAP_host_map,
map->grants[i].ref, map->grants[i].ref,
map->grants[i].domid); map->grants[i].domid);
gnttab_set_unmap_op(&map->kunmap_ops[i], address, gnttab_set_unmap_op(&map->kunmap_ops[i], address,
map->flags | GNTMAP_host_map, -1); flags, -1);
} }
} }
pr_debug("map %d+%d\n", map->index, map->count); pr_debug("map %d+%d\n", map->index, map->count);
err = gnttab_map_refs(map->map_ops, use_ptemod ? map->kmap_ops : NULL, err = gnttab_map_refs(map->map_ops, use_ptemod ? map->kmap_ops : NULL,
map->pages, map->count); map->pages, map->count);
if (err)
return err;
for (i = 0; i < map->count; i++) { for (i = 0; i < map->count; i++) {
if (map->map_ops[i].status) { if (map->map_ops[i].status == GNTST_okay)
map->unmap_ops[i].handle = map->map_ops[i].handle;
else if (!err)
err = -EINVAL; err = -EINVAL;
continue;
}
map->unmap_ops[i].handle = map->map_ops[i].handle; if (map->flags & GNTMAP_device_map)
if (use_ptemod) map->unmap_ops[i].dev_bus_addr = map->map_ops[i].dev_bus_addr;
map->kunmap_ops[i].handle = map->kmap_ops[i].handle;
#ifdef CONFIG_XEN_GRANT_DMA_ALLOC
else if (map->dma_vaddr) {
unsigned long bfn;
bfn = pfn_to_bfn(page_to_pfn(map->pages[i])); if (use_ptemod) {
map->unmap_ops[i].dev_bus_addr = __pfn_to_phys(bfn); if (map->kmap_ops[i].status == GNTST_okay)
map->kunmap_ops[i].handle = map->kmap_ops[i].handle;
else if (!err)
err = -EINVAL;
} }
#endif
} }
return err; return err;
} }
......
...@@ -386,12 +386,12 @@ static int scsiback_gnttab_data_map_batch(struct gnttab_map_grant_ref *map, ...@@ -386,12 +386,12 @@ static int scsiback_gnttab_data_map_batch(struct gnttab_map_grant_ref *map,
return 0; return 0;
err = gnttab_map_refs(map, NULL, pg, cnt); err = gnttab_map_refs(map, NULL, pg, cnt);
BUG_ON(err);
for (i = 0; i < cnt; i++) { for (i = 0; i < cnt; i++) {
if (unlikely(map[i].status != GNTST_okay)) { if (unlikely(map[i].status != GNTST_okay)) {
pr_err("invalid buffer -- could not remap it\n"); pr_err("invalid buffer -- could not remap it\n");
map[i].handle = SCSIBACK_INVALID_HANDLE; map[i].handle = SCSIBACK_INVALID_HANDLE;
err = -ENOMEM; if (!err)
err = -ENOMEM;
} else { } else {
get_page(pg[i]); get_page(pg[i]);
} }
......
...@@ -157,6 +157,7 @@ gnttab_set_map_op(struct gnttab_map_grant_ref *map, phys_addr_t addr, ...@@ -157,6 +157,7 @@ gnttab_set_map_op(struct gnttab_map_grant_ref *map, phys_addr_t addr,
map->flags = flags; map->flags = flags;
map->ref = ref; map->ref = ref;
map->dom = domid; map->dom = domid;
map->status = 1; /* arbitrary positive value */
} }
static inline void static inline void
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment