P2PS: Add PD Response validation

Validate the PD Response frame contents more thoroughly when it is used
for P2PS.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
Reviewed-by: Max Stepanov <Max.Stepanov@intel.com>
Reviewed-by: Ilan Peer <ilan.peer@intel.com>
This commit is contained in:
Andrei Otcheretianski 2015-07-02 10:45:06 +03:00 committed by Jouni Malinen
parent 1f1a08b4cc
commit 1f14e2bf92
2 changed files with 112 additions and 1 deletions

View file

@ -823,6 +823,105 @@ out:
} }
static int p2p_validate_p2ps_pd_resp(struct p2p_data *p2p,
struct p2p_message *msg)
{
u8 conn_cap_go = 0;
u8 conn_cap_cli = 0;
u32 session_id;
u32 adv_id;
#define P2PS_PD_RESP_CHECK(_val, _attr) \
do { \
if ((_val) && !msg->_attr) { \
p2p_dbg(p2p, "P2PS PD Response missing " #_attr); \
return -1; \
} \
} while (0)
P2PS_PD_RESP_CHECK(1, status);
P2PS_PD_RESP_CHECK(1, adv_id);
P2PS_PD_RESP_CHECK(1, adv_mac);
P2PS_PD_RESP_CHECK(1, capability);
P2PS_PD_RESP_CHECK(1, p2p_device_info);
P2PS_PD_RESP_CHECK(1, session_id);
P2PS_PD_RESP_CHECK(1, session_mac);
P2PS_PD_RESP_CHECK(1, feature_cap);
session_id = WPA_GET_LE32(msg->session_id);
adv_id = WPA_GET_LE32(msg->adv_id);
if (p2p->p2ps_prov->session_id != session_id) {
p2p_dbg(p2p,
"Ignore PD Response with unexpected Session ID");
return -1;
}
if (os_memcmp(p2p->p2ps_prov->session_mac, msg->session_mac,
ETH_ALEN)) {
p2p_dbg(p2p,
"Ignore PD Response with unexpected Session MAC");
return -1;
}
if (p2p->p2ps_prov->adv_id != adv_id) {
p2p_dbg(p2p,
"Ignore PD Response with unexpected Advertisement ID");
return -1;
}
if (os_memcmp(p2p->p2ps_prov->adv_mac, msg->adv_mac, ETH_ALEN) != 0) {
p2p_dbg(p2p,
"Ignore PD Response with unexpected Advertisement MAC");
return -1;
}
if (msg->listen_channel) {
p2p_dbg(p2p,
"Ignore malformed PD Response - unexpected Listen Channel");
return -1;
}
if (*msg->status == P2P_SC_SUCCESS &&
!(!!msg->conn_cap ^ !!msg->persistent_dev)) {
p2p_dbg(p2p,
"Ignore malformed PD Response - either conn_cap or persistent group should be present");
return -1;
}
if (msg->persistent_dev && *msg->status != P2P_SC_SUCCESS) {
p2p_dbg(p2p,
"Ignore malformed PD Response - persistent group is present, but the status isn't success");
return -1;
}
if (msg->conn_cap) {
conn_cap_go = *msg->conn_cap == P2PS_SETUP_GROUP_OWNER;
conn_cap_cli = *msg->conn_cap == P2PS_SETUP_CLIENT;
}
P2PS_PD_RESP_CHECK(msg->persistent_dev || conn_cap_go || conn_cap_cli,
channel_list);
P2PS_PD_RESP_CHECK(msg->persistent_dev || conn_cap_go || conn_cap_cli,
config_timeout);
P2PS_PD_RESP_CHECK(conn_cap_go, group_id);
P2PS_PD_RESP_CHECK(conn_cap_go, intended_addr);
P2PS_PD_RESP_CHECK(conn_cap_go, operating_channel);
/*
* TODO: Also validate that operating channel is present if the device
* is a GO in a persistent group. We can't do it here since we don't
* know what is the role of the peer. It should be probably done in
* p2ps_prov_complete callback, but currently operating channel isn't
* passed to it.
*/
#undef P2PS_PD_RESP_CHECK
return 0;
}
void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len) const u8 *data, size_t len)
{ {
@ -840,6 +939,11 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
if (p2p_parse(data, len, &msg)) if (p2p_parse(data, len, &msg))
return; return;
if (p2p->p2ps_prov && p2p_validate_p2ps_pd_resp(p2p, &msg)) {
p2p_parse_free(&msg);
return;
}
/* Parse the P2PS members present */ /* Parse the P2PS members present */
if (msg.status) if (msg.status)
status = *msg.status; status = *msg.status;
@ -944,7 +1048,6 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
} }
if ((msg.conn_cap || msg.persistent_dev) && if ((msg.conn_cap || msg.persistent_dev) &&
msg.adv_id &&
(status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED) && (status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED) &&
p2p->p2ps_prov) { p2p->p2ps_prov) {
if (p2p->cfg->p2ps_prov_complete) { if (p2p->cfg->p2ps_prov_complete) {

View file

@ -3689,6 +3689,14 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
/* Clean up stale persistent groups with this device */ /* Clean up stale persistent groups with this device */
s = wpas_p2p_get_persistent(wpa_s, dev, persist_ssid, s = wpas_p2p_get_persistent(wpa_s, dev, persist_ssid,
persist_ssid_size); persist_ssid_size);
if (persist_ssid && s && s->mode != WPAS_MODE_P2P_GO &&
os_memcmp(grp_mac, mac, ETH_ALEN) == 0) {
wpa_dbg(wpa_s, MSG_ERROR,
"P2P: Peer device is a GO in a persistent group, but it did not provide the intended MAC address");
return;
}
for (;;) { for (;;) {
stale = wpas_p2p_get_persistent(wpa_s, dev, NULL, 0); stale = wpas_p2p_get_persistent(wpa_s, dev, NULL, 0);
if (!stale) if (!stale)