Parcourir la source

qcacld-3.0: Add input validation for SENDACTIONFRAME

This is a qcacld-2.0 to qcacld-3.0 propagation.

Add input validation for SENDACTIONFRAME driver command.

Change-Id: I3d1bf424e5e0f9a3b6f4662dd12a3a7314c7eace
CRs-Fixed: 1001449
Srinivas Girigowda il y a 8 ans
Parent
commit
1efc80ea46
1 fichiers modifiés avec 41 ajouts et 20 suppressions
  1. 41 20
      core/hdd/src/wlan_hdd_ioctl.c

+ 41 - 20
core/hdd/src/wlan_hdd_ioctl.c

@@ -1071,16 +1071,15 @@ static int hdd_parse_reassoc(hdd_adapter_t *adapter, const char *command)
 static int
 hdd_sendactionframe(hdd_adapter_t *adapter, const uint8_t *bssid,
 		    const uint8_t channel, const uint8_t dwell_time,
-		    const uint8_t payload_len, const uint8_t *payload)
+		    const int payload_len, const uint8_t *payload)
 {
 	struct ieee80211_channel chan;
-	uint8_t frame_len;
+	int frame_len, ret = 0;
 	uint8_t *frame;
 	struct ieee80211_hdr_3addr *hdr;
 	u64 cookie;
 	hdd_station_ctx_t *pHddStaCtx;
 	hdd_context_t *hdd_ctx;
-	int ret = 0;
 	tpSirMacVendorSpecificFrameHdr pVendorSpecific =
 		(tpSirMacVendorSpecificFrameHdr) payload;
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
@@ -1259,29 +1258,42 @@ hdd_parse_sendactionframe_v1(hdd_adapter_t *adapter, const char *command)
  * Return: 0 for success non-zero for failure
  */
 static int
-hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter, const char *command)
+hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter,
+			     const char *command, int total_len)
 {
 	struct android_wifi_af_params *params;
 	tSirMacAddr bssid;
 	int ret;
 
-	/* params are large so keep off the stack */
-	params = kmalloc(sizeof(*params), GFP_KERNEL);
-	if (!params)
-		return -ENOMEM;
-
 	/* The params are located after "SENDACTIONFRAME " */
-	memcpy(params, command + 16, sizeof(*params));
+	total_len -= 16;
+	params = (struct android_wifi_af_params *)(command + 16);
+
+	if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE ||
+		(params->len > total_len)) {
+		hdd_err("Invalid payload length: %d", params->len);
+		return -EINVAL;
+	}
 
-	if (!mac_pton(params->bssid, (u8 *) &bssid)) {
+	if (!mac_pton(params->bssid, (u8 *)&bssid)) {
 		hdd_err("MAC address parsing failed");
-		ret = -EINVAL;
-	} else {
-		ret = hdd_sendactionframe(adapter, bssid, params->channel,
-					  params->dwell_time, params->len,
-					  params->data);
+		return -EINVAL;
+	}
+
+	if (params->channel < 0 ||
+	    params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
+		hdd_err("Invalid channel: %d", params->channel);
+		return -EINVAL;
+	}
+
+	if (params->dwell_time < 0) {
+		hdd_err("Invalid dwell_time: %d", params->dwell_time);
+		return -EINVAL;
 	}
-	kfree(params);
+
+	ret = hdd_sendactionframe(adapter, bssid, params->channel,
+				params->dwell_time, params->len, params->data);
+
 	return ret;
 }
 
@@ -1300,7 +1312,8 @@ hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter, const char *command)
  * Return: 0 for success non-zero for failure
  */
 static int
-hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command)
+hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command,
+			  int total_len)
 {
 	int ret;
 
@@ -1317,11 +1330,18 @@ hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command)
 	 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
 	 *           111111111122222222223333
 	 * 0123456789012345678901234567890123
+	 * For both the commands, a valid command must have atleast
+	 * first 34 length of data.
 	 */
+	if (total_len < 34) {
+		hdd_err("Invalid command (total_len=%d)", total_len);
+		return -EINVAL;
+	}
+
 	if (command[33]) {
 		ret = hdd_parse_sendactionframe_v1(adapter, command);
 	} else {
-		ret = hdd_parse_sendactionframe_v2(adapter, command);
+		ret = hdd_parse_sendactionframe_v2(adapter, command, total_len);
 	}
 
 	return ret;
@@ -3708,7 +3728,8 @@ static int drv_cmd_send_action_frame(hdd_adapter_t *adapter,
 				     uint8_t command_len,
 				     hdd_priv_data_t *priv_data)
 {
-	return hdd_parse_sendactionframe(adapter, command);
+	return hdd_parse_sendactionframe(adapter, command,
+					 priv_data->total_len);
 }
 
 static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter,