diff mbox series

[2/4] wan/hdlc_x25: fix skb handling

Message ID 20190403050118.12785-2-ms@dev.tdt.de
State Changes Requested
Delegated to: David Miller
Headers show
Series [1/4] net/x25: call skb_reset_network_header where needed | expand

Commit Message

Martin Schiller April 3, 2019, 5:01 a.m. UTC
o call skb_reset_network_header() before hdlc->xmit()
 o change skb proto to HDLC (0x0019) before hdlc->xmit()
 o call dev_queue_xmit_nit() before hdlc->xmit()

This changes make it possible to trace (tcpdump) outgoing layer2
(ETH_P_HDLC) packets

 o use a copy of the skb for lapb_data_request()

This fixes the problem, that tracing layer3 (ETH_P_X25) packets
results in a malformed first byte of the packets.

Signed-off-by: Martin Schiller <ms@dev.tdt.de>
---
 drivers/net/wan/hdlc_x25.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

Comments

David Miller April 5, 2019, 12:32 a.m. UTC | #1
From: Martin Schiller <ms@dev.tdt.de>
Date: Wed,  3 Apr 2019 07:01:16 +0200

>  	/* X.25 to LAPB */
>  	switch (skb->data[0]) {
>  	case X25_IFACE_DATA:	/* Data to be transmitted */
> -		skb_pull(skb, 1);
> -		if ((result = lapb_data_request(dev, skb)) != LAPB_OK)
> -			dev_kfree_skb(skb);
> -		return NETDEV_TX_OK;
> +		skbn = skb_copy(skb, GFP_ATOMIC);
> +		skb_pull(skbn, 1);
> +		skb_reset_network_header(skbn);
> +		if ((result = lapb_data_request(dev, skbn)) != LAPB_OK)
> +			dev_kfree_skb(skbn);

This leaks 'skb'.

No way I'm applying this stuff.
Martin Schiller April 5, 2019, 6:56 a.m. UTC | #2
On 2019-04-05 02:32, David Miller wrote:
> From: Martin Schiller <ms@dev.tdt.de>
> Date: Wed,  3 Apr 2019 07:01:16 +0200
> 
>>  	/* X.25 to LAPB */
>>  	switch (skb->data[0]) {
>>  	case X25_IFACE_DATA:	/* Data to be transmitted */
>> -		skb_pull(skb, 1);
>> -		if ((result = lapb_data_request(dev, skb)) != LAPB_OK)
>> -			dev_kfree_skb(skb);
>> -		return NETDEV_TX_OK;
>> +		skbn = skb_copy(skb, GFP_ATOMIC);
>> +		skb_pull(skbn, 1);
>> +		skb_reset_network_header(skbn);
>> +		if ((result = lapb_data_request(dev, skbn)) != LAPB_OK)
>> +			dev_kfree_skb(skbn);
> 
> This leaks 'skb'.

What exactly do you mean?
'skb' will get freed at the end of x25_xmit() function:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/wan/hdlc_x25.c#n129

> 
> No way I'm applying this stuff.
David Miller April 5, 2019, 7:15 p.m. UTC | #3
From: Martin Schiller <ms@dev.tdt.de>
Date: Fri, 05 Apr 2019 08:56:44 +0200

> On 2019-04-05 02:32, David Miller wrote:
>> From: Martin Schiller <ms@dev.tdt.de>
>> Date: Wed,  3 Apr 2019 07:01:16 +0200
>> 
>>>  	/* X.25 to LAPB */
>>>  	switch (skb->data[0]) {
>>>  	case X25_IFACE_DATA:	/* Data to be transmitted */
>>> -		skb_pull(skb, 1);
>>> -		if ((result = lapb_data_request(dev, skb)) != LAPB_OK)
>>> -			dev_kfree_skb(skb);
>>> -		return NETDEV_TX_OK;
>>> +		skbn = skb_copy(skb, GFP_ATOMIC);
>>> +		skb_pull(skbn, 1);
>>> +		skb_reset_network_header(skbn);
>>> +		if ((result = lapb_data_request(dev, skbn)) != LAPB_OK)
>>> +			dev_kfree_skb(skbn);
>> This leaks 'skb'.
> 
> What exactly do you mean?
> 'skb' will get freed at the end of x25_xmit() function:
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/wan/hdlc_x25.c#n129

Then why was it freed here in the original code?
Martin Schiller April 8, 2019, 6:07 a.m. UTC | #4
On 2019-04-05 21:15, David Miller wrote:
> From: Martin Schiller <ms@dev.tdt.de>
> Date: Fri, 05 Apr 2019 08:56:44 +0200
> 
>> On 2019-04-05 02:32, David Miller wrote:
>>> From: Martin Schiller <ms@dev.tdt.de>
>>> Date: Wed,  3 Apr 2019 07:01:16 +0200
>>> 
>>>>  	/* X.25 to LAPB */
>>>>  	switch (skb->data[0]) {
>>>>  	case X25_IFACE_DATA:	/* Data to be transmitted */
>>>> -		skb_pull(skb, 1);
>>>> -		if ((result = lapb_data_request(dev, skb)) != LAPB_OK)
>>>> -			dev_kfree_skb(skb);
>>>> -		return NETDEV_TX_OK;
>>>> +		skbn = skb_copy(skb, GFP_ATOMIC);
>>>> +		skb_pull(skbn, 1);
>>>> +		skb_reset_network_header(skbn);
>>>> +		if ((result = lapb_data_request(dev, skbn)) != LAPB_OK)
>>>> +			dev_kfree_skb(skbn);
>>> This leaks 'skb'.
>> 
>> What exactly do you mean?
>> 'skb' will get freed at the end of x25_xmit() function:
>> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/wan/hdlc_x25.c#n129
> 
> Then why was it freed here in the original code?

In the original code, 'skb' is only freed here if lapb_data_request()
return a value != LAPB_OK, which is the case when the skb can't be
queued for transmission. Otherwise 'skb' won't be freed here in the
"X25_IFACE_DATA" case.

What my change do is, that 'skb' is copied to 'skbn' before the skb_pull
of the first byte, to fix the problem that tracing layer3 (ETH_P_X25)
packets results in a malformed first byte of the packets, because the
original "skb" will get modified before the frame reaches the tcpdump
output.

Everything else works like before.
diff mbox series

Patch

diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c
index e867638067a6..fb5ed6856be5 100644
--- a/drivers/net/wan/hdlc_x25.c
+++ b/drivers/net/wan/hdlc_x25.c
@@ -66,6 +66,7 @@  static int x25_data_indication(struct net_device *dev, struct sk_buff *skb)
 	unsigned char *ptr;
 
 	skb_push(skb, 1);
+	skb_reset_network_header(skb);
 
 	if (skb_cow(skb, 1))
 		return NET_RX_DROP;
@@ -82,6 +83,9 @@  static int x25_data_indication(struct net_device *dev, struct sk_buff *skb)
 static void x25_data_transmit(struct net_device *dev, struct sk_buff *skb)
 {
 	hdlc_device *hdlc = dev_to_hdlc(dev);
+	skb_reset_network_header(skb);
+	skb->protocol = hdlc_type_trans(skb, dev);
+	dev_queue_xmit_nit(skb, dev);
 	hdlc->xmit(skb, dev); /* Ignore return value :-( */
 }
 
@@ -89,16 +93,19 @@  static void x25_data_transmit(struct net_device *dev, struct sk_buff *skb)
 
 static netdev_tx_t x25_xmit(struct sk_buff *skb, struct net_device *dev)
 {
+	struct sk_buff *skbn;
 	int result;
 
 
 	/* X.25 to LAPB */
 	switch (skb->data[0]) {
 	case X25_IFACE_DATA:	/* Data to be transmitted */
-		skb_pull(skb, 1);
-		if ((result = lapb_data_request(dev, skb)) != LAPB_OK)
-			dev_kfree_skb(skb);
-		return NETDEV_TX_OK;
+		skbn = skb_copy(skb, GFP_ATOMIC);
+		skb_pull(skbn, 1);
+		skb_reset_network_header(skbn);
+		if ((result = lapb_data_request(dev, skbn)) != LAPB_OK)
+			dev_kfree_skb(skbn);
+		break;
 
 	case X25_IFACE_CONNECT:
 		if ((result = lapb_connect_request(dev))!= LAPB_OK) {