qcacld-3.0: Check buff len alloc in __iw_set_packet_filter_params

In __iw_set_packet_filter_params(), a user controlled length value,
priv_data.length, is used to allocated a buffer. This buffer is then
cast to a struct pointer of struct pkt_filter_cfg type without ensuring
the buffer is of proper length.

Add a sanity check on priv_data.length to ensure that the command being
issued has proper parameters.

Change-Id: Ia871e35ef938ca889fb6b1609a0c881d76f29e4b
CRs-Fixed: 2250775
This commit is contained in:
Sourav Mohapatra 2018-05-31 17:09:05 +05:30 • committed by nshrivas
commit 69d0780f6e

View file

@ -8061,6 +8061,38 @@ static int iw_set_keepalive_params(struct net_device *dev,
}
#ifdef WLAN_FEATURE_PACKET_FILTERING
/**
* validate_packet_filter_params_size() - Validate the size of the params rcvd
* @priv_data: Pointer to the priv data from user space
* @request: Pointer to the struct containing the copied data from user space
*
* Return: False on invalid length, true otherwise
*/
static bool validate_packet_filter_params_size(struct pkt_filter_cfg *request,
uint16_t length)
{
int max_params_size, rcvd_params_size;
max_params_size = HDD_MAX_CMP_PER_PACKET_FILTER *
sizeof(struct pkt_filter_param_cfg);
if (length < sizeof(struct pkt_filter_cfg) - max_params_size) {
hdd_err("Less than minimum number of arguments needed");
return false;
}
rcvd_params_size = request->num_params *
sizeof(struct pkt_filter_param_cfg);
if (length != sizeof(struct pkt_filter_cfg) -
max_params_size + rcvd_params_size) {
hdd_err("Arguments do not match the number of params provided");
return false;
}
return true;
}
/**
* __iw_set_packet_filter_params() - set packet filter parameters in target
* @dev: Pointer to netdev
@ -8101,8 +8133,7 @@ static int __iw_set_packet_filter_params(struct net_device *dev,
return -EINVAL;
}
if ((NULL == priv_data.pointer) || (0 == priv_data.length) ||
priv_data.length < sizeof(struct pkt_filter_cfg)) {
if ((NULL == priv_data.pointer) || (0 == priv_data.length)) {
hdd_err("invalid priv data %pK or invalid priv data length %d",
priv_data.pointer, priv_data.length);
return -EINVAL;
@ -8122,11 +8153,18 @@ static int __iw_set_packet_filter_params(struct net_device *dev,
/* copy data using copy_from_user */
request = mem_alloc_copy_from_user_helper(priv_data.pointer,
priv_data.length);
if (NULL == request) {
hdd_err("mem_alloc_copy_from_user_helper fail");
return -ENOMEM;
}
if (!validate_packet_filter_params_size(request, priv_data.length)) {
hdd_err("Invalid priv data length %d", priv_data.length);
qdf_mem_free(request);
return -EINVAL;
}
if (request->filter_action == HDD_RCV_FILTER_SET)
hdd_ctx->user_configured_pkt_filter_rules |=
1 << request->filter_id;