Browse Source

qcacld-3.0: Avoid integer overflow in set_wifi_test_config

While processing vendor command WIFI_TEST_CONFIG_TWT_SETUP,
in respective command handler __wlan_hdd_cfg80211_set_wifi_test_config()
there is no maximum range check of INTVL_EXP and INTVL_MANTISSA attrs
which can lead to potential integer overflow.

Also there is no check whether mandatory attrs like DURATION,
INTVL_MANTISSA etc., are present. If these mandatory attrs are
not present then driver is initializing them to zeros
which can lead to divide by zero error when calculating wake interval.

To address this, return error when mandatory attributes are not
present and add maximum range check.

Change-Id: If3ac71e1263906fdd502c77103e1fff91f65e816
CRs-Fixed: 2435728
Rajeev Kumar Sirasanagandla 6 years ago
parent
commit
05f1f2dc2b
2 changed files with 61 additions and 39 deletions
  1. 57 39
      core/hdd/src/wlan_hdd_cfg80211.c
  2. 4 0
      core/hdd/src/wlan_hdd_cfg80211.h

+ 57 - 39
core/hdd/src/wlan_hdd_cfg80211.c

@@ -5315,11 +5315,11 @@ wlan_hdd_wifi_config_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1] = {
 static const struct nla_policy qca_wlan_vendor_twt_add_dialog_policy[
 		QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1] = {
 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP] = {.type = NLA_U8 },
-	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST] = {.type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST] = {.type = NLA_FLAG },
 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE] = {.type = NLA_U8 },
-	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER] = {.type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER] = {.type = NLA_FLAG },
 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE] = {.type = NLA_U8 },
-	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION] = {.type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION] = {.type = NLA_FLAG },
 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME] = {.type = NLA_U32 },
 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION] = {.type = NLA_U32 },
 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA] = {
@@ -7222,9 +7222,9 @@ __wlan_hdd_cfg80211_set_wifi_test_config(struct wiphy *wiphy,
 		     adapter->device_mode != QDF_P2P_CLIENT_MODE) ||
 		    hdd_sta_ctx->conn_info.conn_state !=
 		    eConnectionState_Associated) {
-			hdd_err("Invalid state, vdev %d mode %d state %d",
-				adapter->vdev_id, adapter->device_mode,
-				hdd_sta_ctx->conn_info.conn_state);
+			hdd_err_rl("Invalid state, vdev %d mode %d state %d",
+				   adapter->vdev_id, adapter->device_mode,
+				   hdd_sta_ctx->conn_info.conn_state);
 			goto send_err;
 		}
 
@@ -7242,63 +7242,87 @@ __wlan_hdd_cfg80211_set_wifi_test_config(struct wiphy *wiphy,
 					nla_len(twt_session),
 					qca_wlan_vendor_twt_add_dialog_policy);
 			if (rc) {
-				hdd_err("Invalid twt ATTR");
+				hdd_err_rl("Invalid twt ATTR");
 				goto send_err;
 			}
 
 			cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP;
-			if (tb2[cmd_id])
-				wake_intvl_exp = nla_get_u8(tb2[cmd_id]);
+			if (!tb2[cmd_id]) {
+				hdd_err_rl("TWT_SETUP_WAKE_INTVL_EXP is must");
+				goto send_err;
+			}
+			wake_intvl_exp = nla_get_u8(tb2[cmd_id]);
+			if (wake_intvl_exp > TWT_SETUP_WAKE_INTVL_EXP_MAX) {
+				hdd_err_rl("Invalid wake_intvl_exp %u > %u",
+					   wake_intvl_exp,
+					   TWT_SETUP_WAKE_INTVL_EXP_MAX);
+				goto send_err;
+			}
 
 			cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST;
 			if (tb2[cmd_id])
-				params.flag_bcast = nla_get_u8(tb2[cmd_id]);
+				params.flag_bcast = nla_get_flag(tb2[cmd_id]);
 
 			cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE;
-			if (tb2[cmd_id])
-				params.twt_cmd = nla_get_u8(tb2[cmd_id]);
+			if (!tb2[cmd_id]) {
+				hdd_err_rl("TWT_SETUP_REQ_TYPE is must");
+				goto send_err;
+			}
+			params.twt_cmd = nla_get_u8(tb2[cmd_id]);
 
 			cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER;
 			if (tb2[cmd_id])
-				params.flag_trigger = nla_get_u8(tb2[cmd_id]);
+				params.flag_trigger = nla_get_flag(tb2[cmd_id]);
 
 			cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE;
-			if (tb2[cmd_id])
-				params.flag_flow_type = nla_get_u8(tb2[cmd_id]);
+			if (!tb2[cmd_id]) {
+				hdd_err_rl("TWT_SETUP_FLOW_TYPE is must");
+				goto send_err;
+			}
+			params.flag_flow_type = nla_get_u8(tb2[cmd_id]);
 
 			cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION;
 			if (tb2[cmd_id])
 				params.flag_protection =
-					nla_get_u8(tb2[cmd_id]);
+					nla_get_flag(tb2[cmd_id]);
 
 			cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME;
 			if (tb2[cmd_id])
 				params.sp_offset_us = nla_get_u32(tb2[cmd_id]);
 
 			cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION;
-			if (tb2[cmd_id])
-				params.wake_dura_us =
-					256 * nla_get_u32(tb2[cmd_id]);
+			if (!tb2[cmd_id]) {
+				hdd_err_rl("TWT_SETUP_WAKE_DURATION is must");
+				goto send_err;
+			}
+			params.wake_dura_us = 256 * nla_get_u32(tb2[cmd_id]);
+			if (params.wake_dura_us > TWT_SETUP_WAKE_DURATION_MAX) {
+				hdd_err_rl("Invalid wake_dura_us %u",
+					   params.wake_dura_us);
+				goto send_err;
+			}
 
 			cmd_id =
 			QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA;
-			if (tb2[cmd_id])
-				params.wake_intvl_mantis =
-					nla_get_u32(tb2[cmd_id]);
-
-			if (wake_intvl_exp) {
-				if (((sizeof(UINT_MAX) / 8) - 2) <
-				    (wake_intvl_exp - 1)) {
-					hdd_err("Invalid wake_intvl_exp %d",
-						wake_intvl_exp);
-					goto send_err;
-				}
+			if (!tb2[cmd_id]) {
+				hdd_err_rl("SETUP_WAKE_INTVL_MANTISSA is must");
+				goto send_err;
+			}
+			params.wake_intvl_mantis = nla_get_u32(tb2[cmd_id]);
+			if (params.wake_intvl_mantis >
+			    TWT_SETUP_WAKE_INTVL_MANTISSA_MAX) {
+				hdd_err_rl("Invalid wake_intvl_mantis %u",
+					   params.wake_dura_us);
+				goto send_err;
+			}
+
+			if (wake_intvl_exp && params.wake_intvl_mantis) {
 				result = 2 << (wake_intvl_exp - 1);
 				if (result >
 				    (UINT_MAX / params.wake_intvl_mantis)) {
-					hdd_err("Invalid exp %d mantissa %d",
-						wake_intvl_exp,
-						params.wake_intvl_mantis);
+					hdd_err_rl("Invalid exp %d mantissa %d",
+						   wake_intvl_exp,
+						   params.wake_intvl_mantis);
 					goto send_err;
 				}
 				params.wake_intvl_us =
@@ -7307,12 +7331,6 @@ __wlan_hdd_cfg80211_set_wifi_test_config(struct wiphy *wiphy,
 				params.wake_intvl_us = params.wake_intvl_mantis;
 			}
 
-			if (params.wake_dura_us > 0xFFFF) {
-				hdd_err("Invalid wake_dura_us %d",
-					params.wake_dura_us);
-				goto send_err;
-			}
-
 			hdd_debug("twt: vdev %d, intvl_us %d, mantis %d",
 				  params.vdev_id, params.wake_intvl_us,
 				  params.wake_intvl_mantis);

+ 4 - 0
core/hdd/src/wlan_hdd_cfg80211.h

@@ -147,6 +147,10 @@ struct hdd_context;
 #define USE_CFG80211_DEL_STA_V2
 #endif
 
+#define TWT_SETUP_WAKE_INTVL_MANTISSA_MAX 0xFFFF
+#define TWT_SETUP_WAKE_DURATION_MAX       0xFFFF
+#define TWT_SETUP_WAKE_INTVL_EXP_MAX      31
+
 /**
  * enum eDFS_CAC_STATUS: CAC status
  *