diff mbox

l2_packet: Fix valgrind uninitialised byte(s) error messages

Message ID 1423188434-5830-1-git-send-email-masashi.honma@gmail.com
State Not Applicable
Headers show

Commit Message

Masashi Honma Feb. 6, 2015, 2:07 a.m. UTC
The valgrind-3.10.0 outputs following message on Ubuntu 14.10 64bit.

==2942== Syscall param socketcall.bind(my_addr.sa_data) points to uninitialised byte(s)
==2942==    at 0x5ED3577: bind (syscall-template.S:81)
==2942==    by 0x4AB2FE: l2_packet_init (l2_packet_linux.c:211)
==2942==    by 0x485147: wpa_supplicant_update_mac_addr (wpa_supplicant.c:3017)
==2942==    by 0x48888F: wpa_supplicant_driver_init (wpa_supplicant.c:3078)
==2942==    by 0x489A05: wpa_supplicant_init_iface (wpa_supplicant.c:4028)
==2942==    by 0x489A05: wpa_supplicant_add_iface (wpa_supplicant.c:4226)
==2942==    by 0x41DAB9: main (main.c:325)
==2942==  Address 0xfff000274 is on thread 1's stack
==2942==  in frame #1, created by l2_packet_init (l2_packet_linux.c:174)
==2942==

==5631== Syscall param socketcall.sendto(to.sa_data) points to uninitialised byte(s)
==5631==    at 0x5ED3953: __sendto_nocancel (syscall-template.S:81)
==5631==    by 0x4AB061: l2_packet_send (l2_packet_linux.c:106)
==5631==    by 0x434BBE: wpa_sm_ether_send (wpa_i.h:181)
==5631==    by 0x434BBE: wpa_eapol_key_send (wpa.c:72)
==5631==    by 0x435145: wpa_supplicant_send_2_of_4 (wpa.c:401)
==5631==    by 0x419346: wpa_supplicant_process_1_of_4 (wpa.c:516)
==5631==    by 0x43668C: wpa_sm_rx_eapol (wpa.c:1958)
==5631==    by 0x48E6A4: wpa_supplicant_event_assoc (events.c:2046)
==5631==    by 0x48E6A4: wpa_supplicant_event (events.c:3039)
==5631==    by 0x4A4B59: mlme_event_assoc (driver_nl80211_event.c:260)
==5631==    by 0x4A6AF5: do_process_drv_event (driver_nl80211_event.c:1751)
==5631==    by 0x4A6AF5: process_global_event (driver_nl80211_event.c:1878)
==5631==    by 0x53834CE: nl_recvmsgs_report (in /lib/x86_64-linux-gnu/libnl-3.so.200.19.0)
==5631==    by 0x5383898: nl_recvmsgs (in /lib/x86_64-linux-gnu/libnl-3.so.200.19.0)
==5631==    by 0x494297: wpa_driver_nl80211_event_receive (driver_nl80211.c:1313)
==5631==  Address 0xffefff384 is on thread 1's stack
==5631==  in frame #1, created by l2_packet_send (l2_packet_linux.c:89)

This does not occur on Ubuntu 14.10 32bit. So this looks padding problem.
The size of struct sockaddr_ll is 20 bytes. This value is dividable by 4 but not
8. This patch replace the struct by struct sockaddr_storage which is designed by
RFC 2553 to cover all types of sockaddr and have enough padding for 64bit.

Signed-off-by: Masashi Honma <masashi.honma@gmail.com>
---
 src/l2_packet/l2_packet_linux.c | 35 ++++++++++++++++++++---------------
 1 file changed, 20 insertions(+), 15 deletions(-)

Comments

Jouni Malinen Feb. 7, 2015, 11:41 a.m. UTC | #1
On Fri, Feb 06, 2015 at 11:07:14AM +0900, Masashi Honma wrote:
> The valgrind-3.10.0 outputs following message on Ubuntu 14.10 64bit.
> 
> ==2942== Syscall param socketcall.bind(my_addr.sa_data) points to uninitialised byte(s)
> ==2942==    at 0x5ED3577: bind (syscall-template.S:81)
> ==2942==    by 0x4AB2FE: l2_packet_init (l2_packet_linux.c:211)

This looks very strange..

> This does not occur on Ubuntu 14.10 32bit. So this looks padding problem.
> The size of struct sockaddr_ll is 20 bytes. This value is dividable by 4 but not
> 8. This patch replace the struct by struct sockaddr_storage which is designed by
> RFC 2553 to cover all types of sockaddr and have enough padding for 64bit.

I was able to reproduce this on Ubuntu 14.10 64-bit, but don't see it on
Ubuntu 14.04 64-bit which seems to be using the same version of
valgrind. gcc version is different, though.

It looks like adding just two bytes to the sockaddr_ll buffer is enough
to make valgrind not complain. I'm not sure how padding could really
cause this, though, taken into account how valgrind code for this is
implemented in pre_mem_read_sockaddr(). That implementation is not aware
of sockaddr_ll (maybe it would be a good idea to make it aware of
that..), but it seems to be checking the area following sa_family (i.e.,
sll_family in sockaddr_ll) in a way that should not go beyond the
20-byte buffer regardless of how the fields are padded. There is a note
there to point out possibility of false positives due to padding bytes,
but that would not really be applicable here since the l2_packet_linux.c
implementation clear the full buffer with memset (and well, there is not
really any padding octets in sockaddr_ll, i.e., all those 20 bytes are
within the real data fields).

> diff --git a/src/l2_packet/l2_packet_linux.c b/src/l2_packet/l2_packet_linux.c
> @@ -87,7 +87,10 @@ int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
>  int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
>  		   const u8 *buf, size_t len)
>  {
> +	struct sockaddr_storage storage;
> +	struct sockaddr_ll *ll;

I'm not completely sure what is triggering the issue, but the code here
in l2_packet_linux.c looks just fine as-is and it would be unfortunate
if this type of workarounds are needed just to make valgrind happy. I'd
rather figure out what is the real reason behind this bogus warning and
fix that rather than change l2_packet_linux.c unless someone can point a
clear bug there.
Jouni Malinen Feb. 7, 2015, 2:58 p.m. UTC | #2
On Sat, Feb 07, 2015 at 01:41:34PM +0200, Jouni Malinen wrote:
> It looks like adding just two bytes to the sockaddr_ll buffer is enough
> to make valgrind not complain. I'm not sure how padding could really
> cause this, though, taken into account how valgrind code for this is
> implemented in pre_mem_read_sockaddr(). That implementation is not aware
> of sockaddr_ll (maybe it would be a good idea to make it aware of
> that..), but it seems to be checking the area following sa_family (i.e.,
> sll_family in sockaddr_ll) in a way that should not go beyond the
> 20-byte buffer regardless of how the fields are padded.

Well.. I was obviously looking at the trunk version of Valgrind rather
than 3.10.0 that is used in Ubuntu 14.10. This was indeed broken and
fixed after that release:
https://bugs.kde.org/show_bug.cgi?id=342221

I confirmed that the issue does not show up with the current Valgrind
trunk snapshot. As such, I'm dropping this l2_packet patch since this
was caused by a Valgrind bug that has already been fixed (but not yet
included in a formal release).
Masashi Honma Feb. 8, 2015, 12:41 a.m. UTC | #3
2015-02-07 23:58 GMT+09:00 Jouni Malinen <j@w1.fi>:

> On Sat, Feb 07, 2015 at 01:41:34PM +0200, Jouni Malinen wrote:
> > It looks like adding just two bytes to the sockaddr_ll buffer is enough
> > to make valgrind not complain. I'm not sure how padding could really
> > cause this, though, taken into account how valgrind code for this is
> > implemented in pre_mem_read_sockaddr(). That implementation is not aware
> > of sockaddr_ll (maybe it would be a good idea to make it aware of
> > that..), but it seems to be checking the area following sa_family (i.e.,
> > sll_family in sockaddr_ll) in a way that should not go beyond the
> > 20-byte buffer regardless of how the fields are padded.
>
> Well.. I was obviously looking at the trunk version of Valgrind rather
> than 3.10.0 that is used in Ubuntu 14.10. This was indeed broken and
> fixed after that release:
> https://bugs.kde.org/show_bug.cgi?id=342221
>
> I confirmed that the issue does not show up with the current Valgrind
> trunk snapshot. As such, I'm dropping this l2_packet patch since this
> was caused by a Valgrind bug that has already been fixed (but not yet
> included in a formal release).
>

Thank you and sorry for false report.
diff mbox

Patch

diff --git a/src/l2_packet/l2_packet_linux.c b/src/l2_packet/l2_packet_linux.c
index 68b2008..bef08e2 100644
--- a/src/l2_packet/l2_packet_linux.c
+++ b/src/l2_packet/l2_packet_linux.c
@@ -87,7 +87,10 @@  int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
 int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
 		   const u8 *buf, size_t len)
 {
+	struct sockaddr_storage storage;
+	struct sockaddr_ll *ll;
 	int ret;
+
 	if (l2 == NULL)
 		return -1;
 	if (l2->l2_hdr) {
@@ -96,15 +99,15 @@  int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
 			wpa_printf(MSG_ERROR, "l2_packet_send - send: %s",
 				   strerror(errno));
 	} else {
-		struct sockaddr_ll ll;
-		os_memset(&ll, 0, sizeof(ll));
-		ll.sll_family = AF_PACKET;
-		ll.sll_ifindex = l2->ifindex;
-		ll.sll_protocol = htons(proto);
-		ll.sll_halen = ETH_ALEN;
-		os_memcpy(ll.sll_addr, dst_addr, ETH_ALEN);
-		ret = sendto(l2->fd, buf, len, 0, (struct sockaddr *) &ll,
-			     sizeof(ll));
+		os_memset(&storage, 0, sizeof(storage));
+		ll = (struct sockaddr_ll *) &storage;
+		ll->sll_family = AF_PACKET;
+		ll->sll_ifindex = l2->ifindex;
+		ll->sll_protocol = htons(proto);
+		ll->sll_halen = ETH_ALEN;
+		os_memcpy(ll->sll_addr, dst_addr, ETH_ALEN);
+		ret = sendto(l2->fd, buf, len, 0, (struct sockaddr *) ll,
+			     sizeof(*ll));
 		if (ret < 0) {
 			wpa_printf(MSG_ERROR, "l2_packet_send - sendto: %s",
 				   strerror(errno));
@@ -174,7 +177,8 @@  struct l2_packet_data * l2_packet_init(
 {
 	struct l2_packet_data *l2;
 	struct ifreq ifr;
-	struct sockaddr_ll ll;
+	struct sockaddr_storage storage;
+	struct sockaddr_ll *ll;
 
 	l2 = os_zalloc(sizeof(struct l2_packet_data));
 	if (l2 == NULL)
@@ -204,11 +208,12 @@  struct l2_packet_data * l2_packet_init(
 	}
 	l2->ifindex = ifr.ifr_ifindex;
 
-	os_memset(&ll, 0, sizeof(ll));
-	ll.sll_family = PF_PACKET;
-	ll.sll_ifindex = ifr.ifr_ifindex;
-	ll.sll_protocol = htons(protocol);
-	if (bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+	os_memset(&storage, 0, sizeof(storage));
+	ll = (struct sockaddr_ll *) &storage;
+	ll->sll_family = PF_PACKET;
+	ll->sll_ifindex = ifr.ifr_ifindex;
+	ll->sll_protocol = htons(protocol);
+	if (bind(l2->fd, (struct sockaddr *) ll, sizeof(*ll)) < 0) {
 		wpa_printf(MSG_ERROR, "%s: bind[PF_PACKET]: %s",
 			   __func__, strerror(errno));
 		close(l2->fd);