qcacld-3.0: Fix buffer overread & overflow in DISA handler

Currently in hdd_fill_encrypt_decrypt_params() there are multiple
issues with the incoming cfg80211 vendor command handling:
1) A policy is not supplied when invoking nla_parse() which prevents
   basic sanity of the incoming attribute stream.
2) The length of attribute QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN is
   not properly validated.
3) The length of attribute QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA
   is not properly validated.

To address these issues:
1) Create an appropriate nla_policy and specify this policy when
   invoking nla_parse().
2) Validate the length of QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN to
   prevent potential buffer overflow.
3) Validate the length of QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA to
   prevent potential buffer overread.

Change-Id: Ibb86897f249010c94c4098b283aad7a7f95ab9a2
CRs-Fixed: 2054760
This commit is contained in:
Jeff Johnson
2017-06-06 12:53:28 -07:00
committed by snandini
parent a4fdbf6c05
commit 5286eac254

View File

@@ -146,6 +146,16 @@ nla_put_failure:
return -EINVAL; return -EINVAL;
} }
static const struct nla_policy
encrypt_decrypt_policy[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX + 1] = {
[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION] = {
.type = NLA_FLAG},
[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID] = {
.type = NLA_U8},
[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER] = {
.type = NLA_U32},
};
/** /**
* hdd_fill_encrypt_decrypt_params () - parses data from user space * hdd_fill_encrypt_decrypt_params () - parses data from user space
* and fills encrypt/decrypt parameters * and fills encrypt/decrypt parameters
@@ -168,7 +178,7 @@ static int hdd_fill_encrypt_decrypt_params(struct encrypt_decrypt_req_params
uint8_t fc[2]; uint8_t fc[2];
if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX, if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX,
data, data_len, NULL)) { data, data_len, encrypt_decrypt_policy)) {
hdd_err("Invalid ATTR"); hdd_err("Invalid ATTR");
return -EINVAL; return -EINVAL;
} }
@@ -230,8 +240,8 @@ static int hdd_fill_encrypt_decrypt_params(struct encrypt_decrypt_req_params
return -EINVAL; return -EINVAL;
} }
len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN]); len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN]);
if (!len) { if (!len || len > sizeof(encrypt_decrypt_params->pn)) {
hdd_err("Invalid PN length"); hdd_err("Invalid PN length %u", len);
return -EINVAL; return -EINVAL;
} }
@@ -247,8 +257,8 @@ static int hdd_fill_encrypt_decrypt_params(struct encrypt_decrypt_req_params
return -EINVAL; return -EINVAL;
} }
len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA]); len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA]);
if (!len) { if (len < MIN_MAC_HEADER_LEN) {
hdd_err("Invalid header and payload length"); hdd_err("Invalid header and payload length %u", len);
return -EINVAL; return -EINVAL;
} }
@@ -285,6 +295,10 @@ static int hdd_fill_encrypt_decrypt_params(struct encrypt_decrypt_req_params
hdd_debug("mac_hdr_len: %d", mac_hdr_len); hdd_debug("mac_hdr_len: %d", mac_hdr_len);
if (len < mac_hdr_len) {
hdd_err("Invalid header and payload length %u", len);
return -EINVAL;
}
qdf_mem_copy(encrypt_decrypt_params->mac_header, qdf_mem_copy(encrypt_decrypt_params->mac_header,
tmp, mac_hdr_len); tmp, mac_hdr_len);