diff mbox series

[2/3] Use control port over nl80211 also for rx path

Message ID 20200106152107.124745-3-markus.theil@tu-ilmenau.de
State Changes Requested
Headers show
Series nl80211 control port rx path | expand

Commit Message

Markus Theil Jan. 6, 2020, 3:21 p.m. UTC
This patch is based on the previous patch from Brendan Jackman
and adds rx support over nl80211. In order to receive frames
over the event nl socket the following operations have to be
performed over this socket (kernel has checks):
  - associate
  - connect
  - set beacon
  - del beacon
  - disconnect
  - deauthenticate
  - ibss join
  - mesh join

Therefore a new fn is added, which sets the corresponding
control port options (send_and_recv_as_owner). These options
have no effect on disconnent and are therefore left as they are,
but the same socket which was used initially has to be used again.

Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de>
---
 src/drivers/driver_nl80211.c | 69 ++++++++++++++++++++++++++++--------
 src/drivers/driver_nl80211.h |  4 +++
 2 files changed, 58 insertions(+), 15 deletions(-)

Comments

Jouni Malinen Jan. 6, 2020, 8:32 p.m. UTC | #1
On Mon, Jan 06, 2020 at 04:21:06PM +0100, Markus Theil wrote:
> This patch is based on the previous patch from Brendan Jackman
> and adds rx support over nl80211. In order to receive frames
> over the event nl socket the following operations have to be
> performed over this socket (kernel has checks):
>   - associate
>   - connect
>   - set beacon
>   - del beacon
>   - disconnect
>   - deauthenticate
>   - ibss join
>   - mesh join
> 
> Therefore a new fn is added, which sets the corresponding
> control port options (send_and_recv_as_owner). These options
> have no effect on disconnent and are therefore left as they are,
> but the same socket which was used initially has to be used again.

This seems to result in NULL pointer dereferences and/or use of freed
data killing wpa_supplicant in number of hwsim test cases. For example,
grpform_c shows this with driver event delivered to an interface that
was just removed:

Another issue is in ap_cipher_tkip_countermeasures_sta reporting
unexpected disconnection reason and wpas_ctrl_ipaddr reporting "IP
address not in STATUS output" (which is due to closing of wpa_s->l2
which is apparently still needed here for l2_packet_get_ip_addr()).

In total, there was about 80 failed test cases, but some of these are
likely triggered by more severe issues in previously executed test cases
like that NULL pointer killing a process.
diff mbox series

Patch

diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index ddbd4b4bf..effb0504e 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -437,6 +437,41 @@  int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
 			     valid_handler, valid_data);
 }
 
+static int nl80211_send_and_recv_as_owner(struct wpa_driver_nl80211_data *drv,
+					     struct nl_msg *msg)
+{
+	int ret = -1;
+
+	/* in order to be able to receive control port messages over nl80211
+	 * we have to send the initial/final command over the event socket,
+	 * which is registered in nl80211 & eloop for receiving events.
+	 *
+	 * kernel has initial checks for this (in nl80211.c) like:
+	 *     validate_pae_over_nl80211(...)
+	 * or final checks like:
+	 *     dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid
+	 */
+	if (drv->capa.flags & WPA_DRIVER_FLAGS_CONTROL_PORT) {
+		if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_OVER_NL80211) ||
+		    nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER) ||
+		    nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
+				ETH_P_PAE))
+			goto out;
+		struct nl_sock *handle;
+
+		handle = (void *) (((intptr_t) drv->global->nl_event) ^
+			 ELOOP_SOCKET_INVALID);
+
+		ret = send_and_recv(drv->global, handle, msg,
+				    NULL, NULL);
+	} else {
+		ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	}
+
+out:
+	return ret;
+}
+
 
 struct family_data {
 	const char *group;
@@ -2042,11 +2077,14 @@  static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
 	if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1, driver_params))
 		goto failed;
 
-	drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
-	if (drv->eapol_tx_sock < 0)
-		goto failed;
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_CONTROL_PORT)) {
+		drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
+		if (drv->eapol_tx_sock < 0)
+			goto failed;
+	}
 
-	if (drv->data_tx_status) {
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_CONTROL_PORT) &&
+	    drv->data_tx_status) {
 		int enabled = 1;
 
 		if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
@@ -2729,7 +2767,7 @@  static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss)
 		   drv->ifindex);
 	nl80211_put_wiphy_data_ap(bss);
 	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON);
-	return send_and_recv_msgs(drv, msg, NULL, NULL);
+	return nl80211_send_and_recv_as_owner(drv, msg);
 }
 
 
@@ -3296,7 +3334,7 @@  int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
 	if (nl_connect)
 		ret = send_and_recv(drv->global, nl_connect, msg, NULL, NULL);
 	else
-		ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+		ret = nl80211_send_and_recv_as_owner(drv, msg);
 	if (ret) {
 		wpa_dbg(drv->ctx, MSG_DEBUG,
 			"nl80211: MLME command failed: reason=%u ret=%d (%s)",
@@ -4315,7 +4353,8 @@  static int wpa_driver_nl80211_set_ap(void *priv,
 	}
 #endif /* CONFIG_IEEE80211AX */
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	ret = nl80211_send_and_recv_as_owner(drv, msg);
+
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
 			   ret, strerror(-ret));
@@ -4938,7 +4977,8 @@  static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
 	 * Tell cfg80211 that the interface belongs to the socket that created
 	 * it, and the interface should be deleted when the socket is closed.
 	 */
-	if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_CONTROL_PORT) &&
+	    nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
 		goto fail;
 
 	ret = send_and_recv_msgs(drv, msg, handler, arg);
@@ -5335,7 +5375,7 @@  static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
 	int ret;
 
 	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_IBSS);
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	ret = nl80211_send_and_recv_as_owner(drv, msg);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
 			   "(%s)", ret, strerror(-ret));
@@ -5467,7 +5507,7 @@  retry:
 	if (ret < 0)
 		goto fail;
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	ret = nl80211_send_and_recv_as_owner(drv, msg);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
@@ -5872,8 +5912,7 @@  skip_auth_type:
 		ret = send_and_recv(drv->global, nl_connect, msg,
 				    NULL, (void *) -1);
 	else
-		ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
-
+		ret = nl80211_send_and_recv_as_owner(drv, msg);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
@@ -5989,7 +6028,7 @@  static int wpa_driver_nl80211_associate(
 			goto fail;
 	}
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	ret = nl80211_send_and_recv_as_owner(drv, msg);
 	msg = NULL;
 	if (ret) {
 		wpa_dbg(drv->ctx, MSG_DEBUG,
@@ -9830,7 +9869,7 @@  static int nl80211_join_mesh(struct i802_bss *bss,
 	if (nl80211_put_mesh_config(msg, &params->conf) < 0)
 		goto fail;
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	ret = nl80211_send_and_recv_as_owner(drv, msg);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)",
@@ -9887,7 +9926,7 @@  static int wpa_driver_nl80211_leave_mesh(void *priv)
 
 	wpa_printf(MSG_DEBUG, "nl80211: mesh leave (ifindex=%d)", drv->ifindex);
 	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_MESH);
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	ret = nl80211_send_and_recv_as_owner(drv, msg);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)",
 			   ret, strerror(-ret));
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index e4d81b125..98ace7d1d 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -224,6 +224,10 @@  struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd);
 int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg,
 		       int (*valid_handler)(struct nl_msg *, void *),
 		       void *valid_data);
+int send_and_recv_msgs_event(struct wpa_driver_nl80211_data *drv,
+			     struct nl_msg *msg,
+			     int (*valid_handler)(struct nl_msg *, void *),
+			     void *valid_data);
 int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
 			 const char *ifname, enum nl80211_iftype iftype,
 			 const u8 *addr, int wds,