diff mbox

[v3] NFC: pn533: don't send USB data off of the stack

Message ID 20180518103811.GA29186@kroah.com (mailing list archive)
State Superseded
Delegated to: Samuel Ortiz
Headers show

Commit Message

Greg Kroah-Hartman May 18, 2018, 10:38 a.m. UTC
It's amazing that this driver ever worked, but now that x86 doesn't
allow USB data to be sent off of the stack, it really does not work at
all.  Fix this up by properly allocating the data for the small
"commands" that get sent to the device.

The USB stack will free the buffer when the data has been transmitted,
that is why there is no kfree() to mirror the call to kmalloc().

Reported-by: Carlos Manuel Santos <cmmpsantos@gmail.com>
Cc: Samuel Ortiz <sameo@linux.intel.com>
Cc: Stephen Hemminger <stephen@networkplumber.org>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
v3: actually use the correct buffer (thanks to Arend van Spriel)
    use kmemdup (thanks to Johannes Berg and Julia Lawall)
v2: set the urb flags correctly

 drivers/nfc/pn533/usb.c |   17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

Comments

Johan Hovold May 18, 2018, 3:48 p.m. UTC | #1
On Fri, May 18, 2018 at 12:38:11PM +0200, Greg Kroah-Hartman wrote:
> It's amazing that this driver ever worked, but now that x86 doesn't
> allow USB data to be sent off of the stack, it really does not work at
> all.  Fix this up by properly allocating the data for the small
> "commands" that get sent to the device.
> 
> The USB stack will free the buffer when the data has been transmitted,
> that is why there is no kfree() to mirror the call to kmalloc().

It looks like you're now leaking all but the final transfer buffer that
is allocated for outgoing commands, as the URBs themselves are not freed
until disconnect() (and that's when core would free the buffers along
with the URBs if URB_FREE_BUFFER is set).

Johan
Greg Kroah-Hartman May 19, 2018, 7:08 a.m. UTC | #2
On Fri, May 18, 2018 at 05:48:47PM +0200, Johan Hovold wrote:
> On Fri, May 18, 2018 at 12:38:11PM +0200, Greg Kroah-Hartman wrote:
> > It's amazing that this driver ever worked, but now that x86 doesn't
> > allow USB data to be sent off of the stack, it really does not work at
> > all.  Fix this up by properly allocating the data for the small
> > "commands" that get sent to the device.
> > 
> > The USB stack will free the buffer when the data has been transmitted,
> > that is why there is no kfree() to mirror the call to kmalloc().
> 
> It looks like you're now leaking all but the final transfer buffer that
> is allocated for outgoing commands, as the URBs themselves are not freed
> until disconnect() (and that's when core would free the buffers along
> with the URBs if URB_FREE_BUFFER is set).

Ugh, you are right.  The urb handling in this driver is crazy...

Let me go redo this whole thing, give me a few days...

thanks for the review, much appreciated.

Carlos, it would be good to know if your testing showed that the patch
at least enables the device to work for now.  It will leak memory like
crazy, so I don't recomment relying on the driver, but it should be good
enough to see if my thinking as to why the driver was not working is
correct or not.

greg k-h
diff mbox

Patch

--- a/drivers/nfc/pn533/usb.c
+++ b/drivers/nfc/pn533/usb.c
@@ -150,10 +150,16 @@  static int pn533_usb_send_ack(struct pn5
 	struct pn533_usb_phy *phy = dev->phy;
 	static const u8 ack[6] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00};
 	/* spec 7.1.1.3:  Preamble, SoPC (2), ACK Code (2), Postamble */
+	char *buffer;
 	int rc;
 
-	phy->out_urb->transfer_buffer = (u8 *)ack;
+	buffer = kmemdup(ack, sizeof(ack), GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	phy->out_urb->transfer_buffer = buffer;
 	phy->out_urb->transfer_buffer_length = sizeof(ack);
+	phy->out_urb->transfer_flags |= URB_FREE_BUFFER;
 	rc = usb_submit_urb(phy->out_urb, flags);
 
 	return rc;
@@ -170,6 +176,7 @@  static int pn533_usb_send_frame(struct p
 
 	phy->out_urb->transfer_buffer = out->data;
 	phy->out_urb->transfer_buffer_length = out->len;
+	phy->out_urb->transfer_flags &= ~URB_FREE_BUFFER;
 
 	print_hex_dump_debug("PN533 TX: ", DUMP_PREFIX_NONE, 16, 1,
 			     out->data, out->len, false);
@@ -375,20 +382,26 @@  static int pn533_acr122_poweron_rdr(stru
 	/* Power on th reader (CCID cmd) */
 	u8 cmd[10] = {PN533_ACR122_PC_TO_RDR_ICCPOWERON,
 		      0, 0, 0, 0, 0, 0, 3, 0, 0};
+	char *buffer;
 	int rc;
 	void *cntx;
 	struct pn533_acr122_poweron_rdr_arg arg;
 
 	dev_dbg(&phy->udev->dev, "%s\n", __func__);
 
+	buffer = kmemdup(cmd, sizeof(cmd), GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
 	init_completion(&arg.done);
 	cntx = phy->in_urb->context;  /* backup context */
 
 	phy->in_urb->complete = pn533_acr122_poweron_rdr_resp;
 	phy->in_urb->context = &arg;
 
-	phy->out_urb->transfer_buffer = cmd;
+	phy->out_urb->transfer_buffer = buffer;
 	phy->out_urb->transfer_buffer_length = sizeof(cmd);
+	phy->out_urb->transfer_flags |= URB_FREE_BUFFER;
 
 	print_hex_dump_debug("ACR122 TX: ", DUMP_PREFIX_NONE, 16, 1,
 		       cmd, sizeof(cmd), false);