From 1f14e2bf9207c055385bc914cdfd8f4bf86111f2 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Thu, 2 Jul 2015 10:45:06 +0300 Subject: [PATCH] P2PS: Add PD Response validation Validate the PD Response frame contents more thoroughly when it is used for P2PS. Signed-off-by: Andrei Otcheretianski Reviewed-by: Max Stepanov Reviewed-by: Ilan Peer --- src/p2p/p2p_pd.c | 105 +++++++++++++++++++++++++++++++- wpa_supplicant/p2p_supplicant.c | 8 +++ 2 files changed, 112 insertions(+), 1 deletion(-) diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c index 33c65dc00..532c6f054 100644 --- a/src/p2p/p2p_pd.c +++ b/src/p2p/p2p_pd.c @@ -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, 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)) return; + if (p2p->p2ps_prov && p2p_validate_p2ps_pd_resp(p2p, &msg)) { + p2p_parse_free(&msg); + return; + } + /* Parse the P2PS members present */ if (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) && - msg.adv_id && (status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED) && p2p->p2ps_prov) { if (p2p->cfg->p2ps_prov_complete) { diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 220f2d7ac..9e2760fa3 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -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 */ s = wpas_p2p_get_persistent(wpa_s, dev, persist_ssid, 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 (;;) { stale = wpas_p2p_get_persistent(wpa_s, dev, NULL, 0); if (!stale)