Skip to contentSkip to conversation

packet: in packet_snd start writing at link layer allocation

PATCH In review Willem de Bruijn 3 participants 6 messages May 11, 2018 – May 24, 2018

Subsystems (3)
lore
Share & tools
lore

Willem de Bruijn

author maintainer
#0 lore raw

PATCH 1/1 packet: in packet_snd start writing at link layer allocation

From: Willem de Bruijn <[email protected]>

Packet sockets allow construction of packets shorter than dev->hard_header_len to accommodate protocols with variable length link layer headers. These packets are padded to dev->hard_header_len, because some device drivers interpret that as a minimum packet size.

packet_snd reserves dev->hard_header_len bytes on allocation. SOCK_DGRAM sockets call skb_push in dev_hard_header() to ensure that link layer headers are stored in the reserved range. SOCK_RAW sockets do the same in tpacket_snd, but not in packet_snd.

Syzbot was able to send a zero byte packet to a device with massive 116B link layer header, causing padding to cross over into skb_shinfo. Fix this by writing from the start of the llheader reserved range also in the case of packet_snd/SOCK_RAW.

Update skb_set_network_header to the new offset. This also corrects it for SOCK_DGRAM, where it incorrectly double counted reserve due to the skb_push in dev_hard_header.

Fixes 9ed988cd5915 ("packet: validate variable length ll headers")
Reported-by [email protected]
---
 net/packet/af_packet.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
net/packet/af_packet.c +3 -1
index 01f3515cada0d..e9422fe451793 100644
@@ -2903,13 +2903,15 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
 	if (skb == NULL)
 		goto out_unlock;
 
-	skb_set_network_header(skb, reserve);
+	skb_reset_network_header(skb);
 
 	err = -EINVAL;
 	if (sock->type == SOCK_DGRAM) {
 		offset = dev_hard_header(skb, dev, ntohs(proto), addr, NULL, len);
 		if (unlikely(offset < 0))
 			goto out_free;
+	} else if (reserve) {
+		skb_push(skb, reserve);
 	}
 
 	/* Returns -EFAULT on error */
Signature · 1 line
2.17.0.441.gb46fe60e1d-goog
maintainer
#1 lore raw

From: Willem de Bruijn <[email protected]>
Date: Fri, 11 May 2018 13:24:25 -0400

Quoted 17 lines

From: Willem de Bruijn <[email protected]>

Packet sockets allow construction of packets shorter than dev->hard_header_len to accommodate protocols with variable length link layer headers. These packets are padded to dev->hard_header_len, because some device drivers interpret that as a minimum packet size.

packet_snd reserves dev->hard_header_len bytes on allocation. SOCK_DGRAM sockets call skb_push in dev_hard_header() to ensure that link layer headers are stored in the reserved range. SOCK_RAW sockets do the same in tpacket_snd, but not in packet_snd.

Syzbot was able to send a zero byte packet to a device with massive 116B link layer header, causing padding to cross over into skb_shinfo. Fix this by writing from the start of the llheader reserved range also in the case of packet_snd/SOCK_RAW.

Quoted 7 lines

Update skb_set_network_header to the new offset. This also corrects it for SOCK_DGRAM, where it incorrectly double counted reserve due to the skb_push in dev_hard_header.

Fixes 9ed988cd5915 ("packet: validate variable length ll headers")
Reported-by [email protected]

Applied and queued up for -stable, thanks Willem.

#2 lore raw
Quoted 24 lines · David Miller

From: Willem de Bruijn <[email protected]>
Date: Fri, 11 May 2018 13:24:25 -0400

Quoted 21 lines

From: Willem de Bruijn <[email protected]>

Packet sockets allow construction of packets shorter than dev->hard_header_len to accommodate protocols with variable length link layer headers. These packets are padded to dev->hard_header_len, because some device drivers interpret that as a minimum packet size.

packet_snd reserves dev->hard_header_len bytes on allocation. SOCK_DGRAM sockets call skb_push in dev_hard_header() to ensure that link layer headers are stored in the reserved range. SOCK_RAW sockets do the same in tpacket_snd, but not in packet_snd.

Syzbot was able to send a zero byte packet to a device with massive 116B link layer header, causing padding to cross over into skb_shinfo. Fix this by writing from the start of the llheader reserved range also in the case of packet_snd/SOCK_RAW.

Update skb_set_network_header to the new offset. This also corrects it for SOCK_DGRAM, where it incorrectly double counted reserve due to the skb_push in dev_hard_header.

Quoted 6 lines
Quoted 3 lines
Fixes 9ed988cd5915 ("packet: validate variable length ll headers")
Reported-by [email protected]

Applied and queued up for -stable, thanks Willem.

Hi,

One of our regression tests started failing. Once this patch is reverted, test passes.

The tests add flow steering rules in the receiver side and in the sender side it send the packet with some RAW socket applications. Then received side gets completion with error.

Our verification team compared the packets between the stable and the broken version, in the broken version we have some extra bytes at the end of the packet.

It looks like some bad push to the SKB, maybe the conditional reserved addition should be more strict?

Any idea?

Regards,
Tariq

author maintainer
#3 lore raw
Quoted 45 lines · Tariq Toukan
Quoted 25 lines · David Miller

From: Willem de Bruijn <[email protected]>
Date: Fri, 11 May 2018 13:24:25 -0400

Quoted 21 lines

From: Willem de Bruijn <[email protected]>

Packet sockets allow construction of packets shorter than dev->hard_header_len to accommodate protocols with variable length link layer headers. These packets are padded to dev->hard_header_len, because some device drivers interpret that as a minimum packet size.

packet_snd reserves dev->hard_header_len bytes on allocation. SOCK_DGRAM sockets call skb_push in dev_hard_header() to ensure that link layer headers are stored in the reserved range. SOCK_RAW sockets do the same in tpacket_snd, but not in packet_snd.

Syzbot was able to send a zero byte packet to a device with massive 116B link layer header, causing padding to cross over into skb_shinfo. Fix this by writing from the start of the llheader reserved range also in the case of packet_snd/SOCK_RAW.

Update skb_set_network_header to the new offset. This also corrects it for SOCK_DGRAM, where it incorrectly double counted reserve due to the skb_push in dev_hard_header.

Quoted 7 lines
Quoted 3 lines
Fixes 9ed988cd5915 ("packet: validate variable length ll headers")
Reported-by [email protected]

Applied and queued up for -stable, thanks Willem.

Hi,

One of our regression tests started failing. Once this patch is reverted, test passes.

The tests add flow steering rules in the receiver side and in the sender side it send the packet with some RAW socket applications. Then received side gets completion with error.

Quoted 8 lines

Our verification team compared the packets between the stable and the broken version, in the broken version we have some extra bytes at the end of the packet.

It looks like some bad push to the SKB, maybe the conditional reserved addition should be more strict?

Any idea?

Thanks for reporting, sorry for the breakage.

I think I might. This skb_push moves back the start of skb->data in the same way that tpacket_snd does. But it does not reduce the length passed to skb_put, so this might double count hard_header_len.

Let me construct a test.

author maintainer
#4 lore raw
Quoted 55 lines · Willem de Bruijn
Quoted 45 lines · Tariq Toukan
Quoted 25 lines · David Miller

From: Willem de Bruijn <[email protected]>
Date: Fri, 11 May 2018 13:24:25 -0400

Quoted 21 lines

From: Willem de Bruijn <[email protected]>

Packet sockets allow construction of packets shorter than dev->hard_header_len to accommodate protocols with variable length link layer headers. These packets are padded to dev->hard_header_len, because some device drivers interpret that as a minimum packet size.

packet_snd reserves dev->hard_header_len bytes on allocation. SOCK_DGRAM sockets call skb_push in dev_hard_header() to ensure that link layer headers are stored in the reserved range. SOCK_RAW sockets do the same in tpacket_snd, but not in packet_snd.

Syzbot was able to send a zero byte packet to a device with massive 116B link layer header, causing padding to cross over into skb_shinfo. Fix this by writing from the start of the llheader reserved range also in the case of packet_snd/SOCK_RAW.

Update skb_set_network_header to the new offset. This also corrects it for SOCK_DGRAM, where it incorrectly double counted reserve due to the skb_push in dev_hard_header.

Quoted 7 lines
Quoted 3 lines
Fixes 9ed988cd5915 ("packet: validate variable length ll headers")
Reported-by [email protected]

Applied and queued up for -stable, thanks Willem.

Hi,

One of our regression tests started failing. Once this patch is reverted, test passes.

The tests add flow steering rules in the receiver side and in the sender side it send the packet with some RAW socket applications. Then received side gets completion with error.

Quoted 8 lines

Our verification team compared the packets between the stable and the broken version, in the broken version we have some extra bytes at the end of the packet.

It looks like some bad push to the SKB, maybe the conditional reserved addition should be more strict?

Any idea?

Quoted 7 lines

Thanks for reporting, sorry for the breakage.

I think I might. This skb_push moves back the start of skb->data in the same way that tpacket_snd does. But it does not reduce the length passed to skb_put, so this might double count hard_header_len.

Let me construct a test.

Indeed.

Still verifying, but this almost certainly has to be

@@ -2911,7 +2912,7 @@ static int packet_snd(struct socket *sock,
struct msghdr *msg, size_t len)

                  if (unlikely(offset < 0))
                          goto out_free;
          } else if (reserve) {
  -               skb_push(skb, reserve);
  +               skb_reserve(skb, -reserve);
          }

to move the start of the packet without changing its length.

author maintainer
#5 lore raw
Quoted 71 lines · Willem de Bruijn
Quoted 55 lines · Willem de Bruijn
Quoted 45 lines · Tariq Toukan
Quoted 25 lines · David Miller

From: Willem de Bruijn <[email protected]>
Date: Fri, 11 May 2018 13:24:25 -0400

Quoted 21 lines

From: Willem de Bruijn <[email protected]>

Packet sockets allow construction of packets shorter than dev->hard_header_len to accommodate protocols with variable length link layer headers. These packets are padded to dev->hard_header_len, because some device drivers interpret that as a minimum packet size.

packet_snd reserves dev->hard_header_len bytes on allocation. SOCK_DGRAM sockets call skb_push in dev_hard_header() to ensure that link layer headers are stored in the reserved range. SOCK_RAW sockets do the same in tpacket_snd, but not in packet_snd.

Syzbot was able to send a zero byte packet to a device with massive 116B link layer header, causing padding to cross over into skb_shinfo. Fix this by writing from the start of the llheader reserved range also in the case of packet_snd/SOCK_RAW.

Update skb_set_network_header to the new offset. This also corrects it for SOCK_DGRAM, where it incorrectly double counted reserve due to the skb_push in dev_hard_header.

Quoted 7 lines
Quoted 3 lines
Fixes 9ed988cd5915 ("packet: validate variable length ll headers")
Reported-by [email protected]

Applied and queued up for -stable, thanks Willem.

Hi,

One of our regression tests started failing. Once this patch is reverted, test passes.

The tests add flow steering rules in the receiver side and in the sender side it send the packet with some RAW socket applications. Then received side gets completion with error.

Quoted 8 lines

Our verification team compared the packets between the stable and the broken version, in the broken version we have some extra bytes at the end of the packet.

It looks like some bad push to the SKB, maybe the conditional reserved addition should be more strict?

Any idea?

Quoted 7 lines

Thanks for reporting, sorry for the breakage.

I think I might. This skb_push moves back the start of skb->data in the same way that tpacket_snd does. But it does not reduce the length passed to skb_put, so this might double count hard_header_len.

Let me construct a test.

Indeed.

Still verifying, but this almost certainly has to be

@@ -2911,7 +2912,7 @@ static int packet_snd(struct socket *sock,
struct msghdr *msg, size_t len)

Quoted 8 lines
                  if (unlikely(offset < 0))
                          goto out_free;
          } else if (reserve) {
  -               skb_push(skb, reserve);
  +               skb_reserve(skb, -reserve);
          }

to move the start of the packet without changing its length.

I sent http://patchwork.ozlabs.org/patch/920126/

Again, thanks a lot for reporting this, Tariq. I'm working on some packet socket boundary condition tests for tools/testing/selftests/net, so that I cannot push such a mistake again.