Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xen/usb: harden xen_hcd against malicious backends

Make sure a malicious backend can't cause any harm other than wrong
I/O data.

Missing are verification of the request id in a response, sanitizing
the reported actual I/O length, and protection against interrupt storms
from the backend.

Signed-off-by: Juergen Gross <jgross@suse.com>
Link: https://lore.kernel.org/r/20220311103509.12908-1-jgross@suse.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Juergen Gross and committed by
Greg Kroah-Hartman
aff477cb 7f220d4a

+43 -14
+43 -14
drivers/usb/host/xen-hcd.c
··· 51 51 struct usb_shadow { 52 52 struct xenusb_urb_request req; 53 53 struct urb *urb; 54 + bool in_flight; 54 55 }; 55 56 56 57 struct xenhcd_info { ··· 721 720 int nr_segs = 0; 722 721 int i; 723 722 723 + if (!shadow->in_flight) { 724 + xenhcd_set_error(info, "Illegal request id"); 725 + return; 726 + } 727 + shadow->in_flight = false; 728 + 724 729 nr_segs = shadow->req.nr_buffer_segs; 725 730 726 731 if (xenusb_pipeisoc(shadow->req.pipe)) ··· 810 803 811 804 info->urb_ring.req_prod_pvt++; 812 805 info->shadow[id].urb = urb; 806 + info->shadow[id].in_flight = true; 813 807 814 808 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->urb_ring, notify); 815 809 if (notify) ··· 939 931 return ret; 940 932 } 941 933 942 - static int xenhcd_urb_request_done(struct xenhcd_info *info) 934 + static void xenhcd_res_to_urb(struct xenhcd_info *info, 935 + struct xenusb_urb_response *res, struct urb *urb) 936 + { 937 + if (unlikely(!urb)) 938 + return; 939 + 940 + if (res->actual_length > urb->transfer_buffer_length) 941 + urb->actual_length = urb->transfer_buffer_length; 942 + else if (res->actual_length < 0) 943 + urb->actual_length = 0; 944 + else 945 + urb->actual_length = res->actual_length; 946 + urb->error_count = res->error_count; 947 + urb->start_frame = res->start_frame; 948 + xenhcd_giveback_urb(info, urb, res->status); 949 + } 950 + 951 + static int xenhcd_urb_request_done(struct xenhcd_info *info, 952 + unsigned int *eoiflag) 943 953 { 944 954 struct xenusb_urb_response res; 945 - struct urb *urb; 946 955 RING_IDX i, rp; 947 956 __u16 id; 948 957 int more_to_do = 0; ··· 986 961 xenhcd_gnttab_done(info, id); 987 962 if (info->error) 988 963 goto err; 989 - urb = info->shadow[id].urb; 990 - if (likely(urb)) { 991 - urb->actual_length = res.actual_length; 992 - urb->error_count = res.error_count; 993 - urb->start_frame = res.start_frame; 994 - xenhcd_giveback_urb(info, urb, res.status); 995 - } 964 + xenhcd_res_to_urb(info, &res, info->shadow[id].urb); 996 965 } 997 966 998 967 xenhcd_add_id_to_freelist(info, id); 968 + 969 + *eoiflag = 0; 999 970 } 1000 971 info->urb_ring.rsp_cons = i; 1001 972 ··· 1009 988 return 0; 1010 989 } 1011 990 1012 - static int xenhcd_conn_notify(struct xenhcd_info *info) 991 + static int xenhcd_conn_notify(struct xenhcd_info *info, unsigned int *eoiflag) 1013 992 { 1014 993 struct xenusb_conn_response res; 1015 994 struct xenusb_conn_request *req; ··· 1054 1033 info->conn_ring.req_prod_pvt); 1055 1034 req->id = id; 1056 1035 info->conn_ring.req_prod_pvt++; 1036 + 1037 + *eoiflag = 0; 1057 1038 } 1058 1039 1059 1040 if (rc != info->conn_ring.req_prod_pvt) ··· 1078 1055 static irqreturn_t xenhcd_int(int irq, void *dev_id) 1079 1056 { 1080 1057 struct xenhcd_info *info = (struct xenhcd_info *)dev_id; 1058 + unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS; 1081 1059 1082 - if (unlikely(info->error)) 1060 + if (unlikely(info->error)) { 1061 + xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS); 1083 1062 return IRQ_HANDLED; 1063 + } 1084 1064 1085 - while (xenhcd_urb_request_done(info) | xenhcd_conn_notify(info)) 1065 + while (xenhcd_urb_request_done(info, &eoiflag) | 1066 + xenhcd_conn_notify(info, &eoiflag)) 1086 1067 /* Yield point for this unbounded loop. */ 1087 1068 cond_resched(); 1088 1069 1070 + xen_irq_lateeoi(irq, eoiflag); 1089 1071 return IRQ_HANDLED; 1090 1072 } 1091 1073 ··· 1167 1139 goto fail; 1168 1140 } 1169 1141 1170 - err = bind_evtchn_to_irq(info->evtchn); 1142 + err = bind_evtchn_to_irq_lateeoi(info->evtchn); 1171 1143 if (err <= 0) { 1172 - xenbus_dev_fatal(dev, err, "bind_evtchn_to_irq"); 1144 + xenbus_dev_fatal(dev, err, "bind_evtchn_to_irq_lateeoi"); 1173 1145 goto fail; 1174 1146 } 1175 1147 ··· 1522 1494 for (i = 0; i < XENUSB_URB_RING_SIZE; i++) { 1523 1495 info->shadow[i].req.id = i + 1; 1524 1496 info->shadow[i].urb = NULL; 1497 + info->shadow[i].in_flight = false; 1525 1498 } 1526 1499 info->shadow[XENUSB_URB_RING_SIZE - 1].req.id = 0x0fff; 1527 1500