diff mbox series

Use default IEs in wpa_supplicant_trigger_scan

Message ID 20210331185221.61841-1-matthewmwang@chromium.org
State Changes Requested
Headers show
Series Use default IEs in wpa_supplicant_trigger_scan | expand

Commit Message

Matthew Wang March 31, 2021, 6:52 p.m. UTC
wpa_supplicant_trigger_scan previously wouldn't include any of the IEs
generated by wpa_supplicant_extra_ies. Instruct it to do so in most
cases. This is necessary because MBO STAs are required to include MBO
capabilities in their probe requests.

Signed-off-by: Matthew Wang <matthewmwang@chromium.org>
---
 doc/dbus.doxygen                        |  2 +-
 wpa_supplicant/bgscan_learn.c           |  2 +-
 wpa_supplicant/bgscan_simple.c          |  2 +-
 wpa_supplicant/dbus/dbus_new_handlers.c |  6 ++++--
 wpa_supplicant/rrm.c                    |  2 +-
 wpa_supplicant/scan.c                   | 27 ++++++++++++++++++++++---
 wpa_supplicant/scan.h                   |  4 +++-
 wpa_supplicant/sme.c                    |  2 +-
 8 files changed, 36 insertions(+), 11 deletions(-)

Comments

Jouni Malinen Aug. 19, 2021, 2:16 p.m. UTC | #1
On Wed, Mar 31, 2021 at 11:52:21AM -0700, Matthew Wang wrote:
> wpa_supplicant_trigger_scan previously wouldn't include any of the IEs
> generated by wpa_supplicant_extra_ies. Instruct it to do so in most
> cases. This is necessary because MBO STAs are required to include MBO
> capabilities in their probe requests.

> diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
> @@ -278,19 +278,40 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
>   * wpa_supplicant_trigger_scan - Request driver to start a scan
>   * @wpa_s: Pointer to wpa_supplicant data
>   * @params: Scan parameters
> + * @default_ies: Whether or not to use the default IEs in the probe request.
> + * Note that this will free any existing IEs set in @params, so this shouldn't
> + * be set if the IEs have already been set with wpa_supplicant_extra_ies.
> + * Otherwise, wpabuf_free will lead to a double-free.

This sounds a bit scary when most existing calls to
wpa_supplicant_trigger_scan() were modified to use default_ies == true.

> +	if (default_ies) {
> +		if (params->extra_ies_len) {
> +			os_free((u8 *) params->extra_ies);
> +		}

How can this be sure that params->extra_ies (const u8 pointer for a
reason to imply it might not be allocated from heap) is actually
allocated with os_malloc/zalloc() and something that is not referenced
from somewhere else? Should this set params->extra_ies to NULL after it
was freed?

> +		ies = wpa_supplicant_extra_ies(wpa_s);
> +		if (ies) {
> +			params->extra_ies = wpabuf_head(ies);
> +			params->extra_ies_len = wpabuf_len(ies);
> +		}

This would seem to leave params->extra_ies_len > 0 and params->extra_ies
pointing to freed memory if that wpa_supplicant_extra_ies() call fails..
Matthew Wang Aug. 23, 2021, 9:56 p.m. UTC | #2
> This sounds a bit scary when most existing calls to
> wpa_supplicant_trigger_scan() were modified to use default_ies == true.

I've run all the hwsim tests, and it's been in production in ChromeOS
for the past few months with no issues. The extra IEs are just
capability indications (which end up being included in association
requests anyway), so including them in the scan shouldn't break
anything.

> How can this be sure that params->extra_ies (const u8 pointer for a
> reason to imply it might not be allocated from heap) is actually
> allocated with os_malloc/zalloc() and something that is not referenced
> from somewhere else?

params->extra_ies is only either allocated from the heap, or a pointer
to wpabuf_head of wpa_supplicant_extra_ies. In the latter case, there
are a couple instance where trigger_scan is called with
params->extra_ies already allocated via wpa_supplicant_extra_ies, and
these all use default_ies = false (note the comment about the
default_ies parameter). So I guess the answer to your question is that
it's the caller's responsibility to set default_ies based on whether
or not params->extra_ies is expected to already be set.

> Should this set params->extra_ies to NULL after it was freed?

Yes, you're right. I've updated this to set it to NULL and set the
extra_ies_len field to 0. This should address your last comment as
well.

On Thu, Aug 19, 2021 at 7:16 AM Jouni Malinen <j@w1.fi> wrote:
>
> On Wed, Mar 31, 2021 at 11:52:21AM -0700, Matthew Wang wrote:
> > wpa_supplicant_trigger_scan previously wouldn't include any of the IEs
> > generated by wpa_supplicant_extra_ies. Instruct it to do so in most
> > cases. This is necessary because MBO STAs are required to include MBO
> > capabilities in their probe requests.
>
> > diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
> > @@ -278,19 +278,40 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
> >   * wpa_supplicant_trigger_scan - Request driver to start a scan
> >   * @wpa_s: Pointer to wpa_supplicant data
> >   * @params: Scan parameters
> > + * @default_ies: Whether or not to use the default IEs in the probe request.
> > + * Note that this will free any existing IEs set in @params, so this shouldn't
> > + * be set if the IEs have already been set with wpa_supplicant_extra_ies.
> > + * Otherwise, wpabuf_free will lead to a double-free.
>
> This sounds a bit scary when most existing calls to
> wpa_supplicant_trigger_scan() were modified to use default_ies == true.
>
> > +     if (default_ies) {
> > +             if (params->extra_ies_len) {
> > +                     os_free((u8 *) params->extra_ies);
> > +             }
>
> How can this be sure that params->extra_ies (const u8 pointer for a
> reason to imply it might not be allocated from heap) is actually
> allocated with os_malloc/zalloc() and something that is not referenced
> from somewhere else? Should this set params->extra_ies to NULL after it
> was freed?
>
> > +             ies = wpa_supplicant_extra_ies(wpa_s);
> > +             if (ies) {
> > +                     params->extra_ies = wpabuf_head(ies);
> > +                     params->extra_ies_len = wpabuf_len(ies);
> > +             }
>
> This would seem to leave params->extra_ies_len > 0 and params->extra_ies
> pointing to freed memory if that wpa_supplicant_extra_ies() call fails..
>
> --
> Jouni Malinen                                            PGP id EFC895FA
diff mbox series

Patch

diff --git a/doc/dbus.doxygen b/doc/dbus.doxygen
index 8231aac4180..1d93a1d7899 100644
--- a/doc/dbus.doxygen
+++ b/doc/dbus.doxygen
@@ -206,7 +206,7 @@  fi.w1.wpa_supplicant1.CreateInterface.
 	      <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th>
 	      <tr><td>Type</td><td>s</td><td>Type of the scan. Possible values: "active", "passive"</td><td>Yes</td>
 	      <tr><td>SSIDs</td><td>aay</td><td>Array of SSIDs to scan for (applies only if scan type is active)</td><td>No</td>
-	      <tr><td>IEs</td><td>aay</td><td>Information elements to used in active scan (applies only if scan type is active)</td><td>No</td>
+	      <tr><td>IEs</td><td>aay</td><td>Information elements to used in active scan (applies only if scan type is active). Default IEs will be used in absence of this option.</td><td>No</td>
 	      <tr><td>Channels</td><td>a(uu)</td><td>Array of frequencies to scan in form of (center, width) in MHz.</td><td>No</td>
 	      <tr><td>AllowRoam</td><td>b</td><td>TRUE (or absent) to allow a roaming decision based on the results of this scan, FALSE to prevent a roaming decision.</td><td>No</td>
 	    </table>
diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c
index cb732f709b9..3d10d911853 100644
--- a/wpa_supplicant/bgscan_learn.c
+++ b/wpa_supplicant/bgscan_learn.c
@@ -305,7 +305,7 @@  static void bgscan_learn_timeout(void *eloop_ctx, void *timeout_ctx)
 	}
 
 	wpa_printf(MSG_DEBUG, "bgscan learn: Request a background scan");
-	if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
+	if (wpa_supplicant_trigger_scan(wpa_s, &params, true)) {
 		wpa_printf(MSG_DEBUG, "bgscan learn: Failed to trigger scan");
 		eloop_register_timeout(data->scan_interval, 0,
 				       bgscan_learn_timeout, data, NULL);
diff --git a/wpa_supplicant/bgscan_simple.c b/wpa_supplicant/bgscan_simple.c
index 41a26df0d63..4dd212b2197 100644
--- a/wpa_supplicant/bgscan_simple.c
+++ b/wpa_supplicant/bgscan_simple.c
@@ -49,7 +49,7 @@  static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx)
 	 */
 
 	wpa_printf(MSG_DEBUG, "bgscan simple: Request a background scan");
-	if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
+	if (wpa_supplicant_trigger_scan(wpa_s, &params, true)) {
 		wpa_printf(MSG_DEBUG, "bgscan simple: Failed to trigger scan");
 		eloop_register_timeout(data->scan_interval, 0,
 				       bgscan_simple_timeout, data, NULL);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index db9f30c9aab..08be9da3b9e 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -1371,6 +1371,7 @@  DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
 	struct wpa_driver_scan_params params;
 	size_t i;
 	dbus_bool_t allow_roam = 1;
+	bool custom_ies = false;
 
 	os_memset(&params, 0, sizeof(params));
 
@@ -1397,6 +1398,7 @@  DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
 			if (wpas_dbus_get_scan_ies(message, &variant_iter,
 						   &params, &reply) < 0)
 				goto out;
+			custom_ies = true;
 		} else if (os_strcmp(key, "Channels") == 0) {
 			if (wpas_dbus_get_scan_channels(message, &variant_iter,
 							&params, &reply) < 0)
@@ -1444,7 +1446,7 @@  DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
 			if (params.freqs && params.freqs[0]) {
 				wpa_s->last_scan_req = MANUAL_SCAN_REQ;
 				if (wpa_supplicant_trigger_scan(wpa_s,
-								&params)) {
+								&params, false)) {
 					reply = wpas_dbus_error_scan_error(
 						message,
 						"Scan request rejected");
@@ -1470,7 +1472,7 @@  DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
 		}
 
 		wpa_s->last_scan_req = MANUAL_SCAN_REQ;
-		if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
+		if (wpa_supplicant_trigger_scan(wpa_s, &params, !custom_ies)) {
 			reply = wpas_dbus_error_scan_error(
 				message, "Scan request rejected");
 		}
diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
index cf107ebaf63..0e079380b73 100644
--- a/wpa_supplicant/rrm.c
+++ b/wpa_supplicant/rrm.c
@@ -1034,7 +1034,7 @@  static void wpas_rrm_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 	}
 	os_get_reltime(&wpa_s->beacon_rep_scan);
 	if (wpa_s->scanning || wpas_p2p_in_progress(wpa_s) ||
-	    wpa_supplicant_trigger_scan(wpa_s, params))
+	    wpa_supplicant_trigger_scan(wpa_s, params, true))
 		wpas_rrm_refuse_request(wpa_s);
 	params->duration = prev_duration;
 }
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index c53474dae26..94231e417cd 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -278,19 +278,40 @@  static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
  * wpa_supplicant_trigger_scan - Request driver to start a scan
  * @wpa_s: Pointer to wpa_supplicant data
  * @params: Scan parameters
+ * @default_ies: Whether or not to use the default IEs in the probe request.
+ * Note that this will free any existing IEs set in @params, so this shouldn't
+ * be set if the IEs have already been set with wpa_supplicant_extra_ies.
+ * Otherwise, wpabuf_free will lead to a double-free.
  * Returns: 0 on success, -1 on failure
  */
 int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
-				struct wpa_driver_scan_params *params)
+				struct wpa_driver_scan_params *params,
+				bool default_ies)
 {
 	struct wpa_driver_scan_params *ctx;
+	struct wpabuf *ies = NULL;
 
 	if (wpa_s->scan_work) {
 		wpa_dbg(wpa_s, MSG_INFO, "Reject scan trigger since one is already pending");
 		return -1;
 	}
 
+	if (default_ies) {
+		if (params->extra_ies_len) {
+			os_free((u8 *) params->extra_ies);
+		}
+		ies = wpa_supplicant_extra_ies(wpa_s);
+		if (ies) {
+			params->extra_ies = wpabuf_head(ies);
+			params->extra_ies_len = wpabuf_len(ies);
+		}
+	}
 	ctx = wpa_scan_clone_params(params);
+	if (ies) {
+		wpabuf_free(ies);
+		params->extra_ies = NULL;
+		params->extra_ies_len = 0;
+	}
 	if (!ctx ||
 	    radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0)
 	{
@@ -566,7 +587,7 @@  void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s)
 }
 
 
-static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
+struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
 {
 	struct wpabuf *extra_ie = NULL;
 	u8 ext_capab[18];
@@ -1339,7 +1360,7 @@  scan:
 	}
 #endif /* CONFIG_P2P */
 
-	ret = wpa_supplicant_trigger_scan(wpa_s, scan_params);
+	ret = wpa_supplicant_trigger_scan(wpa_s, scan_params, false);
 
 	if (ret && wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs &&
 	    !wpa_s->manual_scan_freqs) {
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 8eb5c73e275..d1f26eccec3 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -43,7 +43,8 @@  void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
 				    int scanning);
 struct wpa_driver_scan_params;
 int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
-				struct wpa_driver_scan_params *params);
+				struct wpa_driver_scan_params *params,
+				bool default_ies);
 struct wpa_scan_results *
 wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
 				struct scan_info *info, int new_scan);
@@ -90,5 +91,6 @@  int wpa_add_scan_freqs_list(struct wpa_supplicant *wpa_s,
 			    enum hostapd_hw_mode band,
 			    struct wpa_driver_scan_params *params,
 			    bool is_6ghz);
+struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s);
 
 #endif /* SCAN_H */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index dde80863a98..bf1576ac31f 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -2543,7 +2543,7 @@  static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 	params.low_priority = 1;
 	wpa_printf(MSG_DEBUG, "SME OBSS: Request an OBSS scan");
 
-	if (wpa_supplicant_trigger_scan(wpa_s, &params))
+	if (wpa_supplicant_trigger_scan(wpa_s, &params, true))
 		wpa_printf(MSG_DEBUG, "SME OBSS: Failed to trigger scan");
 	else
 		wpa_s->sme.sched_obss_scan = 1;