diff mbox

wpa_supplicant: Set null radio when no more used

Message ID 1423230267-19973-1-git-send-email-eduardo.abinader@openbossa.org
State Superseded
Headers show

Commit Message

Eduardo Abinader Feb. 6, 2015, 1:44 p.m. UTC
This patch avoids a segmentation fault that is occurring
when a removed pending p2p interface receives a delayed
scan result and crashes when handled in
wpa_supplicant_event_scan_results.

The scenario being used is a request to pbc join an
autonomous p2p group.

Signed-off-by: Eduardo Abinader <eduardo.abinader@openbossa.org>
---
 wpa_supplicant/wpa_supplicant.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Jouni Malinen Feb. 6, 2015, 8:22 p.m. UTC | #1
On Fri, Feb 06, 2015 at 09:44:27AM -0400, Eduardo Abinader wrote:
> This patch avoids a segmentation fault that is occurring
> when a removed pending p2p interface receives a delayed
> scan result and crashes when handled in
> wpa_supplicant_event_scan_results.
> 
> The scenario being used is a request to pbc join an
> autonomous p2p group.

Would you have a debug log showing this crash? I find it a bit difficult
to see why this would happen for two reasons: 1) the wpa_s instance is
freed immediately after this call (i.e., there is no way a scan results
could be processed for the interface) and 2) driver_nl80211 drops the
scan result indication for the interface once it has been removed.

> diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
> @@ -3675,13 +3675,13 @@ static void radio_remove_interface(struct wpa_supplicant *wpa_s)
> -	wpa_s->radio = NULL;
>  	if (!dl_list_empty(&radio->ifaces))
>  		return; /* Interfaces remain for this radio */
>  
>  	wpa_printf(MSG_DEBUG, "Remove radio %s", radio->name);
>  	eloop_cancel_timeout(radio_start_next_work, radio, NULL);
>  	os_free(radio);
> +	wpa_s->radio = NULL;

This radio_remove_interface() function is called only from
wpa_supplicant_deinit_iface() and this call is followed by the driver
interface deinit and os_free(wpa_s) before returning to eloop. In other
words, there is no way this specific wpa_s instance could be used in
wpa_supplicant_event_scan_results() after this unless there are some
much more severe issues of continuing to use freed memory.

Allowing wpa_s->radio to continue to point to the radio in the
other-interfaces-remain case looks a bit suspicious since if there were
actual real uses of the wpa_s instance after this, I don't see what
would prevent that other remaining wpa_s instance from getting remove
and deleting the radio instance. After that, the wpa_s->radio on the
not-cleared-to-NULL interface would point to freed memory. Anyway, this
path should obviously not happen either due to that os_free(wpa_s)
following this call..
Eduardo Abinader Feb. 6, 2015, 8:45 p.m. UTC | #2
Hi Jouni,

Please see coments below.

On Fri, Feb 6, 2015 at 4:22 PM, Jouni Malinen <j@w1.fi> wrote:
> On Fri, Feb 06, 2015 at 09:44:27AM -0400, Eduardo Abinader wrote:
>> This patch avoids a segmentation fault that is occurring
>> when a removed pending p2p interface receives a delayed
>> scan result and crashes when handled in
>> wpa_supplicant_event_scan_results.
>>
>> The scenario being used is a request to pbc join an
>> autonomous p2p group.
>
> Would you have a debug log showing this crash? I find it a bit difficult
> to see why this would happen for two reasons: 1) the wpa_s instance is
> freed immediately after this call (i.e., there is no way a scan results
> could be processed for the interface) and 2) driver_nl80211 drops the
> scan result indication for the interface once it has been removed.
>

Log file is here:

http://filebin.ca/1ql0zqDLMH1y/wpas_crash.log.gz

>> diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
>> @@ -3675,13 +3675,13 @@ static void radio_remove_interface(struct wpa_supplicant *wpa_s)
>> -     wpa_s->radio = NULL;
>>       if (!dl_list_empty(&radio->ifaces))
>>               return; /* Interfaces remain for this radio */
>>
>>       wpa_printf(MSG_DEBUG, "Remove radio %s", radio->name);
>>       eloop_cancel_timeout(radio_start_next_work, radio, NULL);
>>       os_free(radio);
>> +     wpa_s->radio = NULL;
>
> This radio_remove_interface() function is called only from
> wpa_supplicant_deinit_iface() and this call is followed by the driver
> interface deinit and os_free(wpa_s) before returning to eloop. In other
> words, there is no way this specific wpa_s instance could be used in
> wpa_supplicant_event_scan_results() after this unless there are some
> much more severe issues of continuing to use freed memory.
>
> Allowing wpa_s->radio to continue to point to the radio in the
> other-interfaces-remain case looks a bit suspicious since if there were
> actual real uses of the wpa_s instance after this, I don't see what
> would prevent that other remaining wpa_s instance from getting remove
> and deleting the radio instance. After that, the wpa_s->radio on the
> not-cleared-to-NULL interface would point to freed memory. Anyway, this
> path should obviously not happen either due to that os_free(wpa_s)
> following this call..

Actually wpa_s->radio is only being freed, when no other interface is
using it, like
wlanX. The patches only ensures radio is to null, when freed.

>
> --
> Jouni Malinen                                            PGP id EFC895FA
> _______________________________________________
> HostAP mailing list
> HostAP@lists.shmoo.com
> http://lists.shmoo.com/mailman/listinfo/hostap
Jouni Malinen Feb. 8, 2015, 2:08 p.m. UTC | #3
On Fri, Feb 06, 2015 at 04:45:21PM -0400, Eduardo Abinader wrote:
> Log file is here:
> 
> http://filebin.ca/1ql0zqDLMH1y/wpas_crash.log.gz

Thanks! I was able to reproduce this and confirm that this is indeed due
to use of freed memory after the P2P group interface gets removed.

> >> diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
> >> @@ -3675,13 +3675,13 @@ static void radio_remove_interface(struct wpa_supplicant *wpa_s)
> >> -     wpa_s->radio = NULL;
> >>       if (!dl_list_empty(&radio->ifaces))
> >>               return; /* Interfaces remain for this radio */
> >>
> >>       wpa_printf(MSG_DEBUG, "Remove radio %s", radio->name);
> >>       eloop_cancel_timeout(radio_start_next_work, radio, NULL);
> >>       os_free(radio);
> >> +     wpa_s->radio = NULL;
> >
> > This radio_remove_interface() function is called only from
> > wpa_supplicant_deinit_iface() and this call is followed by the driver
> > interface deinit and os_free(wpa_s) before returning to eloop. In other
> > words, there is no way this specific wpa_s instance could be used in
> > wpa_supplicant_event_scan_results() after this unless there are some
> > much more severe issues of continuing to use freed memory.
> >
> > Allowing wpa_s->radio to continue to point to the radio in the
> > other-interfaces-remain case looks a bit suspicious since if there were
> > actual real uses of the wpa_s instance after this, I don't see what
> > would prevent that other remaining wpa_s instance from getting remove
> > and deleting the radio instance. After that, the wpa_s->radio on the
> > not-cleared-to-NULL interface would point to freed memory. Anyway, this
> > path should obviously not happen either due to that os_free(wpa_s)
> > following this call..
> 
> Actually wpa_s->radio is only being freed, when no other interface is
> using it, like
> wlanX. The patches only ensures radio is to null, when freed.

It doesn't do that. It ensures that wpa_s->radio is _not_ set to NULL
when the radio instance is not freed, but it in no way ensures that
wpa_s->radio gets set to NULL (for all wpa_s instances having used the
radio) when the radio gets removed. That's the part that I don't think
is appropriate since it could leave behind references to a freed radio
on other interfaces than the one that removed the radio.

Anyway, this change is not sufficient to address the issue even if it
happens to hide the crash in some cases. The wpa_s instance is already
freed when wpa_s->radio is used on the scan result handling part. I
fixed this issue by skipping the processing steps following removal of
the P2P group interface:
http://w1.fi/cgit/hostap/commit/?id=b0e669beebbb0d764c354f6ef7736c58f82681ec
diff mbox

Patch

diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 6ad09a8..0897294 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -3675,13 +3675,13 @@  static void radio_remove_interface(struct wpa_supplicant *wpa_s)
 		   wpa_s->ifname, radio->name);
 	dl_list_del(&wpa_s->radio_list);
 	radio_remove_works(wpa_s, NULL, 0);
-	wpa_s->radio = NULL;
 	if (!dl_list_empty(&radio->ifaces))
 		return; /* Interfaces remain for this radio */
 
 	wpa_printf(MSG_DEBUG, "Remove radio %s", radio->name);
 	eloop_cancel_timeout(radio_start_next_work, radio, NULL);
 	os_free(radio);
+	wpa_s->radio = NULL;
 }