Takashi Iwai 958df5
From bb43e5718d8f1b46e7a77e7b39be3c691f293050 Mon Sep 17 00:00:00 2001
Takashi Iwai 958df5
From: "Gustavo A. R. Silva" <gustavoars@kernel.org>
Takashi Iwai 958df5
Date: Wed, 14 Apr 2021 18:45:15 -0500
Takashi Iwai 958df5
Subject: [PATCH] wl3501_cs: Fix out-of-bounds warnings in wl3501_mgmt_join
Takashi Iwai 958df5
Git-commit: bb43e5718d8f1b46e7a77e7b39be3c691f293050
Takashi Iwai 958df5
Patch-mainline: v5.13-rc1
Takashi Iwai 958df5
References: git-fixes
Takashi Iwai 958df5
Takashi Iwai 958df5
Fix the following out-of-bounds warnings by adding a new structure
Takashi Iwai 958df5
wl3501_req instead of duplicating the same members in structure
Takashi Iwai 958df5
wl3501_join_req and wl3501_scan_confirm:
Takashi Iwai 958df5
Takashi Iwai 958df5
arch/x86/include/asm/string_32.h:182:25: warning: '__builtin_memcpy' offset [39, 108] from the object at 'sig' is out of the bounds of referenced subobject 'beacon_period' with type 'short unsigned int' at offset 36 [-Warray-bounds]
Takashi Iwai 958df5
arch/x86/include/asm/string_32.h:182:25: warning: '__builtin_memcpy' offset [25, 95] from the object at 'sig' is out of the bounds of referenced subobject 'beacon_period' with type 'short unsigned int' at offset 22 [-Warray-bounds]
Takashi Iwai 958df5
Takashi Iwai 958df5
Refactor the code, accordingly:
Takashi Iwai 958df5
Takashi Iwai 958df5
$ pahole -C wl3501_req drivers/net/wireless/wl3501_cs.o
Takashi Iwai 958df5
struct wl3501_req {
Takashi Iwai 958df5
        u16                        beacon_period;        /*     0     2 */
Takashi Iwai 958df5
        u16                        dtim_period;          /*     2     2 */
Takashi Iwai 958df5
        u16                        cap_info;             /*     4     2 */
Takashi Iwai 958df5
        u8                         bss_type;             /*     6     1 */
Takashi Iwai 958df5
        u8                         bssid[6];             /*     7     6 */
Takashi Iwai 958df5
        struct iw_mgmt_essid_pset  ssid;                 /*    13    34 */
Takashi Iwai 958df5
        struct iw_mgmt_ds_pset     ds_pset;              /*    47     3 */
Takashi Iwai 958df5
        struct iw_mgmt_cf_pset     cf_pset;              /*    50     8 */
Takashi Iwai 958df5
        struct iw_mgmt_ibss_pset   ibss_pset;            /*    58     4 */
Takashi Iwai 958df5
        struct iw_mgmt_data_rset   bss_basic_rset;       /*    62    10 */
Takashi Iwai 958df5
Takashi Iwai 958df5
        /* size: 72, cachelines: 2, members: 10 */
Takashi Iwai 958df5
        /* last cacheline: 8 bytes */
Takashi Iwai 958df5
};
Takashi Iwai 958df5
Takashi Iwai 958df5
$ pahole -C wl3501_join_req drivers/net/wireless/wl3501_cs.o
Takashi Iwai 958df5
struct wl3501_join_req {
Takashi Iwai 958df5
        u16                        next_blk;             /*     0     2 */
Takashi Iwai 958df5
        u8                         sig_id;               /*     2     1 */
Takashi Iwai 958df5
        u8                         reserved;             /*     3     1 */
Takashi Iwai 958df5
        struct iw_mgmt_data_rset   operational_rset;     /*     4    10 */
Takashi Iwai 958df5
        u16                        reserved2;            /*    14     2 */
Takashi Iwai 958df5
        u16                        timeout;              /*    16     2 */
Takashi Iwai 958df5
        u16                        probe_delay;          /*    18     2 */
Takashi Iwai 958df5
        u8                         timestamp[8];         /*    20     8 */
Takashi Iwai 958df5
        u8                         local_time[8];        /*    28     8 */
Takashi Iwai 958df5
        struct wl3501_req          req;                  /*    36    72 */
Takashi Iwai 958df5
Takashi Iwai 958df5
        /* size: 108, cachelines: 2, members: 10 */
Takashi Iwai 958df5
        /* last cacheline: 44 bytes */
Takashi Iwai 958df5
};
Takashi Iwai 958df5
Takashi Iwai 958df5
$ pahole -C wl3501_scan_confirm drivers/net/wireless/wl3501_cs.o
Takashi Iwai 958df5
struct wl3501_scan_confirm {
Takashi Iwai 958df5
        u16                        next_blk;             /*     0     2 */
Takashi Iwai 958df5
        u8                         sig_id;               /*     2     1 */
Takashi Iwai 958df5
        u8                         reserved;             /*     3     1 */
Takashi Iwai 958df5
        u16                        status;               /*     4     2 */
Takashi Iwai 958df5
        char                       timestamp[8];         /*     6     8 */
Takashi Iwai 958df5
        char                       localtime[8];         /*    14     8 */
Takashi Iwai 958df5
        struct wl3501_req          req;                  /*    22    72 */
Takashi Iwai 958df5
        /* --- cacheline 1 boundary (64 bytes) was 30 bytes ago --- */
Takashi Iwai 958df5
        u8                         rssi;                 /*    94     1 */
Takashi Iwai 958df5
Takashi Iwai 958df5
        /* size: 96, cachelines: 2, members: 8 */
Takashi Iwai 958df5
        /* padding: 1 */
Takashi Iwai 958df5
        /* last cacheline: 32 bytes */
Takashi Iwai 958df5
};
Takashi Iwai 958df5
Takashi Iwai 958df5
The problem is that the original code is trying to copy data into a
Takashi Iwai 958df5
bunch of struct members adjacent to each other in a single call to
Takashi Iwai 958df5
memcpy(). Now that a new struct wl3501_req enclosing all those adjacent
Takashi Iwai 958df5
members is introduced, memcpy() doesn't overrun the length of
Takashi Iwai 958df5
&sig.beacon_period and &this->bss_set[i].beacon_period, because the
Takashi Iwai 958df5
address of the new struct object _req_ is used as the destination,
Takashi Iwai 958df5
instead.
Takashi Iwai 958df5
Takashi Iwai 958df5
This helps with the ongoing efforts to globally enable -Warray-bounds
Takashi Iwai 958df5
and get us closer to being able to tighten the FORTIFY_SOURCE routines
Takashi Iwai 958df5
on memcpy().
Takashi Iwai 958df5
Takashi Iwai 958df5
Link: https://github.com/KSPP/linux/issues/109
Takashi Iwai 958df5
Reported-by: kernel test robot <lkp@intel.com>
Takashi Iwai 958df5
Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
Takashi Iwai 958df5
Reviewed-by: Kees Cook <keescook@chromium.org>
Takashi Iwai 958df5
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Takashi Iwai 958df5
Link: https://lore.kernel.org/r/1fbaf516da763b50edac47d792a9145aa4482e29.1618442265.git.gustavoars@kernel.org
Takashi Iwai 958df5
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai 958df5
Takashi Iwai 958df5
---
Takashi Iwai 958df5
 drivers/net/wireless/wl3501.h    | 35 +++++++++++--------------
Takashi Iwai 958df5
 drivers/net/wireless/wl3501_cs.c | 44 +++++++++++++++++---------------
Takashi Iwai 958df5
 2 files changed, 38 insertions(+), 41 deletions(-)
Takashi Iwai 958df5
Takashi Iwai 958df5
diff --git a/drivers/net/wireless/wl3501.h b/drivers/net/wireless/wl3501.h
Takashi Iwai 958df5
index 8c5480bec104..91f276dd22a1 100644
Takashi Iwai 958df5
--- a/drivers/net/wireless/wl3501.h
Takashi Iwai 958df5
+++ b/drivers/net/wireless/wl3501.h
Takashi Iwai 958df5
@@ -379,16 +379,7 @@ struct wl3501_get_confirm {
Takashi Iwai 958df5
 	u8	mib_value[100];
Takashi Iwai 958df5
 };
Takashi Iwai 958df5
 
Takashi Iwai 958df5
-struct wl3501_join_req {
Takashi Iwai 958df5
-	u16			    next_blk;
Takashi Iwai 958df5
-	u8			    sig_id;
Takashi Iwai 958df5
-	u8			    reserved;
Takashi Iwai 958df5
-	struct iw_mgmt_data_rset    operational_rset;
Takashi Iwai 958df5
-	u16			    reserved2;
Takashi Iwai 958df5
-	u16			    timeout;
Takashi Iwai 958df5
-	u16			    probe_delay;
Takashi Iwai 958df5
-	u8			    timestamp[8];
Takashi Iwai 958df5
-	u8			    local_time[8];
Takashi Iwai 958df5
+struct wl3501_req {
Takashi Iwai 958df5
 	u16			    beacon_period;
Takashi Iwai 958df5
 	u16			    dtim_period;
Takashi Iwai 958df5
 	u16			    cap_info;
Takashi Iwai 958df5
@@ -401,6 +392,19 @@ struct wl3501_join_req {
Takashi Iwai 958df5
 	struct iw_mgmt_data_rset    bss_basic_rset;
Takashi Iwai 958df5
 };
Takashi Iwai 958df5
 
Takashi Iwai 958df5
+struct wl3501_join_req {
Takashi Iwai 958df5
+	u16			    next_blk;
Takashi Iwai 958df5
+	u8			    sig_id;
Takashi Iwai 958df5
+	u8			    reserved;
Takashi Iwai 958df5
+	struct iw_mgmt_data_rset    operational_rset;
Takashi Iwai 958df5
+	u16			    reserved2;
Takashi Iwai 958df5
+	u16			    timeout;
Takashi Iwai 958df5
+	u16			    probe_delay;
Takashi Iwai 958df5
+	u8			    timestamp[8];
Takashi Iwai 958df5
+	u8			    local_time[8];
Takashi Iwai 958df5
+	struct wl3501_req	    req;
Takashi Iwai 958df5
+};
Takashi Iwai 958df5
+
Takashi Iwai 958df5
 struct wl3501_join_confirm {
Takashi Iwai 958df5
 	u16	next_blk;
Takashi Iwai 958df5
 	u8	sig_id;
Takashi Iwai 958df5
@@ -443,16 +447,7 @@ struct wl3501_scan_confirm {
Takashi Iwai 958df5
 	u16			    status;
Takashi Iwai 958df5
 	char			    timestamp[8];
Takashi Iwai 958df5
 	char			    localtime[8];
Takashi Iwai 958df5
-	u16			    beacon_period;
Takashi Iwai 958df5
-	u16			    dtim_period;
Takashi Iwai 958df5
-	u16			    cap_info;
Takashi Iwai 958df5
-	u8			    bss_type;
Takashi Iwai 958df5
-	u8			    bssid[ETH_ALEN];
Takashi Iwai 958df5
-	struct iw_mgmt_essid_pset   ssid;
Takashi Iwai 958df5
-	struct iw_mgmt_ds_pset	    ds_pset;
Takashi Iwai 958df5
-	struct iw_mgmt_cf_pset	    cf_pset;
Takashi Iwai 958df5
-	struct iw_mgmt_ibss_pset    ibss_pset;
Takashi Iwai 958df5
-	struct iw_mgmt_data_rset    bss_basic_rset;
Takashi Iwai 958df5
+	struct wl3501_req	    req;
Takashi Iwai 958df5
 	u8			    rssi;
Takashi Iwai 958df5
 };
Takashi Iwai 958df5
 
Takashi Iwai 958df5
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
Takashi Iwai 958df5
index 70307308635f..672f5d5f3f2c 100644
Takashi Iwai 958df5
--- a/drivers/net/wireless/wl3501_cs.c
Takashi Iwai 958df5
+++ b/drivers/net/wireless/wl3501_cs.c
Takashi Iwai 958df5
@@ -590,7 +590,7 @@ static int wl3501_mgmt_join(struct wl3501_card *this, u16 stas)
Takashi Iwai 958df5
 	struct wl3501_join_req sig = {
Takashi Iwai 958df5
 		.sig_id		  = WL3501_SIG_JOIN_REQ,
Takashi Iwai 958df5
 		.timeout	  = 10,
Takashi Iwai 958df5
-		.ds_pset = {
Takashi Iwai 958df5
+		.req.ds_pset = {
Takashi Iwai 958df5
 			.el = {
Takashi Iwai 958df5
 				.id  = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET,
Takashi Iwai 958df5
 				.len = 1,
Takashi Iwai 958df5
@@ -599,7 +599,7 @@ static int wl3501_mgmt_join(struct wl3501_card *this, u16 stas)
Takashi Iwai 958df5
 		},
Takashi Iwai 958df5
 	};
Takashi Iwai 958df5
 
Takashi Iwai 958df5
-	memcpy(&sig.beacon_period, &this->bss_set[stas].beacon_period, 72);
Takashi Iwai 958df5
+	memcpy(&sig.req, &this->bss_set[stas].req, sizeof(sig.req));
Takashi Iwai 958df5
 	return wl3501_esbq_exec(this, &sig, sizeof(sig));
Takashi Iwai 958df5
 }
Takashi Iwai 958df5
 
Takashi Iwai 958df5
@@ -667,35 +667,37 @@ static void wl3501_mgmt_scan_confirm(struct wl3501_card *this, u16 addr)
Takashi Iwai 958df5
 	if (sig.status == WL3501_STATUS_SUCCESS) {
Takashi Iwai 958df5
 		pr_debug("success");
Takashi Iwai 958df5
 		if ((this->net_type == IW_MODE_INFRA &&
Takashi Iwai 958df5
-		     (sig.cap_info & WL3501_MGMT_CAPABILITY_ESS)) ||
Takashi Iwai 958df5
+		     (sig.req.cap_info & WL3501_MGMT_CAPABILITY_ESS)) ||
Takashi Iwai 958df5
 		    (this->net_type == IW_MODE_ADHOC &&
Takashi Iwai 958df5
-		     (sig.cap_info & WL3501_MGMT_CAPABILITY_IBSS)) ||
Takashi Iwai 958df5
+		     (sig.req.cap_info & WL3501_MGMT_CAPABILITY_IBSS)) ||
Takashi Iwai 958df5
 		    this->net_type == IW_MODE_AUTO) {
Takashi Iwai 958df5
 			if (!this->essid.el.len)
Takashi Iwai 958df5
 				matchflag = 1;
Takashi Iwai 958df5
 			else if (this->essid.el.len == 3 &&
Takashi Iwai 958df5
 				 !memcmp(this->essid.essid, "ANY", 3))
Takashi Iwai 958df5
 				matchflag = 1;
Takashi Iwai 958df5
-			else if (this->essid.el.len != sig.ssid.el.len)
Takashi Iwai 958df5
+			else if (this->essid.el.len != sig.req.ssid.el.len)
Takashi Iwai 958df5
 				matchflag = 0;
Takashi Iwai 958df5
-			else if (memcmp(this->essid.essid, sig.ssid.essid,
Takashi Iwai 958df5
+			else if (memcmp(this->essid.essid, sig.req.ssid.essid,
Takashi Iwai 958df5
 					this->essid.el.len))
Takashi Iwai 958df5
 				matchflag = 0;
Takashi Iwai 958df5
 			else
Takashi Iwai 958df5
 				matchflag = 1;
Takashi Iwai 958df5
 			if (matchflag) {
Takashi Iwai 958df5
 				for (i = 0; i < this->bss_cnt; i++) {
Takashi Iwai 958df5
-					if (ether_addr_equal_unaligned(this->bss_set[i].bssid, sig.bssid)) {
Takashi Iwai 958df5
+					if (ether_addr_equal_unaligned(this->bss_set[i].req.bssid,
Takashi Iwai 958df5
+								       sig.req.bssid)) {
Takashi Iwai 958df5
 						matchflag = 0;
Takashi Iwai 958df5
 						break;
Takashi Iwai 958df5
 					}
Takashi Iwai 958df5
 				}
Takashi Iwai 958df5
 			}
Takashi Iwai 958df5
 			if (matchflag && (i < 20)) {
Takashi Iwai 958df5
-				memcpy(&this->bss_set[i].beacon_period,
Takashi Iwai 958df5
-				       &sig.beacon_period, 73);
Takashi Iwai 958df5
+				memcpy(&this->bss_set[i].req,
Takashi Iwai 958df5
+				       &sig.req, sizeof(sig.req));
Takashi Iwai 958df5
 				this->bss_cnt++;
Takashi Iwai 958df5
 				this->rssi = sig.rssi;
Takashi Iwai 958df5
+				this->bss_set[i].rssi = sig.rssi;
Takashi Iwai 958df5
 			}
Takashi Iwai 958df5
 		}
Takashi Iwai 958df5
 	} else if (sig.status == WL3501_STATUS_TIMEOUT) {
Takashi Iwai 958df5
@@ -887,19 +889,19 @@ static void wl3501_mgmt_join_confirm(struct net_device *dev, u16 addr)
Takashi Iwai 958df5
 			if (this->join_sta_bss < this->bss_cnt) {
Takashi Iwai 958df5
 				const int i = this->join_sta_bss;
Takashi Iwai 958df5
 				memcpy(this->bssid,
Takashi Iwai 958df5
-				       this->bss_set[i].bssid, ETH_ALEN);
Takashi Iwai 958df5
-				this->chan = this->bss_set[i].ds_pset.chan;
Takashi Iwai 958df5
+				       this->bss_set[i].req.bssid, ETH_ALEN);
Takashi Iwai 958df5
+				this->chan = this->bss_set[i].req.ds_pset.chan;
Takashi Iwai 958df5
 				iw_copy_mgmt_info_element(&this->keep_essid.el,
Takashi Iwai 958df5
-						     &this->bss_set[i].ssid.el);
Takashi Iwai 958df5
+						     &this->bss_set[i].req.ssid.el);
Takashi Iwai 958df5
 				wl3501_mgmt_auth(this);
Takashi Iwai 958df5
 			}
Takashi Iwai 958df5
 		} else {
Takashi Iwai 958df5
 			const int i = this->join_sta_bss;
Takashi Iwai 958df5
 
Takashi Iwai 958df5
-			memcpy(&this->bssid, &this->bss_set[i].bssid, ETH_ALEN);
Takashi Iwai 958df5
-			this->chan = this->bss_set[i].ds_pset.chan;
Takashi Iwai 958df5
+			memcpy(&this->bssid, &this->bss_set[i].req.bssid, ETH_ALEN);
Takashi Iwai 958df5
+			this->chan = this->bss_set[i].req.ds_pset.chan;
Takashi Iwai 958df5
 			iw_copy_mgmt_info_element(&this->keep_essid.el,
Takashi Iwai 958df5
-						  &this->bss_set[i].ssid.el);
Takashi Iwai 958df5
+						  &this->bss_set[i].req.ssid.el);
Takashi Iwai 958df5
 			wl3501_online(dev);
Takashi Iwai 958df5
 		}
Takashi Iwai 958df5
 	} else {
Takashi Iwai 958df5
@@ -1573,30 +1575,30 @@ static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info,
Takashi Iwai 958df5
 	for (i = 0; i < this->bss_cnt; ++i) {
Takashi Iwai 958df5
 		iwe.cmd			= SIOCGIWAP;
Takashi Iwai 958df5
 		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
Takashi Iwai 958df5
-		memcpy(iwe.u.ap_addr.sa_data, this->bss_set[i].bssid, ETH_ALEN);
Takashi Iwai 958df5
+		memcpy(iwe.u.ap_addr.sa_data, this->bss_set[i].req.bssid, ETH_ALEN);
Takashi Iwai 958df5
 		current_ev = iwe_stream_add_event(info, current_ev,
Takashi Iwai 958df5
 						  extra + IW_SCAN_MAX_DATA,
Takashi Iwai 958df5
 						  &iwe, IW_EV_ADDR_LEN);
Takashi Iwai 958df5
 		iwe.cmd		  = SIOCGIWESSID;
Takashi Iwai 958df5
 		iwe.u.data.flags  = 1;
Takashi Iwai 958df5
-		iwe.u.data.length = this->bss_set[i].ssid.el.len;
Takashi Iwai 958df5
+		iwe.u.data.length = this->bss_set[i].req.ssid.el.len;
Takashi Iwai 958df5
 		current_ev = iwe_stream_add_point(info, current_ev,
Takashi Iwai 958df5
 						  extra + IW_SCAN_MAX_DATA,
Takashi Iwai 958df5
 						  &iwe,
Takashi Iwai 958df5
-						  this->bss_set[i].ssid.essid);
Takashi Iwai 958df5
+						  this->bss_set[i].req.ssid.essid);
Takashi Iwai 958df5
 		iwe.cmd	   = SIOCGIWMODE;
Takashi Iwai 958df5
-		iwe.u.mode = this->bss_set[i].bss_type;
Takashi Iwai 958df5
+		iwe.u.mode = this->bss_set[i].req.bss_type;
Takashi Iwai 958df5
 		current_ev = iwe_stream_add_event(info, current_ev,
Takashi Iwai 958df5
 						  extra + IW_SCAN_MAX_DATA,
Takashi Iwai 958df5
 						  &iwe, IW_EV_UINT_LEN);
Takashi Iwai 958df5
 		iwe.cmd = SIOCGIWFREQ;
Takashi Iwai 958df5
-		iwe.u.freq.m = this->bss_set[i].ds_pset.chan;
Takashi Iwai 958df5
+		iwe.u.freq.m = this->bss_set[i].req.ds_pset.chan;
Takashi Iwai 958df5
 		iwe.u.freq.e = 0;
Takashi Iwai 958df5
 		current_ev = iwe_stream_add_event(info, current_ev,
Takashi Iwai 958df5
 						  extra + IW_SCAN_MAX_DATA,
Takashi Iwai 958df5
 						  &iwe, IW_EV_FREQ_LEN);
Takashi Iwai 958df5
 		iwe.cmd = SIOCGIWENCODE;
Takashi Iwai 958df5
-		if (this->bss_set[i].cap_info & WL3501_MGMT_CAPABILITY_PRIVACY)
Takashi Iwai 958df5
+		if (this->bss_set[i].req.cap_info & WL3501_MGMT_CAPABILITY_PRIVACY)
Takashi Iwai 958df5
 			iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
Takashi Iwai 958df5
 		else
Takashi Iwai 958df5
 			iwe.u.data.flags = IW_ENCODE_DISABLED;
Takashi Iwai 958df5
-- 
Takashi Iwai 958df5
2.26.2
Takashi Iwai 958df5