Skip to content

Commit cd7bcfa

Browse files
committed
xen/usb: don't use gnttab_end_foreign_access() in xenhcd_gnttab_done()
The usage of gnttab_end_foreign_access() in xenhcd_gnttab_done() is not safe against a malicious backend, as the backend could keep the I/O page mapped and modify it even after the granted memory page is being used for completely other purposes in the local system. So replace that use case with gnttab_try_end_foreign_access() and disable the PV host adapter in case the backend didn't stop using the granted page. In xenhcd_urb_request_done() immediately return in case of setting the device state to "error" instead of looking into further backend responses. Reported-by: Demi Marie Obenour <[email protected]> Signed-off-by: Juergen Gross <[email protected]> Reviewed-by: Jan Beulich <[email protected]> --- V2: - use gnttab_try_end_foreign_access()
1 parent 1dbd11c commit cd7bcfa

File tree

1 file changed

+18
-8
lines changed

1 file changed

+18
-8
lines changed

drivers/usb/host/xen-hcd.c

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -716,8 +716,9 @@ static int xenhcd_map_urb_for_request(struct xenhcd_info *info, struct urb *urb,
716716
return 0;
717717
}
718718

719-
static void xenhcd_gnttab_done(struct usb_shadow *shadow)
719+
static void xenhcd_gnttab_done(struct xenhcd_info *info, unsigned int id)
720720
{
721+
struct usb_shadow *shadow = info->shadow + id;
721722
int nr_segs = 0;
722723
int i;
723724

@@ -726,8 +727,10 @@ static void xenhcd_gnttab_done(struct usb_shadow *shadow)
726727
if (xenusb_pipeisoc(shadow->req.pipe))
727728
nr_segs += shadow->req.u.isoc.nr_frame_desc_segs;
728729

729-
for (i = 0; i < nr_segs; i++)
730-
gnttab_end_foreign_access(shadow->req.seg[i].gref, 0, 0UL);
730+
for (i = 0; i < nr_segs; i++) {
731+
if (!gnttab_try_end_foreign_access(shadow->req.seg[i].gref))
732+
xenhcd_set_error(info, "backend didn't release grant");
733+
}
731734

732735
shadow->req.nr_buffer_segs = 0;
733736
shadow->req.u.isoc.nr_frame_desc_segs = 0;
@@ -841,7 +844,9 @@ static void xenhcd_cancel_all_enqueued_urbs(struct xenhcd_info *info)
841844
list_for_each_entry_safe(urbp, tmp, &info->in_progress_list, list) {
842845
req_id = urbp->req_id;
843846
if (!urbp->unlinked) {
844-
xenhcd_gnttab_done(&info->shadow[req_id]);
847+
xenhcd_gnttab_done(info, req_id);
848+
if (info->error)
849+
return;
845850
if (urbp->urb->status == -EINPROGRESS)
846851
/* not dequeued */
847852
xenhcd_giveback_urb(info, urbp->urb,
@@ -942,8 +947,7 @@ static int xenhcd_urb_request_done(struct xenhcd_info *info)
942947
rp = info->urb_ring.sring->rsp_prod;
943948
if (RING_RESPONSE_PROD_OVERFLOW(&info->urb_ring, rp)) {
944949
xenhcd_set_error(info, "Illegal index on urb-ring");
945-
spin_unlock_irqrestore(&info->lock, flags);
946-
return 0;
950+
goto err;
947951
}
948952
rmb(); /* ensure we see queued responses up to "rp" */
949953

@@ -952,11 +956,13 @@ static int xenhcd_urb_request_done(struct xenhcd_info *info)
952956
id = res.id;
953957
if (id >= XENUSB_URB_RING_SIZE) {
954958
xenhcd_set_error(info, "Illegal data on urb-ring");
955-
continue;
959+
goto err;
956960
}
957961

958962
if (likely(xenusb_pipesubmit(info->shadow[id].req.pipe))) {
959-
xenhcd_gnttab_done(&info->shadow[id]);
963+
xenhcd_gnttab_done(info, id);
964+
if (info->error)
965+
goto err;
960966
urb = info->shadow[id].urb;
961967
if (likely(urb)) {
962968
urb->actual_length = res.actual_length;
@@ -978,6 +984,10 @@ static int xenhcd_urb_request_done(struct xenhcd_info *info)
978984
spin_unlock_irqrestore(&info->lock, flags);
979985

980986
return more_to_do;
987+
988+
err:
989+
spin_unlock_irqrestore(&info->lock, flags);
990+
return 0;
981991
}
982992

983993
static int xenhcd_conn_notify(struct xenhcd_info *info)

0 commit comments

Comments
 (0)