mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2024-11-28 18:28:23 -05:00
P2PS: Add validation for P2PS PD Request
Validate that all the required attributes appear in a P2PS PD Request, and in addition, in the case of follow-on PD Request, check that the given values match those of the original PD Request. Signed-off-by: Ilan Peer <ilan.peer@intel.com>
This commit is contained in:
parent
20324d47f9
commit
e4f90a6a27
181
src/p2p/p2p_pd.c
181
src/p2p/p2p_pd.c
@ -427,6 +427,117 @@ static u8 p2ps_own_preferred_cpt(const u8 *cpt_priority, u8 req_cpt_mask)
|
||||
}
|
||||
|
||||
|
||||
/* Check if the message contains a valid P2PS PD Request */
|
||||
static int p2ps_validate_pd_req(struct p2p_data *p2p, struct p2p_message *msg,
|
||||
const u8 *addr)
|
||||
{
|
||||
u8 group_id = 0;
|
||||
u8 intended_addr = 0;
|
||||
u8 operating_channel = 0;
|
||||
u8 channel_list = 0;
|
||||
u8 config_timeout = 0;
|
||||
u8 listen_channel = 0;
|
||||
|
||||
#define P2PS_PD_REQ_CHECK(_val, _attr) \
|
||||
do { \
|
||||
if ((_val) && !msg->_attr) { \
|
||||
p2p_dbg(p2p, "Not P2PS PD Request. Missing %s", #_attr); \
|
||||
return -1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
P2PS_PD_REQ_CHECK(1, adv_id);
|
||||
P2PS_PD_REQ_CHECK(1, session_id);
|
||||
P2PS_PD_REQ_CHECK(1, session_mac);
|
||||
P2PS_PD_REQ_CHECK(1, adv_mac);
|
||||
P2PS_PD_REQ_CHECK(1, capability);
|
||||
P2PS_PD_REQ_CHECK(1, p2p_device_info);
|
||||
P2PS_PD_REQ_CHECK(1, feature_cap);
|
||||
|
||||
/*
|
||||
* We don't need to check Connection Capability, Persistent Group,
|
||||
* and related attributes for follow-on PD Request with a status
|
||||
* other than SUCCESS_DEFERRED.
|
||||
*/
|
||||
if (msg->status && *msg->status != P2P_SC_SUCCESS_DEFERRED)
|
||||
return 0;
|
||||
|
||||
P2PS_PD_REQ_CHECK(1, conn_cap);
|
||||
|
||||
/*
|
||||
* Note 1: A feature capability attribute structure can be changed
|
||||
* in the future. The assumption is that such modifications are
|
||||
* backward compatible, therefore we allow processing of msg.feature_cap
|
||||
* exceeding the size of the p2ps_feature_capab structure.
|
||||
* Note 2: Verification of msg.feature_cap_len below has to be changed
|
||||
* to allow 2 byte feature capability processing if
|
||||
* struct p2ps_feature_capab is extended to include additional fields
|
||||
* and it affects the structure size.
|
||||
*/
|
||||
if (msg->feature_cap_len < sizeof(struct p2ps_feature_capab)) {
|
||||
p2p_dbg(p2p, "P2PS: Invalid feature capability len");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (*msg->conn_cap) {
|
||||
case P2PS_SETUP_NEW:
|
||||
group_id = 1;
|
||||
intended_addr = 1;
|
||||
operating_channel = 1;
|
||||
channel_list = 1;
|
||||
config_timeout = 1;
|
||||
listen_channel = 1;
|
||||
break;
|
||||
case P2PS_SETUP_CLIENT:
|
||||
channel_list = 1;
|
||||
listen_channel = 1;
|
||||
break;
|
||||
case P2PS_SETUP_GROUP_OWNER:
|
||||
group_id = 1;
|
||||
intended_addr = 1;
|
||||
operating_channel = 1;
|
||||
break;
|
||||
case P2PS_SETUP_NEW | P2PS_SETUP_GROUP_OWNER:
|
||||
group_id = 1;
|
||||
operating_channel = 1;
|
||||
intended_addr = 1;
|
||||
channel_list = 1;
|
||||
config_timeout = 1;
|
||||
break;
|
||||
case P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER:
|
||||
group_id = 1;
|
||||
intended_addr = 1;
|
||||
operating_channel = 1;
|
||||
channel_list = 1;
|
||||
config_timeout = 1;
|
||||
break;
|
||||
default:
|
||||
p2p_dbg(p2p, "Invalid P2PS PD connection capability");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg->persistent_dev) {
|
||||
channel_list = 1;
|
||||
config_timeout = 1;
|
||||
if (os_memcmp(msg->persistent_dev, addr, ETH_ALEN) == 0) {
|
||||
intended_addr = 1;
|
||||
operating_channel = 1;
|
||||
}
|
||||
}
|
||||
|
||||
P2PS_PD_REQ_CHECK(group_id, group_id);
|
||||
P2PS_PD_REQ_CHECK(intended_addr, intended_addr);
|
||||
P2PS_PD_REQ_CHECK(operating_channel, operating_channel);
|
||||
P2PS_PD_REQ_CHECK(channel_list, channel_list);
|
||||
P2PS_PD_REQ_CHECK(config_timeout, config_timeout);
|
||||
P2PS_PD_REQ_CHECK(listen_channel, listen_channel);
|
||||
|
||||
#undef P2PS_PD_REQ_CHECK
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
|
||||
const u8 *data, size_t len, int rx_freq)
|
||||
{
|
||||
@ -538,21 +649,23 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
|
||||
os_memset(session_mac, 0, ETH_ALEN);
|
||||
os_memset(adv_mac, 0, ETH_ALEN);
|
||||
|
||||
/* Note 1: A feature capability attribute structure can be changed
|
||||
* in the future. The assumption is that such modifications are
|
||||
* backwards compatible, therefore we allow processing of
|
||||
* msg.feature_cap exceeding the size of the p2ps_feature_capab
|
||||
* structure.
|
||||
* Note 2: Vverification of msg.feature_cap_len below has to be changed
|
||||
* to allow 2 byte feature capability processing if struct
|
||||
* p2ps_feature_capab is extended to include additional fields and it
|
||||
* affects the structure size.
|
||||
/*
|
||||
* Validate a P2PS PD Request and skip P2PS processing if not a valid
|
||||
* P2PS PD.
|
||||
*/
|
||||
if (!msg.adv_id || !msg.session_id || !msg.session_mac ||
|
||||
!msg.adv_mac || !msg.feature_cap ||
|
||||
msg.feature_cap_len < sizeof(*req_fcap) ||
|
||||
!(msg.status || msg.conn_cap))
|
||||
if (msg.adv_id) {
|
||||
/*
|
||||
* Set adv_id here, so that in case of an error, a P2PS PD
|
||||
* Response will be sent.
|
||||
*/
|
||||
adv_id = WPA_GET_LE32(msg.adv_id);
|
||||
if (p2ps_validate_pd_req(p2p, &msg, sa) < 0) {
|
||||
reject = P2P_SC_FAIL_INVALID_PARAMS;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
goto out;
|
||||
}
|
||||
|
||||
req_fcap = (struct p2ps_feature_capab *) msg.feature_cap;
|
||||
|
||||
@ -560,17 +673,28 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
|
||||
os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN);
|
||||
|
||||
session_id = WPA_GET_LE32(msg.session_id);
|
||||
adv_id = WPA_GET_LE32(msg.adv_id);
|
||||
|
||||
if (!msg.status)
|
||||
p2ps_adv = p2p_service_p2ps_id(p2p, adv_id);
|
||||
|
||||
p2p_dbg(p2p, "adv_id: %x - p2ps_adv - %p", adv_id, p2ps_adv);
|
||||
|
||||
if (msg.conn_cap)
|
||||
conncap = *msg.conn_cap;
|
||||
remote_conncap = conncap;
|
||||
|
||||
if (!msg.status) {
|
||||
if (os_memcmp(p2p->cfg->dev_addr, msg.adv_mac, ETH_ALEN)) {
|
||||
p2p_dbg(p2p,
|
||||
"P2PS PD adv mac does not match the local one");
|
||||
reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
p2ps_adv = p2p_service_p2ps_id(p2p, adv_id);
|
||||
if (!p2ps_adv) {
|
||||
p2p_dbg(p2p, "P2PS PD invalid adv_id=0x%X", adv_id);
|
||||
reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
|
||||
goto out;
|
||||
}
|
||||
p2p_dbg(p2p, "adv_id: 0x%X, p2ps_adv: %p", adv_id, p2ps_adv);
|
||||
}
|
||||
|
||||
if (p2ps_adv) {
|
||||
auto_accept = p2ps_adv->auto_accept;
|
||||
conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx,
|
||||
@ -613,9 +737,6 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
|
||||
if (auto_accept || reject != P2P_SC_SUCCESS) {
|
||||
struct p2ps_provision *tmp;
|
||||
|
||||
if (reject == P2P_SC_SUCCESS && !conncap)
|
||||
reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
|
||||
|
||||
if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id,
|
||||
msg.wps_config_methods,
|
||||
session_mac, adv_mac) < 0) {
|
||||
@ -635,9 +756,6 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
|
||||
if (reject != P2P_SC_SUCCESS)
|
||||
goto out;
|
||||
}
|
||||
} else if (!msg.status) {
|
||||
reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!msg.status && !auto_accept &&
|
||||
@ -672,6 +790,19 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
|
||||
if (*msg.status != P2P_SC_SUCCESS_DEFERRED || !p2p->p2ps_prov)
|
||||
goto out;
|
||||
|
||||
if (p2p->p2ps_prov->adv_id != adv_id ||
|
||||
os_memcmp(p2p->p2ps_prov->adv_mac, msg.adv_mac, ETH_ALEN)) {
|
||||
p2p_dbg(p2p,
|
||||
"P2PS Follow-on PD with mismatch Advertisement ID/MAC");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (p2p->p2ps_prov->session_id != session_id ||
|
||||
os_memcmp(p2p->p2ps_prov->session_mac, msg.session_mac, ETH_ALEN)) {
|
||||
p2p_dbg(p2p, "P2PS Follow-on PD with mismatch Session ID/MAC");
|
||||
goto out;
|
||||
}
|
||||
|
||||
method = p2p->p2ps_prov->method;
|
||||
|
||||
conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx,
|
||||
|
Loading…
Reference in New Issue
Block a user