diff mbox series

[v2] Fix use after free warning introduced by gcc 12.1

Message ID 20230420192821.376828-1-krishna.t@nordicsemi.no
State Accepted
Headers show
Series [v2] Fix use after free warning introduced by gcc 12.1 | expand

Commit Message

Krishna Chaitanya April 20, 2023, 7:28 p.m. UTC
From: krishna T <krishna.t@nordicsemi.no>

gcc 12.1 complains about using pointer after realloc as it could
potentially be moved/freed, causing any uses after UB.

Fix this by doing checks before alloc and use those statuses and update
with new BSS.

Signed-off-by: Krishna T <krishna.t@nordicsemi.no>
---
v2: Fix the warning by doing the checks before realloc.
---
 wpa_supplicant/bss.c | 46 +++++++++++++++++++++++++++++++-------------
 1 file changed, 33 insertions(+), 13 deletions(-)

Comments

Jouni Malinen April 28, 2023, 3:39 p.m. UTC | #1
On Fri, Apr 21, 2023 at 12:58:21AM +0530, Krishna wrote:
> gcc 12.1 complains about using pointer after realloc as it could
> potentially be moved/freed, causing any uses after UB.
> 
> Fix this by doing checks before alloc and use those statuses and update
> with new BSS.

Could you please provide the exact warning message produced by the
compiler? gcc 12.1 did not complain about anything in my test setup when
compiling wpa_supplicant, so I'm assuming this would need some extra
warnings to be enabled.

As far as the "use of a pointer after realloc" is concerned, it should
be noted that the implementation here does not dereference the old
pointer after the realloc() call. What is being done here is a
check of whether the buffer was indeed moved by comparing the pointer
values before and after the realloc call. Is that really UB or is that
an excessive warning from the compiler?
Krishna Chaitanya April 29, 2023, 6:34 p.m. UTC | #2
On Fri, Apr 28, 2023 at 9:09 PM Jouni Malinen <j@w1.fi> wrote:
>
> On Fri, Apr 21, 2023 at 12:58:21AM +0530, Krishna wrote:
> > gcc 12.1 complains about using pointer after realloc as it could
> > potentially be moved/freed, causing any uses after UB.
> >
> > Fix this by doing checks before alloc and use those statuses and update
> > with new BSS.
>
> Could you please provide the exact warning message produced by the
> compiler? gcc 12.1 did not complain about anything in my test setup when
> compiling wpa_supplicant, so I'm assuming this would need some extra
> warnings to be enabled.

../../../../../modules/lib/hostap/wpa_supplicant/bss.c:701:25: error:
pointer 'bss' may be used after 'realloc' [-Werror=use-after-free]
701 | wpa_bss_update_pending_connect(wpa_s, bss, nbss);

>
> As far as the "use of a pointer after realloc" is concerned, it should
> be noted that the implementation here does not dereference the old
> pointer after the realloc() call. What is being done here is a
> check of whether the buffer was indeed moved by comparing the pointer
> values before and after the realloc call. Is that really UB or is that
> an excessive warning from the compiler?
Well, the code looks fine, but as the pointer after realloc might not
exist, compiler
can optimize the code causing indeterminate behaviour. This is discussed
here https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104069 and
https://www.reddit.com/r/C_Programming/comments/vffgpo/comment/icvvw8e/?utm_source=share&utm_medium=web2x&context=3
Krishna Chaitanya Nov. 5, 2023, 5:34 p.m. UTC | #3
On Sun, Apr 30, 2023 at 12:04 AM Krishna Chaitanya
<chaitanya.mgit@gmail.com> wrote:
>
> On Fri, Apr 28, 2023 at 9:09 PM Jouni Malinen <j@w1.fi> wrote:
> >
> > On Fri, Apr 21, 2023 at 12:58:21AM +0530, Krishna wrote:
> > > gcc 12.1 complains about using pointer after realloc as it could
> > > potentially be moved/freed, causing any uses after UB.
> > >
> > > Fix this by doing checks before alloc and use those statuses and update
> > > with new BSS.
> >
> > Could you please provide the exact warning message produced by the
> > compiler? gcc 12.1 did not complain about anything in my test setup when
> > compiling wpa_supplicant, so I'm assuming this would need some extra
> > warnings to be enabled.
>
> ../../../../../modules/lib/hostap/wpa_supplicant/bss.c:701:25: error:
> pointer 'bss' may be used after 'realloc' [-Werror=use-after-free]
> 701 | wpa_bss_update_pending_connect(wpa_s, bss, nbss);
>
> >
> > As far as the "use of a pointer after realloc" is concerned, it should
> > be noted that the implementation here does not dereference the old
> > pointer after the realloc() call. What is being done here is a
> > check of whether the buffer was indeed moved by comparing the pointer
> > values before and after the realloc call. Is that really UB or is that
> > an excessive warning from the compiler?
> Well, the code looks fine, but as the pointer after realloc might not
> exist, compiler
> can optimize the code causing indeterminate behaviour. This is discussed
> here https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104069 and
> https://www.reddit.com/r/C_Programming/comments/vffgpo/comment/icvvw8e/?utm_source=share&utm_medium=web2x&context=3
Gentle reminder.
Jouni Malinen Nov. 6, 2023, 9:10 a.m. UTC | #4
On Sun, Apr 30, 2023 at 12:04:57AM +0530, Krishna Chaitanya wrote:
> On Fri, Apr 28, 2023 at 9:09 PM Jouni Malinen <j@w1.fi> wrote:
> >
> > On Fri, Apr 21, 2023 at 12:58:21AM +0530, Krishna wrote:
> > > gcc 12.1 complains about using pointer after realloc as it could
> > > potentially be moved/freed, causing any uses after UB.
> > >
> > > Fix this by doing checks before alloc and use those statuses and update
> > > with new BSS.
> >
> > Could you please provide the exact warning message produced by the
> > compiler? gcc 12.1 did not complain about anything in my test setup when
> > compiling wpa_supplicant, so I'm assuming this would need some extra
> > warnings to be enabled.
> 
> ../../../../../modules/lib/hostap/wpa_supplicant/bss.c:701:25: error:
> pointer 'bss' may be used after 'realloc' [-Werror=use-after-free]
> 701 | wpa_bss_update_pending_connect(wpa_s, bss, nbss);

Thanks for the details. This gets hidden by CONFIG_WPA_TRACE=y that I
use in my builds.. I was able to reproduce this now and I applied the
patch with some cleanup.
diff mbox series

Patch

diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 320441426..c98104ca3 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -182,9 +182,26 @@  static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
 	os_free(anqp);
 }
 
+static bool wpa_bss_check_pending_connect(struct wpa_supplicant *wpa_s,
+					   struct wpa_bss *bss)
+{
+	struct wpa_radio_work *work;
+	struct wpa_connect_work *cwork;
+
+	work = radio_work_pending(wpa_s, "sme-connect");
+	if (!work)
+		work = radio_work_pending(wpa_s, "connect");
+	if (!work)
+		return false;
+
+	cwork = work->ctx;
+	if (cwork->bss != bss)
+		return false;
+
+	return true;
+}
 
 static void wpa_bss_update_pending_connect(struct wpa_supplicant *wpa_s,
-					   struct wpa_bss *old_bss,
 					   struct wpa_bss *new_bss)
 {
 	struct wpa_radio_work *work;
@@ -197,8 +214,6 @@  static void wpa_bss_update_pending_connect(struct wpa_supplicant *wpa_s,
 		return;
 
 	cwork = work->ctx;
-	if (cwork->bss != old_bss)
-		return;
 
 	wpa_printf(MSG_DEBUG,
 		   "Update BSS pointer for the pending connect radio work");
@@ -224,7 +239,8 @@  void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 			}
 		}
 	}
-	wpa_bss_update_pending_connect(wpa_s, bss, NULL);
+	if (wpa_bss_check_pending_connect(wpa_s, bss))
+		wpa_bss_update_pending_connect(wpa_s, NULL);
 	dl_list_del(&bss->list);
 	dl_list_del(&bss->list_id);
 	wpa_s->num_bss--;
@@ -725,20 +741,24 @@  wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 	} else {
 		struct wpa_bss *nbss;
 		struct dl_list *prev = bss->list_id.prev;
+		bool update_pending_connect = wpa_bss_check_pending_connect(
+			wpa_s, bss);
+		unsigned int i;
+		bool update_current_bss = wpa_s->current_bss == bss;
+		for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+			if (wpa_s->last_scan_res[i] == bss)
+				break;
+		}
 		dl_list_del(&bss->list_id);
 		nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
 				  res->beacon_ie_len);
 		if (nbss) {
-			unsigned int i;
-			for (i = 0; i < wpa_s->last_scan_res_used; i++) {
-				if (wpa_s->last_scan_res[i] == bss) {
-					wpa_s->last_scan_res[i] = nbss;
-					break;
-				}
-			}
-			if (wpa_s->current_bss == bss)
+			if (i != wpa_s->last_scan_res_used)
+				wpa_s->last_scan_res[i] = nbss;
+			if (update_current_bss)
 				wpa_s->current_bss = nbss;
-			wpa_bss_update_pending_connect(wpa_s, bss, nbss);
+			if (update_pending_connect)
+				wpa_bss_update_pending_connect(wpa_s, nbss);
 			bss = nbss;
 			os_memcpy(bss->ies, res + 1,
 				  res->ie_len + res->beacon_ie_len);