mirror of
https://github.com/torvalds/linux.git
synced 2024-12-29 14:21:47 +00:00
nfc: pn533: Wait for out_urb's completion in pn533_usb_send_frame()
Fix a use-after-free that occurs in hcd when in_urb sent from
pn533_usb_send_frame() is completed earlier than out_urb. Its callback
frees the skb data in pn533_send_async_complete() that is used as a
transfer buffer of out_urb. Wait before sending in_urb until the
callback of out_urb is called. To modify the callback of out_urb alone,
separate the complete function of out_urb and ack_urb.
Found by a modified version of syzkaller.
BUG: KASAN: use-after-free in dummy_timer
Call Trace:
memcpy (mm/kasan/shadow.c:65)
dummy_perform_transfer (drivers/usb/gadget/udc/dummy_hcd.c:1352)
transfer (drivers/usb/gadget/udc/dummy_hcd.c:1453)
dummy_timer (drivers/usb/gadget/udc/dummy_hcd.c:1972)
arch_static_branch (arch/x86/include/asm/jump_label.h:27)
static_key_false (include/linux/jump_label.h:207)
timer_expire_exit (include/trace/events/timer.h:127)
call_timer_fn (kernel/time/timer.c:1475)
expire_timers (kernel/time/timer.c:1519)
__run_timers (kernel/time/timer.c:1790)
run_timer_softirq (kernel/time/timer.c:1803)
Fixes: c46ee38620
("NFC: pn533: add NXP pn533 nfc device driver")
Signed-off-by: Minsuk Kang <linuxlovemin@yonsei.ac.kr>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
2ab6478d12
commit
9dab880d67
@ -153,10 +153,17 @@ static int pn533_usb_send_ack(struct pn533 *dev, gfp_t flags)
|
|||||||
return usb_submit_urb(phy->ack_urb, flags);
|
return usb_submit_urb(phy->ack_urb, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct pn533_out_arg {
|
||||||
|
struct pn533_usb_phy *phy;
|
||||||
|
struct completion done;
|
||||||
|
};
|
||||||
|
|
||||||
static int pn533_usb_send_frame(struct pn533 *dev,
|
static int pn533_usb_send_frame(struct pn533 *dev,
|
||||||
struct sk_buff *out)
|
struct sk_buff *out)
|
||||||
{
|
{
|
||||||
struct pn533_usb_phy *phy = dev->phy;
|
struct pn533_usb_phy *phy = dev->phy;
|
||||||
|
struct pn533_out_arg arg;
|
||||||
|
void *cntx;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (phy->priv == NULL)
|
if (phy->priv == NULL)
|
||||||
@ -168,10 +175,17 @@ static int pn533_usb_send_frame(struct pn533 *dev,
|
|||||||
print_hex_dump_debug("PN533 TX: ", DUMP_PREFIX_NONE, 16, 1,
|
print_hex_dump_debug("PN533 TX: ", DUMP_PREFIX_NONE, 16, 1,
|
||||||
out->data, out->len, false);
|
out->data, out->len, false);
|
||||||
|
|
||||||
|
init_completion(&arg.done);
|
||||||
|
cntx = phy->out_urb->context;
|
||||||
|
phy->out_urb->context = &arg;
|
||||||
|
|
||||||
rc = usb_submit_urb(phy->out_urb, GFP_KERNEL);
|
rc = usb_submit_urb(phy->out_urb, GFP_KERNEL);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
wait_for_completion(&arg.done);
|
||||||
|
phy->out_urb->context = cntx;
|
||||||
|
|
||||||
if (dev->protocol_type == PN533_PROTO_REQ_RESP) {
|
if (dev->protocol_type == PN533_PROTO_REQ_RESP) {
|
||||||
/* request for response for sent packet directly */
|
/* request for response for sent packet directly */
|
||||||
rc = pn533_submit_urb_for_response(phy, GFP_KERNEL);
|
rc = pn533_submit_urb_for_response(phy, GFP_KERNEL);
|
||||||
@ -408,7 +422,31 @@ static int pn533_acr122_poweron_rdr(struct pn533_usb_phy *phy)
|
|||||||
return arg.rc;
|
return arg.rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pn533_send_complete(struct urb *urb)
|
static void pn533_out_complete(struct urb *urb)
|
||||||
|
{
|
||||||
|
struct pn533_out_arg *arg = urb->context;
|
||||||
|
struct pn533_usb_phy *phy = arg->phy;
|
||||||
|
|
||||||
|
switch (urb->status) {
|
||||||
|
case 0:
|
||||||
|
break; /* success */
|
||||||
|
case -ECONNRESET:
|
||||||
|
case -ENOENT:
|
||||||
|
dev_dbg(&phy->udev->dev,
|
||||||
|
"The urb has been stopped (status %d)\n",
|
||||||
|
urb->status);
|
||||||
|
break;
|
||||||
|
case -ESHUTDOWN:
|
||||||
|
default:
|
||||||
|
nfc_err(&phy->udev->dev,
|
||||||
|
"Urb failure (status %d)\n",
|
||||||
|
urb->status);
|
||||||
|
}
|
||||||
|
|
||||||
|
complete(&arg->done);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pn533_ack_complete(struct urb *urb)
|
||||||
{
|
{
|
||||||
struct pn533_usb_phy *phy = urb->context;
|
struct pn533_usb_phy *phy = urb->context;
|
||||||
|
|
||||||
@ -496,10 +534,10 @@ static int pn533_usb_probe(struct usb_interface *interface,
|
|||||||
|
|
||||||
usb_fill_bulk_urb(phy->out_urb, phy->udev,
|
usb_fill_bulk_urb(phy->out_urb, phy->udev,
|
||||||
usb_sndbulkpipe(phy->udev, out_endpoint),
|
usb_sndbulkpipe(phy->udev, out_endpoint),
|
||||||
NULL, 0, pn533_send_complete, phy);
|
NULL, 0, pn533_out_complete, phy);
|
||||||
usb_fill_bulk_urb(phy->ack_urb, phy->udev,
|
usb_fill_bulk_urb(phy->ack_urb, phy->udev,
|
||||||
usb_sndbulkpipe(phy->udev, out_endpoint),
|
usb_sndbulkpipe(phy->udev, out_endpoint),
|
||||||
NULL, 0, pn533_send_complete, phy);
|
NULL, 0, pn533_ack_complete, phy);
|
||||||
|
|
||||||
switch (id->driver_info) {
|
switch (id->driver_info) {
|
||||||
case PN533_DEVICE_STD:
|
case PN533_DEVICE_STD:
|
||||||
|
Loading…
Reference in New Issue
Block a user