Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion overlay/hostapd/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ OVERLAY_RELEASE:=1
include ../../include/overlay.mk

define Overlay/BuildConfig
# safe for all variants, no-op when CONFIG_EAP_TLS is not enabled
# Safe for all package variants except those using the 'internal' TLS backend.
# Only variants with CONFIG_EAP_TLS=y will actually build pinning support.
ifneq ($(SSL_VARIANT),internal)
DRIVER_MAKEOPTS += CONFIG_EAP_TLS_PINNING=y
endif
endef

$(eval $(call BuildPackageOverlay,network/services/hostapd))
120 changes: 100 additions & 20 deletions overlay/hostapd/patches/o000-hostapd-ht-operation-null-deref.patch
Original file line number Diff line number Diff line change
@@ -1,46 +1,126 @@
From 0e275f281a19e3175fd02335145600e338b378c5 Mon Sep 17 00:00:00 2001
From 5ca1f6193cc45051bf3e698d501fc6d6e7c718e3 Mon Sep 17 00:00:00 2001
From: Karsten Sperling <ksperling@apple.com>
Date: Wed, 29 Jul 2026 19:21:36 +1200
Subject: [PATCH] hostapd: Fix NULL deref in hostapd_eid_ht_operation
Subject: [PATCH] hostapd: Fix NULL deref and endianness in Extended NSS BW
code

hapd->iface->current_mode is NULL whenever hostapd runs without hw
feature data, which is not an error:
hostapd_setup_interface_complete_sync() continues when
hostapd_get_hw_features() fails (commented "Not all drivers support this
yet, so continue without hw feature data"), skipping the
170-hostapd-update-cfs0-and-cfs1-for-160MHz.patch adds an Extended NSS
BW check to hostapd_eid_ht_operation() and hostapd_eid_vht_operation();
both dereference hapd->iface->current_mode without a NULL check.

current_mode is NULL whenever hostapd runs without hw feature data,
which is not an error: hostapd_setup_interface_complete_sync() continues
when hostapd_get_hw_features() fails (commented "Not all drivers support
this yet, so continue without hw feature data"), skipping the
hostapd_select_hw_mode() block that would set current_mode. Interface
setup then proceeds to hostapd_start_beacon() and builds the beacon IEs
anyway. This is why hostapd_eid_erp_info(),
hostapd_dfs_start_channel_switch() and many other call sites all check
current_mode before dereferencing it.

Reaching it requires ieee80211n=1 (the function returns early otherwise)
together with no hw feature data, i.e. driver=none or any driver whose
get_hw_feature_data fails.
Reaching the HT case requires ieee80211n=1 (hostapd_eid_ht_operation()
returns early otherwise), the VHT case ieee80211ac=1 (all callers of
hostapd_eid_vht_operation() gate it on hostapd_is_vht_enabled()),
together with no hw feature data -- i.e. driver=none or any driver whose
get_hw_feature_data fails. The VHT case is particularly clearly
unintended: hostapd_eid_vht_capabilities(), called immediately before
hostapd_eid_vht_operation() at every call site, already returns early
when current_mode is absent, so hostapd correctly omits the VHT
Capabilities element and then crashes building VHT Operation.

Treat an absent current_mode as advertising no Extended NSS BW support,
which leaves both elements identical to what upstream emitted before the
check was introduced.

Treat an absent current_mode as advertising no VHT capabilities, which
leaves the resulting HT Operation element identical to what upstream
emitted before the Extended NSS BW check was introduced.
Also fix misplaced host_to_le32() calls in the same patch:
iface->current_mode->vht_capab and the VHT_CAP_* constants are both host
byte order (u32), so can be compared / masked directly without the
detour through an le32 local. However in hostapd_eid_vht_capabilities()
the vht_capabilities_info being built is le32, so constants need
swapping before application. This endianness issue is not expected to
affect any OpenWrt target in practice, since the radios that support 160
/ 80+80 channels are on little-endian platforms.

Signed-off-by: Karsten Sperling <ksperling@apple.com>
---
src/ap/ieee802_11_ht.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
src/ap/ieee802_11_ht.c | 7 +++----
src/ap/ieee802_11_vht.c | 11 +++++------
2 files changed, 8 insertions(+), 10 deletions(-)

diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 77b7907e7..47e9ea390 100644
index 77b7907e7..9661733fe 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -145,7 +145,8 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
@@ -127,7 +127,6 @@ no_update:
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
{
struct ieee80211_ht_operation *oper;
- le32 vht_capabilities_info;
u8 *pos = eid;
u8 chwidth;

@@ -145,10 +144,10 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
oper->operation_mode = host_to_le16(hapd->iface->ht_op_mode);
set_ht_param(hapd, oper);

- vht_capabilities_info = host_to_le32(hapd->iface->current_mode->vht_capab);
+ vht_capabilities_info = host_to_le32(hapd->iface->current_mode ?
+ hapd->iface->current_mode->vht_capab : 0);
chwidth = hostapd_get_oper_chwidth(hapd->iconf);
if (vht_capabilities_info & VHT_CAP_EXTENDED_NSS_BW_SUPPORT
- if (vht_capabilities_info & VHT_CAP_EXTENDED_NSS_BW_SUPPORT
- && ((chwidth == CHANWIDTH_160MHZ) || (chwidth == CHANWIDTH_80P80MHZ))) {
+ if (hapd->iface->current_mode &&
+ (hapd->iface->current_mode->vht_capab & VHT_CAP_EXTENDED_NSS_BW_SUPPORT) &&
+ ((chwidth == CHANWIDTH_160MHZ) || (chwidth == CHANWIDTH_80P80MHZ))) {
oper->operation_mode = host_to_le16(hapd->iconf->vht_oper_centr_freq_seg0_idx << 5);
}

diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index f77cbdb7e..226c30319 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -65,14 +65,14 @@ u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts)
}

chwidth = hostapd_get_oper_chwidth(hapd->iconf);
- if (((host_to_le32(mode->vht_capab)) & VHT_CAP_EXTENDED_NSS_BW_SUPPORT)
+ if ((mode->vht_capab & VHT_CAP_EXTENDED_NSS_BW_SUPPORT)
&& ((chwidth == CHANWIDTH_160MHZ) || (chwidth == CHANWIDTH_80P80MHZ))) {
- cap->vht_capabilities_info |= VHT_CAP_EXTENDED_NSS_BW_SUPPORT;
+ cap->vht_capabilities_info |= host_to_le32(VHT_CAP_EXTENDED_NSS_BW_SUPPORT);
cap->vht_capabilities_info &= ~(host_to_le32(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ));
cap->vht_capabilities_info &= ~(host_to_le32(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ));
cap->vht_capabilities_info &= ~(host_to_le32(VHT_CAP_SUPP_CHAN_WIDTH_MASK));
} else {
- cap->vht_capabilities_info &= ~VHT_CAP_EXTENDED_NSS_BW_SUPPORT_MASK;
+ cap->vht_capabilities_info &= ~(host_to_le32(VHT_CAP_EXTENDED_NSS_BW_SUPPORT_MASK));
}

/* Supported MCS set comes from hw */
@@ -87,7 +87,6 @@ u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts)
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
{
struct ieee80211_vht_operation *oper;
- le32 vht_capabilities_info;
u8 *pos = eid;
enum oper_chan_width oper_chwidth =
hostapd_get_oper_chwidth(hapd->iconf);
@@ -126,7 +125,6 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
oper->vht_op_info_chan_center_freq_seg1_idx = seg1;

oper->vht_op_info_chwidth = oper_chwidth;
- vht_capabilities_info = host_to_le32(hapd->iface->current_mode->vht_capab);
if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ) {
/*
* Convert 160 MHz channel width to new style as interop
@@ -141,7 +139,8 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
else
oper->vht_op_info_chan_center_freq_seg0_idx += 8;

- if (vht_capabilities_info & VHT_CAP_EXTENDED_NSS_BW_SUPPORT)
+ if (hapd->iface->current_mode &&
+ (hapd->iface->current_mode->vht_capab & VHT_CAP_EXTENDED_NSS_BW_SUPPORT))
oper->vht_op_info_chan_center_freq_seg1_idx = 0;
} else if (oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) {
/*
--
2.50.1 (Apple Git-155)

21 changes: 11 additions & 10 deletions overlay/hostapd/patches/o001-radius-server-accept-attr-fixes.patch
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
From 8a3ff9d9f228a40de81d2b91ac77beef7265aea8 Mon Sep 17 00:00:00 2001
From 4e351c1e65e0c1590d59bfbe6ef05d4555ffc7c3 Mon Sep 17 00:00:00 2001
From: Karsten Sperling <ksperling@apple.com>
Date: Sun, 9 Aug 2026 02:25:05 +1200
Subject: [PATCH] RADIUS server: Fix accept_attr leak, allocation size and NULL
handling
Subject: [PATCH] RADIUS server: accept_attr leak, alloc size, NULL handling

radius_server_get_eap_user() is the get_eap_user callback, so it runs
for every EAP user lookup and reassigns sess->accept_attr each time,
Expand All @@ -21,11 +20,11 @@ session.

Signed-off-by: Karsten Sperling <ksperling@apple.com>
---
src/radius/radius_server.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
src/radius/radius_server.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 44b4312e3..23d9a9333 100644
index 44b4312e3..c65c1bfa4 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -554,7 +554,7 @@ radius_server_copy_attr(const struct hostapd_radius_attr *data)
Expand All @@ -48,14 +47,16 @@ index 44b4312e3..23d9a9333 100644

sess->username = os_malloc(user_len * 4 + 1);
if (sess->username == NULL) {
@@ -2370,7 +2374,10 @@ static int radius_server_get_eap_user(void *ctx, const u8 *identity,
@@ -2370,7 +2374,11 @@ static int radius_server_get_eap_user(void *ctx, const u8 *identity,
ret = data->get_eap_user(data->conf_ctx, identity, identity_len,
phase2, user);
if (ret == 0 && user) {
+ os_free(sess->accept_attr);
sess->accept_attr = radius_server_copy_attr(user->accept_attr);
+ if (sess->accept_attr == NULL)
- sess->accept_attr = radius_server_copy_attr(user->accept_attr);
+ struct radius_accept_attr *attr = radius_server_copy_attr(user->accept_attr);
+ if (attr == NULL)
+ return -1;
+ os_free(sess->accept_attr);
+ sess->accept_attr = attr;
sess->macacl = user->macacl;
sess->t_c_timestamp = user->t_c_timestamp;
}
Expand Down
12 changes: 6 additions & 6 deletions overlay/hostapd/patches/o103-eap-tls-server-cert-pinning.patch
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
From e52755c05ab4d48f63bd9ae0b56fb10d0477e628 Mon Sep 17 00:00:00 2001
From 13eaad49ffca32ee48ed6ec0303415f568bf55bb Mon Sep 17 00:00:00 2001
From: Karsten Sperling <ksperling@apple.com>
Date: Fri, 3 Jul 2026 23:12:12 +1200
Subject: [PATCH] EAP-TLS server: Add support for client cert pinning
Expand Down Expand Up @@ -59,10 +59,10 @@ Signed-off-by: Karsten Sperling <ksperling@apple.com>
create mode 100644 tests/hwsim/test_ap_eap_tls_cert_pin.py

diff --git a/hostapd/Makefile b/hostapd/Makefile
index a7ebc534f..ee4e18079 100644
index c277d070a..361e1a8ba 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -434,6 +434,10 @@ ifdef CONFIG_EAP_TLS
@@ -438,6 +438,10 @@ ifdef CONFIG_EAP_TLS
CFLAGS += -DEAP_SERVER_TLS
OBJS += ../src/eap_server/eap_server_tls.o
TLS_FUNCS=y
Expand Down Expand Up @@ -211,10 +211,10 @@ index c0e903040..b58a65303 100644
}

diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 349e489c6..90bc43d70 100644
index b0c386053..5f0b579a0 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -2389,6 +2389,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
@@ -2391,6 +2391,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,

os_memset(user, 0, sizeof(*user));
user->phase2 = phase2;
Expand Down Expand Up @@ -492,7 +492,7 @@ index 81d1eedd4..7174cfb7a 100644
session_ctx[7] = (u8) eap_type;
if (tls_connection_set_verify(sm->cfg->ssl_ctx, data->conn, verify_peer,
diff --git a/tests/hwsim/example-hostapd.config b/tests/hwsim/example-hostapd.config
index 58b07513b..a2b526a27 100644
index 383368bfd..20561a410 100644
--- a/tests/hwsim/example-hostapd.config
+++ b/tests/hwsim/example-hostapd.config
@@ -14,6 +14,7 @@ CONFIG_EAP=y
Expand Down