packet: validate address length if non-zero
Subsystems (3)
Willem de Bruijn
maintainerPATCH 1/1 packet: validate address length if non-zero
From: Willem de Bruijn <[email protected]>
Validate packet socket address length if a length is given. Zero length is equivalent to not setting an address.
--- net/packet/af_packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/packet/af_packet.c +2 -2
@@ -2625,7 +2625,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (&po->sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out;
@@ -2825,7 +2825,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll , sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out;
Signature · 1 line
2.20.1.415.g653613c723-goog
From: Willem de Bruijn <[email protected]>
Date: Sat, 22 Dec 2018 16:53:45 -0500
Quoted 8 lines
From: Willem de Bruijn <[email protected]>
Validate packet socket address length if a length is given. Zero length is equivalent to not setting an address.
Fixes 99137b7888f4 ("packet: validate address length")Reported-by Ido Schimmel <[email protected]>Signed-off-by Willem de Bruijn <[email protected]>
Applied, thanks Willem.
I'll put this into -stable next to the patch it fixes.
Thanks again.
Willem de Bruijn
maintainerQuoted 9 lines · David Miller
From: Willem de Bruijn <[email protected]>
Date: Sat, 22 Dec 2018 16:53:45 -0500Quoted 5 lines
From: Willem de Bruijn <[email protected]>
Validate packet socket address length if a length is given. Zero length is equivalent to not setting an address.
Quoted 7 lines
Quoted 3 lines
Fixes 99137b7888f4 ("packet: validate address length")Reported-by Ido Schimmel <[email protected]>Signed-off-by Willem de Bruijn <[email protected]>Applied, thanks Willem.
I'll put this into -stable next to the patch it fixes.
Thanks David. Sorry for the earlier cock-up.
Looking at this, I noticed one header_ops.create implementation that always expects non-zero daddr. Will send a small fix for that, too.
Quoted 8 lines · Willem de Bruijn
From: Willem de Bruijn <[email protected]>
Validate packet socket address length if a length is given. Zero length is equivalent to not setting an address.
Fixes 99137b7888f4 ("packet: validate address length")Reported-by Ido Schimmel <[email protected]>Signed-off-by Willem de Bruijn <[email protected]>
Thanks for the quick fix! Issue is gone with this patch.
From: Willem de Bruijn
Quoted 34 lines
Sent: 22 December 2018 21:54
Validate packet socket address length if a length is given. Zero length is equivalent to not setting an address.Fixes 99137b7888f4 ("packet: validate address length")Reported-by Ido Schimmel <[email protected]>Signed-off-by Willem de Bruijn <[email protected]>--- net/packet/af_packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)net/packet/af_packet.c +2
-3@@ -2625,7 +2625,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (&po->sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out;@@ -2825,7 +2825,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll , sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out; --
Quoted 1 line
2.20.1.415.g653613c723-goog
We've just discovered the combination of this patch and the one it 'fixes' breaks some of our userspace code.
Prior to these changes it didn't matter if code using AF_PACKET to send ethernet frames on a specific 'ethertype' failed to set sll_addr. Everything assumed it would be 6 - and the packets were sent.
With both changes you get a -EINVAL return from somewhere. I can fix our code, but I doubt it is the only code affected. Other people are likely to have copied the same example.
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Willem de Bruijn
maintainerQuoted 41 lines · David Laight
From: Willem de Bruijn
Quoted 34 lines
Sent: 22 December 2018 21:54
Validate packet socket address length if a length is given. Zero length is equivalent to not setting an address.Fixes 99137b7888f4 ("packet: validate address length")Reported-by Ido Schimmel <[email protected]>Signed-off-by Willem de Bruijn <[email protected]>--- net/packet/af_packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)net/packet/af_packet.c +2
-3@@ -2625,7 +2625,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (&po->sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out;@@ -2825,7 +2825,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll , sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out; --Quoted 1 line
2.20.1.415.g653613c723-goog
We've just discovered the combination of this patch and the one it 'fixes' breaks some of our userspace code.
Quoted 7 lines
Prior to these changes it didn't matter if code using
AF_PACKETto send ethernet frames on a specific 'ethertype' failed to setsll_addr. Everything assumed it would be 6 - and the packets were sent.With both changes you get a
-EINVALreturn from somewhere. I can fix our code, but I doubt it is the only code affected. Other people are likely to have copied the same example.
Thanks for the report.
Usage trumps correctness. But this seems to be a case of damned if you do, damned if you don't.
Syzbot found a real use case of reading beyond the end of msg->msg_namelen, since that is checked against
if (msg->msg_namelen < (saddr->sll_halen +
offsetof(struct sockaddr_ll, sll_addr)))
Just assuming that address length is dev->addr_len allows an ns_capable root to build link layer packets with address set to uninitialized data.
Ethernet is not the most problematic link layer. Indeed, since ETH_ALEN < sizeof(sll_addr), the previous check
if (msg->msg_namelen < sizeof(struct sockaddr_ll))
Will be sufficient in this case. The syzbot report was on a device of type ip6gre, with addr_len sizeof(struct in6_addr).
So I can refine to only perform the check on protocols with addr_len
Quoted 1 line
=
sizeof(sll_addr), excluding Ethernet.
From: Willem de Bruijn
Quoted 69 lines
Sent: 23 April 2019 16:08
Quoted 41 lines · David Laight
From: Willem de Bruijn
Quoted 34 lines
Sent: 22 December 2018 21:54
Validate packet socket address length if a length is given. Zero length is equivalent to not setting an address.Fixes 99137b7888f4 ("packet: validate address length")Reported-by Ido Schimmel <[email protected]>Signed-off-by Willem de Bruijn <[email protected]>--- net/packet/af_packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)net/packet/af_packet.c +2
-3@@ -2625,7 +2625,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (&po->sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out;@@ -2825,7 +2825,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll , sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out; --Quoted 1 line
2.20.1.415.g653613c723-goog
We've just discovered the combination of this patch and the one it 'fixes' breaks some of our userspace code.
Quoted 7 lines
Prior to these changes it didn't matter if code using
AF_PACKETto send ethernet frames on a specific 'ethertype' failed to setsll_addr. Everything assumed it would be 6 - and the packets were sent.With both changes you get a
-EINVALreturn from somewhere. I can fix our code, but I doubt it is the only code affected. Other people are likely to have copied the same example.Thanks for the report.
Usage trumps correctness. But this seems to be a case of damned if you do, damned if you don't.
Syzbot found a real use case of reading beyond the end of
msg->msg_namelen, since that is checked againstif (msg->msg_namelen < (saddr->sll_halen +
offsetof(struct sockaddr_ll, sll_addr)))Just assuming that address length is
dev->addr_lenallows anns_capableroot to build link layer packets with address set to uninitialized data.Ethernet is not the most problematic link layer. Indeed, since
ETH_ALEN<sizeof(sll_addr), the previous check
Quoted 7 lines
if (msg->msg_namelen < sizeof(struct sockaddr_ll))Will be sufficient in this case. The syzbot report was on a device of type ip6gre, with
addr_lensizeof(struct in6_addr).So I can refine to only perform the check on protocols with
addr_lenQuoted 1 line
=
sizeof(sll_addr), excluding Ethernet.
Maybe something like:
addr = saddr->sll_addr; dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); if (dev && msg->msg_namelen < (dev->addr_len + offsetof(struct sockaddr_ll, sll_addr))) /* Don't read address from beyond the end of the buffer */ goto out;
So it just checks that all of the address is in the buffer passed from the user.
Although I'd write those tests in a different order:
if (dev && offsetof(struct sockaddr_ll, sll_addr) + dev->addr_len > msg->msg_namelen) goto out;
FWIW the relevant application code has been in our cvs tree for 13 years. Mark Brown might remember where he stole it from :-)
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Willem de Bruijn
maintainerQuoted 88 lines · David Laight
From: Willem de Bruijn
Quoted 69 lines
Sent: 23 April 2019 16:08
Quoted 41 lines · David Laight
From: Willem de Bruijn
Quoted 34 lines
Sent: 22 December 2018 21:54
Validate packet socket address length if a length is given. Zero length is equivalent to not setting an address.Fixes 99137b7888f4 ("packet: validate address length")Reported-by Ido Schimmel <[email protected]>Signed-off-by Willem de Bruijn <[email protected]>--- net/packet/af_packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)net/packet/af_packet.c +2
-3@@ -2625,7 +2625,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (&po->sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out;@@ -2825,7 +2825,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll , sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out; --Quoted 1 line
2.20.1.415.g653613c723-goog
We've just discovered the combination of this patch and the one it 'fixes' breaks some of our userspace code.
Quoted 7 lines
Prior to these changes it didn't matter if code using
AF_PACKETto send ethernet frames on a specific 'ethertype' failed to setsll_addr. Everything assumed it would be 6 - and the packets were sent.With both changes you get a
-EINVALreturn from somewhere. I can fix our code, but I doubt it is the only code affected. Other people are likely to have copied the same example.Thanks for the report.
Usage trumps correctness. But this seems to be a case of damned if you do, damned if you don't.
Syzbot found a real use case of reading beyond the end of
msg->msg_namelen, since that is checked againstif (msg->msg_namelen < (saddr->sll_halen +
offsetof(struct sockaddr_ll, sll_addr)))Just assuming that address length is
dev->addr_lenallows anns_capableroot to build link layer packets with address set to uninitialized data.Ethernet is not the most problematic link layer. Indeed, since
ETH_ALEN<sizeof(sll_addr), the previous checkQuoted 7 lines
if (msg->msg_namelen < sizeof(struct sockaddr_ll))Will be sufficient in this case. The syzbot report was on a device of type ip6gre, with
addr_lensizeof(struct in6_addr).So I can refine to only perform the check on protocols with
addr_lenQuoted 1 line
=
sizeof(sll_addr), excluding Ethernet.Maybe something like:
addr = saddr->sll_addr; dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); if (dev && msg->msg_namelen < (dev->addr_len + offsetof(struct sockaddr_ll, sll_addr))) /* Don't read address from beyond the end of the buffer */ goto out;
Quoted 2 lines
So it just checks that all of the address is in the buffer passed from the user.
Yes. sll_halen is never used outside this block. Testing that against dev->addr_len just adds needless a level of indirection. We only care that code that assumes the address is dev->addr_len won't read beyond the end of msg->namelen. So this looks great to me (aside from goto out_unlock). Thanks.
Quoted 3 lines
Although I'd write those tests in a different order:
if (dev && offsetof(struct sockaddr_ll, sll_addr) + dev->addr_len > msg->msg_namelen) goto out;
Since there already is a test for msg->msg_namelen < sizeof(struct sockaddr_ll) just before, I'd keep the same order.
Do you want to send a fix, or shall I?
Willem de Bruijn
maintainerQuoted 90 lines · Willem de Bruijn
Quoted 88 lines · David Laight
From: Willem de Bruijn
Quoted 69 lines
Sent: 23 April 2019 16:08
Quoted 41 lines · David Laight
From: Willem de Bruijn
Quoted 34 lines
Sent: 22 December 2018 21:54
Validate packet socket address length if a length is given. Zero length is equivalent to not setting an address.Fixes 99137b7888f4 ("packet: validate address length")Reported-by Ido Schimmel <[email protected]>Signed-off-by Willem de Bruijn <[email protected]>--- net/packet/af_packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)net/packet/af_packet.c +2
-3@@ -2625,7 +2625,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (&po->sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out;@@ -2825,7 +2825,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll , sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out; --Quoted 1 line
2.20.1.415.g653613c723-goog
We've just discovered the combination of this patch and the one it 'fixes' breaks some of our userspace code.
Quoted 7 lines
Prior to these changes it didn't matter if code using
AF_PACKETto send ethernet frames on a specific 'ethertype' failed to setsll_addr. Everything assumed it would be 6 - and the packets were sent.With both changes you get a
-EINVALreturn from somewhere. I can fix our code, but I doubt it is the only code affected. Other people are likely to have copied the same example.Thanks for the report.
Usage trumps correctness. But this seems to be a case of damned if you do, damned if you don't.
Syzbot found a real use case of reading beyond the end of
msg->msg_namelen, since that is checked againstif (msg->msg_namelen < (saddr->sll_halen +
offsetof(struct sockaddr_ll, sll_addr)))Just assuming that address length is
dev->addr_lenallows anns_capableroot to build link layer packets with address set to uninitialized data.Ethernet is not the most problematic link layer. Indeed, since
ETH_ALEN<sizeof(sll_addr), the previous checkQuoted 7 lines
if (msg->msg_namelen < sizeof(struct sockaddr_ll))Will be sufficient in this case. The syzbot report was on a device of type ip6gre, with
addr_lensizeof(struct in6_addr).So I can refine to only perform the check on protocols with
addr_lenQuoted 1 line
=
sizeof(sll_addr), excluding Ethernet.Maybe something like:
addr = saddr->sll_addr; dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); if (dev && msg->msg_namelen < (dev->addr_len + offsetof(struct sockaddr_ll, sll_addr))) /* Don't read address from beyond the end of the buffer */ goto out;
Quoted 8 lines
Quoted 2 lines
So it just checks that all of the address is in the buffer passed from the user.
Yes.
sll_halenis never used outside this block. Testing that againstdev->addr_lenjust adds needless a level of indirection. We only care that code that assumes the address isdev->addr_lenwon't read beyond the end ofmsg->namelen. So this looks great to me (aside from gotoout_unlock). Thanks.
Actually, this only matters if sll_addr may be read, which is only true for SOCK_DGRAM. It is fine to pass a sockaddr_ll without an address for SOCK_RAW.
Quoted 9 lines
Quoted 4 lines
Although I'd write those tests in a different order:
if (dev && offsetof(struct sockaddr_ll, sll_addr) + dev->addr_len > msg->msg_namelen) goto out;Since there already is a test for
msg->msg_namelen<sizeof(struct sockaddr_ll)just before, I'd keep the same order.Do you want to send a fix, or shall I?
Willem de Bruijn
maintainerQuoted 102 lines · Willem de Bruijn
Quoted 90 lines · Willem de Bruijn
Quoted 88 lines · David Laight
From: Willem de Bruijn
Quoted 69 lines
Sent: 23 April 2019 16:08
Quoted 41 lines · David Laight
From: Willem de Bruijn
Quoted 34 lines
Sent: 22 December 2018 21:54
Validate packet socket address length if a length is given. Zero length is equivalent to not setting an address.Fixes 99137b7888f4 ("packet: validate address length")Reported-by Ido Schimmel <[email protected]>Signed-off-by Willem de Bruijn <[email protected]>--- net/packet/af_packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)net/packet/af_packet.c +2
-3@@ -2625,7 +2625,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (&po->sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out;@@ -2825,7 +2825,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll , sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out; --Quoted 1 line
2.20.1.415.g653613c723-goog
We've just discovered the combination of this patch and the one it 'fixes' breaks some of our userspace code.
Quoted 7 lines
Prior to these changes it didn't matter if code using
AF_PACKETto send ethernet frames on a specific 'ethertype' failed to setsll_addr. Everything assumed it would be 6 - and the packets were sent.With both changes you get a
-EINVALreturn from somewhere. I can fix our code, but I doubt it is the only code affected. Other people are likely to have copied the same example.Thanks for the report.
Usage trumps correctness. But this seems to be a case of damned if you do, damned if you don't.
Syzbot found a real use case of reading beyond the end of
msg->msg_namelen, since that is checked againstif (msg->msg_namelen < (saddr->sll_halen +
offsetof(struct sockaddr_ll, sll_addr)))Just assuming that address length is
dev->addr_lenallows anns_capableroot to build link layer packets with address set to uninitialized data.Ethernet is not the most problematic link layer. Indeed, since
ETH_ALEN<sizeof(sll_addr), the previous checkQuoted 7 lines
if (msg->msg_namelen < sizeof(struct sockaddr_ll))Will be sufficient in this case. The syzbot report was on a device of type ip6gre, with
addr_lensizeof(struct in6_addr).So I can refine to only perform the check on protocols with
addr_lenQuoted 1 line
=
sizeof(sll_addr), excluding Ethernet.Maybe something like:
addr = saddr->sll_addr; dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); if (dev && msg->msg_namelen < (dev->addr_len + offsetof(struct sockaddr_ll, sll_addr))) /* Don't read address from beyond the end of the buffer */ goto out;Quoted 8 lines
Quoted 2 lines
So it just checks that all of the address is in the buffer passed from the user.
Yes.
sll_halenis never used outside this block. Testing that againstdev->addr_lenjust adds needless a level of indirection. We only care that code that assumes the address isdev->addr_lenwon't read beyond the end ofmsg->namelen. So this looks great to me (aside from gotoout_unlock). Thanks.
Quoted 3 lines
Actually, this only matters if
sll_addrmay be read, which is only true forSOCK_DGRAM. It is fine to pass asockaddr_llwithout an address forSOCK_RAW.
So something like
net/packet/af_packet.c +0 -0
@@ -2819,12 +2819,10 @@ static int packet_snd(struct socket *sock,
struct msghdr *msg, size_t len)
err = -EINVAL;
if (msg->msg_namelen < sizeof(struct sockaddr_ll))
goto out;
- if (msg->msg_namelen < (saddr->sll_halen +
offsetof(struct sockaddr_ll, sll_addr)))
- goto out;
proto = saddr->sll_protocol;
- addr = saddr->sll_halen ? saddr->sll_addr : NULL;
+ addr = sock->type == SOCK_DGRAM ? saddr->sll_addr : NULL;
dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex);
- if (addr && dev && saddr->sll_halen < dev->addr_len)
+ if (addr && dev && msg->msg_namelen < (dev->addr_len +
offsetof(struct sockaddr_ll, sll_addr)))
goto out_unlock;Willem de Bruijn
maintainerQuoted 130 lines · Willem de Bruijn
Quoted 102 lines · Willem de Bruijn
Quoted 90 lines · Willem de Bruijn
Quoted 88 lines · David Laight
From: Willem de Bruijn
Quoted 69 lines
Sent: 23 April 2019 16:08
Quoted 41 lines · David Laight
From: Willem de Bruijn
Quoted 34 lines
Sent: 22 December 2018 21:54
Validate packet socket address length if a length is given. Zero length is equivalent to not setting an address.Fixes 99137b7888f4 ("packet: validate address length")Reported-by Ido Schimmel <[email protected]>Signed-off-by Willem de Bruijn <[email protected]>--- net/packet/af_packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)net/packet/af_packet.c +2
-3@@ -2625,7 +2625,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (&po->sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out;@@ -2825,7 +2825,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll , sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out; --Quoted 1 line
2.20.1.415.g653613c723-goog
We've just discovered the combination of this patch and the one it 'fixes' breaks some of our userspace code.
Quoted 7 lines
Prior to these changes it didn't matter if code using
AF_PACKETto send ethernet frames on a specific 'ethertype' failed to setsll_addr. Everything assumed it would be 6 - and the packets were sent.With both changes you get a
-EINVALreturn from somewhere. I can fix our code, but I doubt it is the only code affected. Other people are likely to have copied the same example.Thanks for the report.
Usage trumps correctness. But this seems to be a case of damned if you do, damned if you don't.
Syzbot found a real use case of reading beyond the end of
msg->msg_namelen, since that is checked againstif (msg->msg_namelen < (saddr->sll_halen +
offsetof(struct sockaddr_ll, sll_addr)))Just assuming that address length is
dev->addr_lenallows anns_capableroot to build link layer packets with address set to uninitialized data.Ethernet is not the most problematic link layer. Indeed, since
ETH_ALEN<sizeof(sll_addr), the previous checkQuoted 7 lines
if (msg->msg_namelen < sizeof(struct sockaddr_ll))Will be sufficient in this case. The syzbot report was on a device of type ip6gre, with
addr_lensizeof(struct in6_addr).So I can refine to only perform the check on protocols with
addr_lenQuoted 1 line
=
sizeof(sll_addr), excluding Ethernet.Maybe something like:
addr = saddr->sll_addr; dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); if (dev && msg->msg_namelen < (dev->addr_len + offsetof(struct sockaddr_ll, sll_addr))) /* Don't read address from beyond the end of the buffer */ goto out;Quoted 8 lines
Quoted 2 lines
So it just checks that all of the address is in the buffer passed from the user.
Yes.
sll_halenis never used outside this block. Testing that againstdev->addr_lenjust adds needless a level of indirection. We only care that code that assumes the address isdev->addr_lenwon't read beyond the end ofmsg->namelen. So this looks great to me (aside from gotoout_unlock). Thanks.Quoted 3 lines
Actually, this only matters if
sll_addrmay be read, which is only true forSOCK_DGRAM. It is fine to pass asockaddr_llwithout an address forSOCK_RAW.So something like
net/packet/af_packet.c +2
-4@@ -2819,12 +2819,10 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) err = -EINVAL ;if (msg->msg_namelen <sizeof (struct sockaddr_ll )) goto out; -if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll, sll_addr))) - goto out; proto = saddr->sll_protocol; - addr = saddr->sll_halen ? saddr->sll_addr :NULL ; + addr = sock->type ==SOCK_DGRAM ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (sk), saddr->sll_ifindex); -if (addr && dev && saddr->sll_halen < dev->addr_len) +if (addr && dev && msg->msg_namelen < (dev->addr_len + offsetof(struct sockaddr_ll , sll_addr)))
Quoted 1 line
goto out_unlock;
Sent http://patchwork.ozlabs.org/patch/1090340/
Though I probably misunderstood your issue.
I initially thought that an sll_halen > 0 < dev->addr_len was triggering the immediately check.
But I guess that the real issue was an sll_halen == 0 was causing addr to be NULL, but dev_hard_header still called. For Ethernet, eth_header then does not fail, but simply does not fill in eth->h_dest.
Let me know if you'd prefer a revised commit message.
Willem de Bruijn
maintainerQuoted 137 lines · Willem de Bruijn
Quoted 130 lines · Willem de Bruijn
Quoted 102 lines · Willem de Bruijn
Quoted 90 lines · Willem de Bruijn
Quoted 88 lines · David Laight
From: Willem de Bruijn
Quoted 69 lines
Sent: 23 April 2019 16:08
Quoted 41 lines · David Laight
From: Willem de Bruijn
Quoted 34 lines
Sent: 22 December 2018 21:54
Validate packet socket address length if a length is given. Zero length is equivalent to not setting an address.Fixes 99137b7888f4 ("packet: validate address length")Reported-by Ido Schimmel <[email protected]>Signed-off-by Willem de Bruijn <[email protected]>--- net/packet/af_packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)net/packet/af_packet.c +2
-3@@ -2625,7 +2625,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (&po->sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out;@@ -2825,7 +2825,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll , sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out; --Quoted 1 line
2.20.1.415.g653613c723-goog
We've just discovered the combination of this patch and the one it 'fixes' breaks some of our userspace code.
Quoted 7 lines
Prior to these changes it didn't matter if code using
AF_PACKETto send ethernet frames on a specific 'ethertype' failed to setsll_addr. Everything assumed it would be 6 - and the packets were sent.With both changes you get a
-EINVALreturn from somewhere. I can fix our code, but I doubt it is the only code affected. Other people are likely to have copied the same example.Thanks for the report.
Usage trumps correctness. But this seems to be a case of damned if you do, damned if you don't.
Syzbot found a real use case of reading beyond the end of
msg->msg_namelen, since that is checked againstif (msg->msg_namelen < (saddr->sll_halen +
offsetof(struct sockaddr_ll, sll_addr)))Just assuming that address length is
dev->addr_lenallows anns_capableroot to build link layer packets with address set to uninitialized data.Ethernet is not the most problematic link layer. Indeed, since
ETH_ALEN<sizeof(sll_addr), the previous checkQuoted 7 lines
if (msg->msg_namelen < sizeof(struct sockaddr_ll))Will be sufficient in this case. The syzbot report was on a device of type ip6gre, with
addr_lensizeof(struct in6_addr).So I can refine to only perform the check on protocols with
addr_lenQuoted 1 line
=
sizeof(sll_addr), excluding Ethernet.Maybe something like:
addr = saddr->sll_addr; dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); if (dev && msg->msg_namelen < (dev->addr_len + offsetof(struct sockaddr_ll, sll_addr))) /* Don't read address from beyond the end of the buffer */ goto out;Quoted 8 lines
Quoted 2 lines
So it just checks that all of the address is in the buffer passed from the user.
Yes.
sll_halenis never used outside this block. Testing that againstdev->addr_lenjust adds needless a level of indirection. We only care that code that assumes the address isdev->addr_lenwon't read beyond the end ofmsg->namelen. So this looks great to me (aside from gotoout_unlock). Thanks.Quoted 3 lines
Actually, this only matters if
sll_addrmay be read, which is only true forSOCK_DGRAM. It is fine to pass asockaddr_llwithout an address forSOCK_RAW.So something like
net/packet/af_packet.c +2
-4@@ -2819,12 +2819,10 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) err = -EINVAL ;if (msg->msg_namelen <sizeof (struct sockaddr_ll )) goto out; -if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll, sll_addr))) - goto out; proto = saddr->sll_protocol; - addr = saddr->sll_halen ? saddr->sll_addr :NULL ; + addr = sock->type ==SOCK_DGRAM ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (sk), saddr->sll_ifindex); -if (addr && dev && saddr->sll_halen < dev->addr_len) +if (addr && dev && msg->msg_namelen < (dev->addr_len + offsetof(struct sockaddr_ll , sll_addr)))Quoted 1 line
goto out_unlock;
Quoted 8 lines
Though I probably misunderstood your issue.
I initially thought that an
sll_halen> 0 <dev->addr_lenwas triggering the immediately check.But I guess that the real issue was an
sll_halen== 0 was causing addr to be NULL, butdev_hard_headerstill called. For Ethernet,eth_headerthen does not fail, but simply does not fill ineth->h_dest.
Luckily I misread. It *does* fail and so does sendto. But indeed in a different way than I previously understood your report.
Quoted 1 line
Let me know if you'd prefer a revised commit message.
This, then, still stands.
From: Willem de Bruijn
Quoted 148 lines
Sent: 24 April 2019 20:35
Quoted 28 lines · Willem de Bruijn
Quoted 25 lines · Willem de Bruijn
Quoted 22 lines · Willem de Bruijn
Quoted 19 lines · Willem de Bruijn
Quoted 17 lines · David Laight
From: Willem de Bruijn
Quoted 15 lines
Sent: 23 April 2019 16:08
Quoted 13 lines · David Laight
From: Willem de Bruijn
Quoted 11 lines
Sent: 22 December 2018 21:54
Validate packet socket address length if a length is given. Zero length is equivalent to not setting an address.Fixes 99137b7888f4 ("packet: validate address length")Reported-by Ido Schimmel <[email protected]>Signed-off-by Willem de Bruijn <[email protected]>--- net/packet/af_packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
net/packet/af_packet.c static int tpacket_snd(struct packet_sock *po, struct msghdr
Quoted 5 lines
net/packet/af_packet.c +0
-0@@ -2625,7 +2625,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr*msg)
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
net/packet/af_packet.c static int packet_snd(struct socket *sock, struct msghdr *msg,
Quoted 9 lines
net/packet/af_packet.c +1
-1sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (&po->sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out;@@ -2825,7 +2825,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg,
size_tlen)Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
net/packet/af_packet.c static int packet_snd(struct socket *sock, struct msghdr *msg, · line 2825
Quoted 1 line
net/packet/af_packet.c +0
-0if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll,
sll_addr)))Quoted 99 lines
Quoted 90 lines
Quoted 65 lines
Quoted 56 lines
Quoted 56 lines
Quoted 39 lines
Quoted 13 lines
Quoted 9 lines
net/packet/af_packet.c +1
-2goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out; --2.20.1.415.g653613c723-goog
We've just discovered the combination of this patch and the one it 'fixes' breaks some of our userspace code.
Quoted 7 lines
Prior to these changes it didn't matter if code using
AF_PACKETto send ethernet frames on a specific 'ethertype' failed to setsll_addr. Everything assumed it would be 6 - and the packets were sent.With both changes you get a
-EINVALreturn from somewhere. I can fix our code, but I doubt it is the only code affected. Other people are likely to have copied the same example.Thanks for the report.
Usage trumps correctness. But this seems to be a case of damned if you do, damned if you don't.
Syzbot found a real use case of reading beyond the end of
msg->msg_namelen, since that is checked againstif (msg->msg_namelen < (saddr->sll_halen +
offsetof(struct sockaddr_ll, sll_addr)))Just assuming that address length is
dev->addr_lenallows anns_capableroot to build link layer packets with address set to uninitialized data.Ethernet is not the most problematic link layer. Indeed, since
ETH_ALEN<sizeof(sll_addr), the previous checkQuoted 7 lines
if (msg->msg_namelen < sizeof(struct sockaddr_ll))Will be sufficient in this case. The syzbot report was on a device of type ip6gre, with
addr_lensizeof(struct in6_addr).So I can refine to only perform the check on protocols with
addr_lenQuoted 1 line
=
sizeof(sll_addr), excluding Ethernet.Maybe something like:
addr = saddr->sll_addr; dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); if (dev && msg->msg_namelen < (dev->addr_len + offsetof(struct sockaddr_ll, sll_addr))) /* Don't read address from beyond the end of the buffer */ goto out;Quoted 8 lines
Quoted 2 lines
So it just checks that all of the address is in the buffer passed from the user.
Yes.
sll_halenis never used outside this block. Testing that againstdev->addr_lenjust adds needless a level of indirection. We only care that code that assumes the address isdev->addr_lenwon't read beyond the end ofmsg->namelen. So this looks great to me (aside from gotoout_unlock). Thanks.Quoted 3 lines
Actually, this only matters if
sll_addrmay be read, which is only true forSOCK_DGRAM. It is fine to pass asockaddr_llwithout an address forSOCK_RAW.So something like
net/packet/af_packet.c +2
-4@@ -2819,12 +2819,10 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) err = -EINVAL ;if (msg->msg_namelen <sizeof (struct sockaddr_ll )) goto out; -if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll, sll_addr))) - goto out; proto = saddr->sll_protocol; - addr = saddr->sll_halen ? saddr->sll_addr :NULL ; + addr = sock->type ==SOCK_DGRAM ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (sk), saddr->sll_ifindex); -if (addr && dev && saddr->sll_halen < dev->addr_len) +if (addr && dev && msg->msg_namelen < (dev->addr_len + offsetof(struct sockaddr_ll , sll_addr)))Quoted 1 line
goto out_unlock;Sent http://patchwork.ozlabs.org/patch/1090340/
Though I probably misunderstood your issue.
I initially thought that an
sll_halen> 0 <dev->addr_lenwas triggering the immediately check.
Quoted 6 lines
Quoted 3 lines
But I guess that the real issue was an
sll_halen== 0 was causing addr to be NULL, butdev_hard_headerstill called. For Ethernet,eth_headerthen does not fail, but simply does not fill ineth->h_dest.Luckily I misread. It *does* fail and so does sendto. But indeed in a different way than I previously understood your report.
I didn't track down where the EINVAL came from.
Quoted 1 line
Quoted 1 line
Let me know if you'd prefer a revised commit message.
I've just done a bit of software archaeology.
Prior to 2.6.14-rc3 the send code ignored sll_halen, it was only set by the receive code. So it is not surprising that old application code leaves it as zero.
The old receive code also always set msg_namelen = sizeof (struct sockaddr_ll). The receive code now sets:
msg_namelen = offsetof(struct sockaddr_ll, sll_addr) + saddr->sll_halen;
For ethernet this changes the msg_namelen from 20 to 18.
A side effect (no one has noticed for years) is that you can't send a reply by passing back the received address buffer.
Looking at it all again how about:
char *addr = NULL;
...
err = -EINVAL;
if (msg->msg_namelen < offsetof(struct sockaddr_ll, sll_addr))
goto out;
proto = saddr->sll_protocol;
dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex);
if (dev && sock->type == SOCK_DGRAM) {
if (msg->msg_namelen < dev->addr_len + offsetof(struct sockaddr_ll, sll_addr))
goto out_unlock;
addr = saddr->sll_addr;
}Although it might even be worth moving the check for (dev == NULL) inside the conditional.
Then we'll paint the bikeshed in Paisley.
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Willem de Bruijn
maintainerQuoted 166 lines · David Laight
From: Willem de Bruijn
Quoted 148 lines
Sent: 24 April 2019 20:35
Quoted 28 lines · Willem de Bruijn
Quoted 25 lines · Willem de Bruijn
Quoted 22 lines · Willem de Bruijn
Quoted 19 lines · Willem de Bruijn
Quoted 17 lines · David Laight
From: Willem de Bruijn
Quoted 15 lines
Sent: 23 April 2019 16:08
Quoted 13 lines · David Laight
From: Willem de Bruijn
Quoted 11 lines
Sent: 22 December 2018 21:54
Validate packet socket address length if a length is given. Zero length is equivalent to not setting an address.Fixes 99137b7888f4 ("packet: validate address length")Reported-by Ido Schimmel <[email protected]>Signed-off-by Willem de Bruijn <[email protected]>--- net/packet/af_packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
net/packet/af_packet.c static int tpacket_snd(struct packet_sock *po, struct msghdr
Quoted 5 lines
net/packet/af_packet.c +0
-0@@ -2625,7 +2625,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr*msg)
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
net/packet/af_packet.c static int packet_snd(struct socket *sock, struct msghdr *msg,
Quoted 9 lines
net/packet/af_packet.c +1
-1sll_addr))) goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (&po->sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out;@@ -2825,7 +2825,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg,
size_tlen)Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
net/packet/af_packet.c static int packet_snd(struct socket *sock, struct msghdr *msg, · line 2825
Quoted 1 line
net/packet/af_packet.c +0
-0if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll,
sll_addr)))Quoted 99 lines
Quoted 90 lines
Quoted 65 lines
Quoted 56 lines
Quoted 56 lines
Quoted 39 lines
Quoted 13 lines
Quoted 9 lines
net/packet/af_packet.c +1
-2goto out; proto = saddr->sll_protocol; - addr = saddr->sll_addr; + addr = saddr->sll_halen ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (sk), saddr->sll_ifindex);if (addr && dev && saddr->sll_halen < dev->addr_len) goto out; --2.20.1.415.g653613c723-goog
We've just discovered the combination of this patch and the one it 'fixes' breaks some of our userspace code.
Quoted 7 lines
Prior to these changes it didn't matter if code using
AF_PACKETto send ethernet frames on a specific 'ethertype' failed to setsll_addr. Everything assumed it would be 6 - and the packets were sent.With both changes you get a
-EINVALreturn from somewhere. I can fix our code, but I doubt it is the only code affected. Other people are likely to have copied the same example.Thanks for the report.
Usage trumps correctness. But this seems to be a case of damned if you do, damned if you don't.
Syzbot found a real use case of reading beyond the end of
msg->msg_namelen, since that is checked againstif (msg->msg_namelen < (saddr->sll_halen +
offsetof(struct sockaddr_ll, sll_addr)))Just assuming that address length is
dev->addr_lenallows anns_capableroot to build link layer packets with address set to uninitialized data.Ethernet is not the most problematic link layer. Indeed, since
ETH_ALEN<sizeof(sll_addr), the previous checkQuoted 7 lines
if (msg->msg_namelen < sizeof(struct sockaddr_ll))Will be sufficient in this case. The syzbot report was on a device of type ip6gre, with
addr_lensizeof(struct in6_addr).So I can refine to only perform the check on protocols with
addr_lenQuoted 1 line
=
sizeof(sll_addr), excluding Ethernet.Maybe something like:
addr = saddr->sll_addr; dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); if (dev && msg->msg_namelen < (dev->addr_len + offsetof(struct sockaddr_ll, sll_addr))) /* Don't read address from beyond the end of the buffer */ goto out;Quoted 8 lines
Quoted 2 lines
So it just checks that all of the address is in the buffer passed from the user.
Yes.
sll_halenis never used outside this block. Testing that againstdev->addr_lenjust adds needless a level of indirection. We only care that code that assumes the address isdev->addr_lenwon't read beyond the end ofmsg->namelen. So this looks great to me (aside from gotoout_unlock). Thanks.Quoted 3 lines
Actually, this only matters if
sll_addrmay be read, which is only true forSOCK_DGRAM. It is fine to pass asockaddr_llwithout an address forSOCK_RAW.So something like
net/packet/af_packet.c +2
-4@@ -2819,12 +2819,10 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) err = -EINVAL ;if (msg->msg_namelen <sizeof (struct sockaddr_ll )) goto out; -if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll, sll_addr))) - goto out; proto = saddr->sll_protocol; - addr = saddr->sll_halen ? saddr->sll_addr :NULL ; + addr = sock->type ==SOCK_DGRAM ? saddr->sll_addr :NULL ; dev =dev_get_by_index (sock_net (sk), saddr->sll_ifindex); -if (addr && dev && saddr->sll_halen < dev->addr_len) +if (addr && dev && msg->msg_namelen < (dev->addr_len + offsetof(struct sockaddr_ll , sll_addr)))Quoted 1 line
goto out_unlock;Sent http://patchwork.ozlabs.org/patch/1090340/
Though I probably misunderstood your issue.
I initially thought that an
sll_halen> 0 <dev->addr_lenwas triggering the immediately check.Quoted 6 lines
Quoted 3 lines
But I guess that the real issue was an
sll_halen== 0 was causing addr to be NULL, butdev_hard_headerstill called. For Ethernet,eth_headerthen does not fail, but simply does not fill ineth->h_dest.Luckily I misread. It *does* fail and so does sendto. But indeed in a different way than I previously understood your report.
I didn't track down where the EINVAL came from.
Quoted 1 line
Quoted 1 line
Let me know if you'd prefer a revised commit message.
I've just done a bit of software archaeology.
Prior to 2.6.14-rc3 the send code ignored
sll_halen, it was only set by the receive code. So it is not surprising that old application code leaves it as zero.
Quoted 6 lines
The old receive code also always set
msg_namelen= sizeof (structsockaddr_ll). The receive code now sets:
msg_namelen=offsetof(struct sockaddr_ll, sll_addr)+saddr->sll_halen;
For ethernet this changes themsg_namelenfrom 20 to 18.
A side effect (no one has noticed for years) is that you can't send a reply by passing back the received address buffer.
Great find, thanks. I hadn't thought of going back that far, but clearly should in these legacy caller questions..
Quoted 13 lines
Looking at it all again how about:
char *addr = NULL; ... err = -EINVAL; if (msg->msg_namelen < offsetof(struct sockaddr_ll, sll_addr)) goto out; proto = saddr->sll_protocol; dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); if (dev && sock->type == SOCK_DGRAM) { if (msg->msg_namelen < dev->addr_len + offsetof(struct sockaddr_ll, sll_addr)) goto out_unlock; addr = saddr->sll_addr; }
Yes, given the above, this looks great to me.
In general I'm hesitant to loosen interface constraints. As you can never tighten them again. But given the change on recv, it seems correct here. That is technically a separate issue, so worth a separate patch, I think. If that's not too pedantic. Else at least an extra Fixes tag.
Quoted 4 lines
Although it might even be worth moving the check for (dev == NULL) inside the conditional.
Then we'll paint the bikeshed in Paisley.
:)
Agreed on moving the dev. That makes it really obvious that addr is only used in datagram mode. And indeed exactly matches the branch around the only user, dev_hard_header.
Quoted 5 lines
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
From: Willem de Bruijn
Quoted 1 line
Sent: 25 April 2019 14:57
...
Quoted 12 lines
Quoted 11 lines
I've just done a bit of software archaeology.
Prior to 2.6.14-rc3 the send code ignored
sll_halen, it was only set by the receive code. So it is not surprising that old application code leaves it as zero.The old receive code also always set
msg_namelen= sizeof (structsockaddr_ll). The receive code now sets:
msg_namelen=offsetof(struct sockaddr_ll, sll_addr)+saddr->sll_halen;
For ethernet this changes themsg_namelenfrom 20 to 18.
A side effect (no one has noticed for years) is that you can't send a reply by passing back the received address buffer.
Quoted 2 lines
Great find, thanks. I hadn't thought of going back that far, but clearly should in these legacy caller questions..
Fortunately I didn't have to find the pre-git sources :-)
Quoted 14 lines
Quoted 13 lines
Looking at it all again how about:
char *addr = NULL; ... err = -EINVAL; if (msg->msg_namelen < offsetof(struct sockaddr_ll, sll_addr)) goto out; proto = saddr->sll_protocol; dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); if (dev && sock->type == SOCK_DGRAM) { if (msg->msg_namelen < dev->addr_len + offsetof(struct sockaddr_ll, sll_addr)) goto out_unlock; addr = saddr->sll_addr; }
Quoted 4 lines
Yes, given the above, this looks great to me.
In general I'm hesitant to loosen interface constraints. As you can never tighten them again.
Indeed.
Quoted 4 lines
But given the change on recv, it seems
correct here. That is technically a separate issue, so worth a separate patch, I think. If that's not too pedantic. Else at least an extra Fixes tag.
Or leave the above using 'sizeof' and change the receive code to pad the address to sizeof struct sockaddr_ll.
Which is definitely a completely different fix.
The rx code seems to be:
if (sock->type == SOCK_PACKET) {
__sockaddr_check_size(sizeof(struct sockaddr_pkt));
msg->msg_namelen = sizeof(struct sockaddr_pkt);
} else {
struct sockaddr_ll *sll = &PACKET_SKB_CB(skb)->sa.ll;
msg->msg_namelen = sll->sll_halen +
offsetof(struct sockaddr_ll, sll_addr);
}
memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa,
msg->msg_namelen);Hopefully the buffer is always big enough!
Assuming that the code that sets up the address zaps the last two bytes the SOCK_DGRAM side just needs a max(, sizeof (struct sockaddr_ll)). Zeroing the 8 byte field before the mac address is put into it is cheap (one 64bit write on 64bit systems).
I guess this would have 'Fixes' tag for the 2.6.14 git tag!
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Willem de Bruijn
maintainerQuoted 64 lines · David Laight
From: Willem de Bruijn
Quoted 1 line
Sent: 25 April 2019 14:57
...
Quoted 12 lines
Quoted 11 lines
I've just done a bit of software archaeology.
Prior to 2.6.14-rc3 the send code ignored
sll_halen, it was only set by the receive code. So it is not surprising that old application code leaves it as zero.The old receive code also always set
msg_namelen= sizeof (structsockaddr_ll). The receive code now sets:
msg_namelen=offsetof(struct sockaddr_ll, sll_addr)+saddr->sll_halen;
For ethernet this changes themsg_namelenfrom 20 to 18.
A side effect (no one has noticed for years) is that you can't send a reply by passing back the received address buffer.Quoted 2 lines
Great find, thanks. I hadn't thought of going back that far, but clearly should in these legacy caller questions..
Fortunately I didn't have to find the pre-git sources :-)
Quoted 14 lines
Quoted 13 lines
Looking at it all again how about:
char *addr = NULL; ... err = -EINVAL; if (msg->msg_namelen < offsetof(struct sockaddr_ll, sll_addr)) goto out; proto = saddr->sll_protocol; dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); if (dev && sock->type == SOCK_DGRAM) { if (msg->msg_namelen < dev->addr_len + offsetof(struct sockaddr_ll, sll_addr)) goto out_unlock; addr = saddr->sll_addr; }Quoted 4 lines
Yes, given the above, this looks great to me.
In general I'm hesitant to loosen interface constraints. As you can never tighten them again.
Indeed.
Quoted 4 lines
But given the change on recv, it seems
correct here. That is technically a separate issue, so worth a separate patch, I think. If that's not too pedantic. Else at least an extra Fixes tag.Or leave the above using 'sizeof' and change the receive code to pad the address to sizeof struct
sockaddr_ll.
Which is definitely a completely different fix.
The rx code seems to be:if (sock->type == SOCK_PACKET) { __sockaddr_check_size(sizeof(struct sockaddr_pkt)); msg->msg_namelen = sizeof(struct sockaddr_pkt); } else { struct sockaddr_ll *sll = &PACKET_SKB_CB(skb)->sa.ll; msg->msg_namelen = sll->sll_halen + offsetof(struct sockaddr_ll, sll_addr); } memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa, msg->msg_namelen);
Quoted 1 line
Hopefully the buffer is always big enough!
The kernel buffer is always sockaddr_storage with _K_SS_MAXSIZE or 128B. Before copying into skb->cb[] there is the sock_skb_cb_check_size BUILD_BUG_ON based on the assumption that every lladdr len <= MAX_ADDR_LEN (32B). As far as I can telll, that does seem to hold (INFINIBAND_ALEN being the largest at 32). So while there is no explicit check on the memcpy from skb->cb into msg_name, this is safe.
Quoted 6 lines
Assuming that the code that sets up the address zaps the last two bytes the
SOCK_DGRAMside just needs amax(, sizeof (struct sockaddr_ll)). Zeroing the 8 byte field before the mac address is put into it is cheap (one 64bit write on 64bit systems).I guess this would have 'Fixes' tag for the 2.6.14 git tag!
The uaddr_len change is commit 0fb375fb9b93 ("[AF_PACKET]: Allow for > 8 byte hardware addresses.")?
That both introduced the recv change to return a length based on dev->addr_len even the total is if below sizeof(struct sockaddr_ll)
- else
- msg->msg_namelen = sizeof(struct sockaddr_ll);
[..]
+ else
+ msg->msg_namelen = sll->sll_halen + offsetof(structsockaddr_ll, sll_addr);
and the new sendmsg check
if (msg->msg_namelen < sizeof(struct sockaddr_ll))
goto out;+ if (msg->msg_namelen < (saddr->sll_halen +offsetof(struct sockaddr_ll, sll_addr)))
+ goto out;
but without removing the preexisting check above it, thus causing the recvfrom () followed by sendto() to fail.
Willem de Bruijn
maintainerQuoted 37 lines · Willem de Bruijn
Quoted 35 lines · David Laight
From: Willem de Bruijn
Quoted 1 line
Sent: 25 April 2019 14:57
...
Quoted 12 lines
Quoted 11 lines
I've just done a bit of software archaeology.
Prior to 2.6.14-rc3 the send code ignored
sll_halen, it was only set by the receive code. So it is not surprising that old application code leaves it as zero.The old receive code also always set
msg_namelen= sizeof (structsockaddr_ll). The receive code now sets:
msg_namelen=offsetof(struct sockaddr_ll, sll_addr)+saddr->sll_halen;
For ethernet this changes themsg_namelenfrom 20 to 18.
A side effect (no one has noticed for years) is that you can't send a reply by passing back the received address buffer.Quoted 2 lines
Great find, thanks. I hadn't thought of going back that far, but clearly should in these legacy caller questions..
Fortunately I didn't have to find the pre-git sources :-)
Quoted 14 lines
Quoted 13 lines
Looking at it all again how about:
char *addr = NULL; ... err = -EINVAL; if (msg->msg_namelen < offsetof(struct sockaddr_ll, sll_addr)) goto out; proto = saddr->sll_protocol; dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); if (dev && sock->type == SOCK_DGRAM) { if (msg->msg_namelen < dev->addr_len + offsetof(struct sockaddr_ll, sll_addr)) goto out_unlock; addr = saddr->sll_addr; }
Quoted 1 line
Quoted 1 line
Quoted 1 line
Yes, given the above, this looks great to me.
Coming back to this. Both the above and two separate send/recv fixes seem fine to me. Do you have a preference either way? And do you want to send the fix(es) or should I?
Thanks,
Willem
From: Willem de Bruijn
Quoted 41 lines
Sent: 26 April 2019 16:11
Quoted 23 lines · Willem de Bruijn
Quoted 21 lines · David Laight
From: Willem de Bruijn
Quoted 1 line
Sent: 25 April 2019 14:57
...
Quoted 12 lines
Quoted 11 lines
I've just done a bit of software archaeology.
Prior to 2.6.14-rc3 the send code ignored
sll_halen, it was only set by the receive code. So it is not surprising that old application code leaves it as zero.The old receive code also always set
msg_namelen= sizeof (structsockaddr_ll). The receive code now sets:
msg_namelen=offsetof(struct sockaddr_ll, sll_addr)+saddr->sll_halen;
For ethernet this changes themsg_namelenfrom 20 to 18.
A side effect (no one has noticed for years) is that you can't send a reply by passing back the received address buffer.Quoted 2 lines
Great find, thanks. I hadn't thought of going back that far, but clearly should in these legacy caller questions..
Fortunately I didn't have to find the pre-git sources :-)
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Looking at it all again how about:
char *addr = NULL; ... err = -EINVAL; if (msg->msg_namelen < offsetof(struct sockaddr_ll, sll_addr)) goto out; proto = saddr->sll_protocol; dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); if (dev && sock->type == SOCK_DGRAM) { if (msg->msg_namelen < dev->addr_len + offsetof(struct
sockaddr_ll,sll_addr))Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
goto out_unlock; addr = saddr->sll_addr; }
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Yes, given the above, this looks great to me.
Coming back to this. Both the above and two separate send/recv fixes seem fine to me. Do you have a preference either way? And do you want to send the fix(es) or should I?
I'll let you do it - save me working out how to get valid patches off my Linux systems and into outlook :-)
If you are going to do the recv fix the send one can keep the check against the full struct sockaddr_ll.
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Willem de Bruijn
maintainerQuoted 49 lines · David Laight
From: Willem de Bruijn
Quoted 41 lines
Sent: 26 April 2019 16:11
Quoted 23 lines · Willem de Bruijn
Quoted 21 lines · David Laight
From: Willem de Bruijn
Quoted 1 line
Sent: 25 April 2019 14:57
...
Quoted 12 lines
Quoted 11 lines
I've just done a bit of software archaeology.
Prior to 2.6.14-rc3 the send code ignored
sll_halen, it was only set by the receive code. So it is not surprising that old application code leaves it as zero.The old receive code also always set
msg_namelen= sizeof (structsockaddr_ll). The receive code now sets:
msg_namelen=offsetof(struct sockaddr_ll, sll_addr)+saddr->sll_halen;
For ethernet this changes themsg_namelenfrom 20 to 18.
A side effect (no one has noticed for years) is that you can't send a reply by passing back the received address buffer.Quoted 2 lines
Great find, thanks. I hadn't thought of going back that far, but clearly should in these legacy caller questions..
Fortunately I didn't have to find the pre-git sources :-)
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Looking at it all again how about:
char *addr = NULL; ... err = -EINVAL; if (msg->msg_namelen < offsetof(struct sockaddr_ll, sll_addr)) goto out; proto = saddr->sll_protocol; dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); if (dev && sock->type == SOCK_DGRAM) { if (msg->msg_namelen < dev->addr_len + offsetof(struct
sockaddr_ll,sll_addr))Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
goto out_unlock; addr = saddr->sll_addr; }Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Yes, given the above, this looks great to me.
Coming back to this. Both the above and two separate send/recv fixes seem fine to me. Do you have a preference either way? And do you want to send the fix(es) or should I?
Quoted 5 lines
I'll let you do it - save me working out how to get valid patches off my Linux systems and into outlook :-)
If you are going to do the recv fix the send one can keep the check against the full struct
sockaddr_ll.
It took a bit longer than expected, sorry. In the rx one, I went with a branch in the relatively unlikely msg->msg_name branch rather than an unconditional zero in the packet_rcv hot path.
http://patchwork.ozlabs.org/patch/1091764/
http://patchwork.ozlabs.org/patch/1091765/