* [PATCH 1/3] Fix overread in PREQ frame processing [not found] <8f0a2488540f4a65ea4d837a06225a27a10cc305.camel@sipsolutions.net> @ 2026-05-08 22:59 ` Masashi Honma 2026-05-08 22:59 ` [PATCH 2/3] Fix overread in PREP " Masashi Honma ` (2 more replies) 0 siblings, 3 replies; 10+ messages in thread From: Masashi Honma @ 2026-05-08 22:59 UTC (permalink / raw) To: linux-wireless; +Cc: johannes, Masashi Honma When the AF flag is enabled, hwmp_preq_frame_process() overreads target_addr by 2 bytes. Since this occurs within the socket buffer, it does not read across memory boundaries and therefore poses no security risk; however, we will fix it as a precaution. In this fix, a new function mesh_path_parse_request_frame() is established to separate the implementation of frame format validation and the check for unsupported features. This is intended to facilitate future work when implementing the currently unsupported parts. Assisted-by: Claude:Sonnet 4.6 Signed-off-by: Masashi Honma <masashi.honma@gmail.com> --- net/mac80211/mesh.h | 1 + net/mac80211/mesh_hwmp.c | 35 +++++++++++++++++++++++++++++++++-- net/mac80211/parse.c | 7 +++++-- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 3f9664e4e00c..331d2d774196 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -317,6 +317,7 @@ struct mesh_path * mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx); void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop); void mesh_path_expire(struct ieee80211_sub_if_data *sdata); +u8 mesh_path_parse_request_frame(const u8 *pos, u8 elen); void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len); struct mesh_path * diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 9d89ebcce1c1..4239412d12c7 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -45,6 +45,7 @@ static inline u16 u16_field_get(const u8 *preq_elem, int offset, bool ae) #define PREQ_IE_ORIG_SN(x) u32_field_get(x, 13, 0) #define PREQ_IE_LIFETIME(x) u32_field_get(x, 17, AE_F_SET(x)) #define PREQ_IE_METRIC(x) u32_field_get(x, 21, AE_F_SET(x)) +#define PREQ_IE_TARGET_COUNT(x) (*(AE_F_SET(x) ? x + 31 : x + 25)) #define PREQ_IE_TARGET_F(x) (*(AE_F_SET(x) ? x + 32 : x + 26)) #define PREQ_IE_TARGET_ADDR(x) (AE_F_SET(x) ? x + 33 : x + 27) #define PREQ_IE_TARGET_SN(x) u32_field_get(x, 33, AE_F_SET(x)) @@ -924,6 +925,29 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, rcu_read_unlock(); } +/* IEEE Std 802.11-2016 9.4.2.113 PREQ element */ +u8 mesh_path_parse_request_frame(const u8 *pos, u8 elen) +{ + u8 target_count; + u8 expected_len; + + target_count = PREQ_IE_TARGET_COUNT(pos); + if (unlikely(target_count < 1 || target_count > 20)) + return IEEE80211_PARSE_ERR_UNEXPECTED_ELEM; + + expected_len = 1 /* Flags */ + 1 /* Hop Count */ + 1 /* Element TTL */ + + 4 /* Path Discovery ID */ + + 6 /* Originator Mesh STA Address */ + + 4 /* Originator HWMP Sequence Number */ + + (AE_F_SET(pos) ? 6 : 0) /* Originator External Address */ + + 4 /* Lifetime */ + 4 /* Metric */ + 1 + /* Target Count */ + + target_count * (1 /* Per Target Flags */ + + 6 /* Target Address */ + 4 /* Target HWMP Sequence Number */); + if (unlikely(elen != expected_len)) + return IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + + return 0; +} void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len) @@ -932,6 +956,7 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, size_t baselen; u32 path_metric; struct sta_info *sta; + u8 target_count; /* need action_code */ if (len < IEEE80211_MIN_ACTION_SIZE(mesh_action)) @@ -955,9 +980,15 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, return; if (elems->preq) { - if (elems->preq_len != 37) - /* Right now we support just 1 destination and no AE */ + /* Right now we do not support AE (Address Extension) */ + if (AE_F_SET(elems->preq)) goto free; + + /* Right now we only supports 1 target */ + target_count = PREQ_IE_TARGET_COUNT(elems->preq); + if (target_count != 1) + goto free; + path_metric = hwmp_route_info_get(sdata, mgmt, elems->preq, MPATH_PREQ); if (path_metric) diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c index 5e61457be0f3..7a2abe676361 100644 --- a/net/mac80211/parse.c +++ b/net/mac80211/parse.c @@ -547,8 +547,11 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, elems->awake_window = (void *)pos; break; case WLAN_EID_PREQ: - elems->preq = pos; - elems->preq_len = elen; + elem_parse_failed = mesh_path_parse_request_frame(pos, elen); + if (likely(!elem_parse_failed)) { + elems->preq = pos; + elems->preq_len = elen; + } break; case WLAN_EID_PREP: elems->prep = pos; -- 2.43.0 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/3] Fix overread in PREP frame processing 2026-05-08 22:59 ` [PATCH 1/3] Fix overread in PREQ frame processing Masashi Honma @ 2026-05-08 22:59 ` Masashi Honma 2026-05-08 22:59 ` [PATCH 3/3] Fix PERR " Masashi Honma 2026-05-09 9:17 ` [PATCH 1/3] Fix overread in PREQ " Johannes Berg 2 siblings, 0 replies; 10+ messages in thread From: Masashi Honma @ 2026-05-08 22:59 UTC (permalink / raw) To: linux-wireless; +Cc: johannes, Masashi Honma When the AF flag is enabled, hwmp_prep_frame_process() overreads orig_addr by 2 bytes. Since this occurs within the socket buffer, it does not read across memory boundaries and therefore poses no security risk; however, we will fix it as a precaution. In this fix, a new function mesh_path_parse_reply_frame() is established to separate the implementation of frame format validation and the check for unsupported features. This is intended to facilitate future work when implementing the currently unsupported parts. Assisted-by: Claude:Sonnet 4.6 Signed-off-by: Masashi Honma <masashi.honma@gmail.com> --- net/mac80211/mesh.h | 1 + net/mac80211/mesh_hwmp.c | 24 ++++++++++++++++++++++-- net/mac80211/parse.c | 7 +++++-- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 331d2d774196..aba7ef59195a 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -318,6 +318,7 @@ mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx); void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop); void mesh_path_expire(struct ieee80211_sub_if_data *sdata); u8 mesh_path_parse_request_frame(const u8 *pos, u8 elen); +u8 mesh_path_parse_reply_frame(const u8 *pos, u8 elen); void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len); struct mesh_path * diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 4239412d12c7..9f903a2408f7 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -949,6 +949,25 @@ u8 mesh_path_parse_request_frame(const u8 *pos, u8 elen) return 0; } +/* IEEE Std 802.11-2016 9.4.2.114 PREP element */ +u8 mesh_path_parse_reply_frame(const u8 *pos, u8 elen) +{ + u8 expected_len; + + expected_len = 1 /* Flags */ + 1 /* Hop Count */ + 1 /* Element TTL */ + + 6 /* Target Mesh STA Address */ + + 4 /* Target HWMP Sequence Number */ + + (AE_F_SET(pos) ? 6 : 0) /* Target External Address */ + + 4 /* Lifetime */ + 4 /* Metric */ + + 6 /* Originator Mesh STA Address */ + + 4 /* Originator HWMP Sequence Number */; + + if (unlikely(elen != expected_len)) + return IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + + return 0; +} + void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len) { @@ -996,9 +1015,10 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, path_metric); } if (elems->prep) { - if (elems->prep_len != 31) - /* Right now we support no AE */ + /* Right now we do not support AE (Address Extension) */ + if (AE_F_SET(elems->prep)) goto free; + path_metric = hwmp_route_info_get(sdata, mgmt, elems->prep, MPATH_PREP); if (path_metric) diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c index 7a2abe676361..cdc549055242 100644 --- a/net/mac80211/parse.c +++ b/net/mac80211/parse.c @@ -554,8 +554,11 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, } break; case WLAN_EID_PREP: - elems->prep = pos; - elems->prep_len = elen; + elem_parse_failed = mesh_path_parse_reply_frame(pos, elen); + if (likely(!elem_parse_failed)) { + elems->prep = pos; + elems->prep_len = elen; + } break; case WLAN_EID_PERR: elems->perr = pos; -- 2.43.0 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/3] Fix PERR frame processing 2026-05-08 22:59 ` [PATCH 1/3] Fix overread in PREQ frame processing Masashi Honma 2026-05-08 22:59 ` [PATCH 2/3] Fix overread in PREP " Masashi Honma @ 2026-05-08 22:59 ` Masashi Honma 2026-05-09 9:17 ` [PATCH 1/3] Fix overread in PREQ " Johannes Berg 2 siblings, 0 replies; 10+ messages in thread From: Masashi Honma @ 2026-05-08 22:59 UTC (permalink / raw) To: linux-wireless; +Cc: johannes, Masashi Honma There are no issues with the PERR processing itself; however, to maintain consistency with the previous PREQ/PREP code modifications, I will create a new mesh_path_parse_error_frame() function to separately implement the frame format validation and the "not supported" check. Assisted-by: Claude:Sonnet 4.6 Signed-off-by: Masashi Honma <masashi.honma@gmail.com> --- net/mac80211/mesh.h | 1 + net/mac80211/mesh_hwmp.c | 48 ++++++++++++++++++++++++++++++++++++++-- net/mac80211/parse.c | 7 ++++-- 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index aba7ef59195a..610c34e35e64 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -319,6 +319,7 @@ void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop); void mesh_path_expire(struct ieee80211_sub_if_data *sdata); u8 mesh_path_parse_request_frame(const u8 *pos, u8 elen); u8 mesh_path_parse_reply_frame(const u8 *pos, u8 elen); +u8 mesh_path_parse_error_frame(const u8 *pos, u8 elen); void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len); struct mesh_path * diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 9f903a2408f7..2a293b771f79 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -62,6 +62,7 @@ static inline u16 u16_field_get(const u8 *preq_elem, int offset, bool ae) #define PREP_IE_TARGET_SN(x) u32_field_get(x, 9, 0) #define PERR_IE_TTL(x) (*(x)) +#define PERR_IE_NUMBER_OF_DST(x) (*(x + 1)) #define PERR_IE_TARGET_FLAGS(x) (*(x + 2)) #define PERR_IE_TARGET_ADDR(x) (x + 3) #define PERR_IE_TARGET_SN(x) u32_field_get(x, 9, 0) @@ -968,6 +969,42 @@ u8 mesh_path_parse_reply_frame(const u8 *pos, u8 elen) return 0; } +/* IEEE Std 802.11-2016 9.4.2.115 PERR element */ +u8 mesh_path_parse_error_frame(const u8 *pos, u8 elen) +{ + u8 number_of_dst; + u8 expected_len; + const u8 *start; + int i; + + number_of_dst = PERR_IE_NUMBER_OF_DST(pos); + if (unlikely(number_of_dst < 1 || number_of_dst > 19)) + return IEEE80211_PARSE_ERR_UNEXPECTED_ELEM; + + start = pos; + expected_len = 1 /* Element TTL */ + 1 /* Number of Destinations */; + pos += 2; + + for (i = 0; i < number_of_dst; i++) { + u8 dst_len; + + if (unlikely(pos - start >= elen)) + return IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + + dst_len = 1 /* Flags */ + 6 /* Destination Address */ + + 4 /* HWMP Sequence Number */ + + (AE_F_SET(pos) ? 6 : 0) /* Destination External Address */ + + 2 /* Reason Code */; + expected_len += dst_len; + pos += dst_len; + } + + if (unlikely(elen != expected_len)) + return IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + + return 0; +} + void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len) { @@ -976,6 +1013,7 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, u32 path_metric; struct sta_info *sta; u8 target_count; + u8 number_of_dst; /* need action_code */ if (len < IEEE80211_MIN_ACTION_SIZE(mesh_action)) @@ -1026,9 +1064,15 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, path_metric); } if (elems->perr) { - if (elems->perr_len != 15) - /* Right now we support only one destination per PERR */ + /* Right now we support only one destination per PERR */ + number_of_dst = PERR_IE_NUMBER_OF_DST(elems->perr); + if (number_of_dst != 1) goto free; + + /* Right now we do not support AE (Address Extension) */ + if (PERR_IE_TARGET_FLAGS(elems->perr) & AE_F) + goto free; + hwmp_perr_frame_process(sdata, mgmt, elems->perr); } if (elems->rann) diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c index cdc549055242..dfc326db0471 100644 --- a/net/mac80211/parse.c +++ b/net/mac80211/parse.c @@ -561,8 +561,11 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, } break; case WLAN_EID_PERR: - elems->perr = pos; - elems->perr_len = elen; + elem_parse_failed = mesh_path_parse_error_frame(pos, elen); + if (likely(!elem_parse_failed)) { + elems->perr = pos; + elems->perr_len = elen; + } break; case WLAN_EID_RANN: if (elen >= sizeof(struct ieee80211_rann_ie)) -- 2.43.0 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 1/3] Fix overread in PREQ frame processing 2026-05-08 22:59 ` [PATCH 1/3] Fix overread in PREQ frame processing Masashi Honma 2026-05-08 22:59 ` [PATCH 2/3] Fix overread in PREP " Masashi Honma 2026-05-08 22:59 ` [PATCH 3/3] Fix PERR " Masashi Honma @ 2026-05-09 9:17 ` Johannes Berg 2026-05-09 23:41 ` Masashi Honma 2 siblings, 1 reply; 10+ messages in thread From: Johannes Berg @ 2026-05-09 9:17 UTC (permalink / raw) To: Masashi Honma, linux-wireless On Sat, 2026-05-09 at 07:59 +0900, Masashi Honma wrote: > > +/* IEEE Std 802.11-2016 9.4.2.113 PREQ element */ > +u8 mesh_path_parse_request_frame(const u8 *pos, u8 elen) > +{ > + u8 target_count; > + u8 expected_len; > + > + target_count = PREQ_IE_TARGET_COUNT(pos); > + if (unlikely(target_count < 1 || target_count > 20)) > + return IEEE80211_PARSE_ERR_UNEXPECTED_ELEM; not sure the likely/unlikely really is worth anything there - we don't process *that* many frames. > + > + expected_len = 1 /* Flags */ + 1 /* Hop Count */ + 1 /* Element TTL */ + > + 4 /* Path Discovery ID */ + > + 6 /* Originator Mesh STA Address */ + > + 4 /* Originator HWMP Sequence Number */ + > + (AE_F_SET(pos) ? 6 : 0) /* Originator External Address */ + > + 4 /* Lifetime */ + 4 /* Metric */ + 1 + /* Target Count */ + > + target_count * (1 /* Per Target Flags */ + > + 6 /* Target Address */ + 4 /* Target HWMP Sequence Number */); > + if (unlikely(elen != expected_len)) > + return IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; I think there's a case to be made for doing this like many others, in an inline in ieee80211-mesh.h, and calling it ..._size_ok() with a bool return. > +++ b/net/mac80211/parse.c > @@ -547,8 +547,11 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, > elems->awake_window = (void *)pos; > break; > case WLAN_EID_PREQ: > - elems->preq = pos; > - elems->preq_len = elen; > + elem_parse_failed = mesh_path_parse_request_frame(pos, elen); > + if (likely(!elem_parse_failed)) { that would also fix the build issue here if mesh isn't compiled in. (and also here, not sure about likely/unlikely, doesn't really seem worth it, and under attack maybe the failure becomes likely?) johannes ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/3] Fix overread in PREQ frame processing 2026-05-09 9:17 ` [PATCH 1/3] Fix overread in PREQ " Johannes Berg @ 2026-05-09 23:41 ` Masashi Honma 2026-05-09 23:41 ` [PATCH 2/3] Fix overread in PREP " Masashi Honma ` (2 more replies) 0 siblings, 3 replies; 10+ messages in thread From: Masashi Honma @ 2026-05-09 23:41 UTC (permalink / raw) To: linux-wireless; +Cc: johannes, Masashi Honma When the AF flag is enabled, hwmp_preq_frame_process() overreads target_addr by 2 bytes. Since this occurs within the socket buffer, it does not read across memory boundaries and therefore poses no security risk; however, we will fix it as a precaution. In this fix, a new function mesh_path_parse_request_frame() is established to separate the implementation of frame format validation and the check for unsupported features. This is intended to facilitate future work when implementing the currently unsupported parts. Assisted-by: Claude:Sonnet 4.6 Signed-off-by: Masashi Honma <masashi.honma@gmail.com> --- include/linux/ieee80211-mesh.h | 56 ++++++++++++++++++++++++++++++++++ net/mac80211/mesh_hwmp.c | 42 ++++++------------------- net/mac80211/parse.c | 9 ++++-- 3 files changed, 72 insertions(+), 35 deletions(-) diff --git a/include/linux/ieee80211-mesh.h b/include/linux/ieee80211-mesh.h index 4b829bcb38b6..8ff68cf539ff 100644 --- a/include/linux/ieee80211-mesh.h +++ b/include/linux/ieee80211-mesh.h @@ -34,6 +34,38 @@ struct ieee80211s_hdr { #define MESH_FLAGS_AE 0x3 #define MESH_FLAGS_PS_DEEP 0x4 +/* HWMP IE processing macros */ +#define AE_F (1<<6) +#define AE_F_SET(x) (*x & AE_F) +#define PREQ_IE_FLAGS(x) (*(x)) +#define PREQ_IE_HOPCOUNT(x) (*(x + 1)) +#define PREQ_IE_TTL(x) (*(x + 2)) +#define PREQ_IE_PREQ_ID(x) u32_field_get(x, 3, 0) +#define PREQ_IE_ORIG_ADDR(x) (x + 7) +#define PREQ_IE_ORIG_SN(x) u32_field_get(x, 13, 0) +#define PREQ_IE_LIFETIME(x) u32_field_get(x, 17, AE_F_SET(x)) +#define PREQ_IE_METRIC(x) u32_field_get(x, 21, AE_F_SET(x)) +#define PREQ_IE_TARGET_COUNT(x) (*(AE_F_SET(x) ? x + 31 : x + 25)) +#define PREQ_IE_TARGET_F(x) (*(AE_F_SET(x) ? x + 32 : x + 26)) +#define PREQ_IE_TARGET_ADDR(x) (AE_F_SET(x) ? x + 33 : x + 27) +#define PREQ_IE_TARGET_SN(x) u32_field_get(x, 33, AE_F_SET(x)) + +#define PREP_IE_FLAGS(x) PREQ_IE_FLAGS(x) +#define PREP_IE_HOPCOUNT(x) PREQ_IE_HOPCOUNT(x) +#define PREP_IE_TTL(x) PREQ_IE_TTL(x) +#define PREP_IE_ORIG_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21) +#define PREP_IE_ORIG_SN(x) u32_field_get(x, 27, AE_F_SET(x)) +#define PREP_IE_LIFETIME(x) u32_field_get(x, 13, AE_F_SET(x)) +#define PREP_IE_METRIC(x) u32_field_get(x, 17, AE_F_SET(x)) +#define PREP_IE_TARGET_ADDR(x) (x + 3) +#define PREP_IE_TARGET_SN(x) u32_field_get(x, 9, 0) + +#define PERR_IE_TTL(x) (*(x)) +#define PERR_IE_TARGET_FLAGS(x) (*(x + 2)) +#define PERR_IE_TARGET_ADDR(x) (x + 3) +#define PERR_IE_TARGET_SN(x) u32_field_get(x, 9, 0) +#define PERR_IE_TARGET_RCODE(x) u16_field_get(x, 13, 0) + /** * enum ieee80211_preq_flags - mesh PREQ element flags * @@ -227,4 +259,28 @@ enum ieee80211_root_mode_identifier { IEEE80211_PROACTIVE_RANN = 4, }; +/* IEEE Std 802.11-2016 9.4.2.113 PREQ element */ +static inline bool ieee80211_mesh_preq_size_ok(const u8 *pos, u8 elen) +{ + u8 target_count; + u8 needed; + + target_count = PREQ_IE_TARGET_COUNT(pos); + if (target_count < 1 || target_count > 20) + return false; + + needed = 1 /* Flags */ + 1 /* Hop Count */ + 1 /* Element TTL */ + + 4 /* Path Discovery ID */ + + 6 /* Originator Mesh STA Address */ + + 4 /* Originator HWMP Sequence Number */ + + (AE_F_SET(pos) ? 6 : 0) /* Originator External Address */ + + 4 /* Lifetime */ + 4 /* Metric */ + 1 + /* Target Count */ + + target_count * (1 /* Per Target Flags */ + + 6 /* Target Address */ + 4 /* Target HWMP Sequence Number */); + if (elen != needed) + return false; + + return true; +} + #endif /* LINUX_IEEE80211_MESH_H */ diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 9d89ebcce1c1..a4984b015995 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -35,37 +35,6 @@ static inline u16 u16_field_get(const u8 *preq_elem, int offset, bool ae) } /* HWMP IE processing macros */ -#define AE_F (1<<6) -#define AE_F_SET(x) (*x & AE_F) -#define PREQ_IE_FLAGS(x) (*(x)) -#define PREQ_IE_HOPCOUNT(x) (*(x + 1)) -#define PREQ_IE_TTL(x) (*(x + 2)) -#define PREQ_IE_PREQ_ID(x) u32_field_get(x, 3, 0) -#define PREQ_IE_ORIG_ADDR(x) (x + 7) -#define PREQ_IE_ORIG_SN(x) u32_field_get(x, 13, 0) -#define PREQ_IE_LIFETIME(x) u32_field_get(x, 17, AE_F_SET(x)) -#define PREQ_IE_METRIC(x) u32_field_get(x, 21, AE_F_SET(x)) -#define PREQ_IE_TARGET_F(x) (*(AE_F_SET(x) ? x + 32 : x + 26)) -#define PREQ_IE_TARGET_ADDR(x) (AE_F_SET(x) ? x + 33 : x + 27) -#define PREQ_IE_TARGET_SN(x) u32_field_get(x, 33, AE_F_SET(x)) - - -#define PREP_IE_FLAGS(x) PREQ_IE_FLAGS(x) -#define PREP_IE_HOPCOUNT(x) PREQ_IE_HOPCOUNT(x) -#define PREP_IE_TTL(x) PREQ_IE_TTL(x) -#define PREP_IE_ORIG_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21) -#define PREP_IE_ORIG_SN(x) u32_field_get(x, 27, AE_F_SET(x)) -#define PREP_IE_LIFETIME(x) u32_field_get(x, 13, AE_F_SET(x)) -#define PREP_IE_METRIC(x) u32_field_get(x, 17, AE_F_SET(x)) -#define PREP_IE_TARGET_ADDR(x) (x + 3) -#define PREP_IE_TARGET_SN(x) u32_field_get(x, 9, 0) - -#define PERR_IE_TTL(x) (*(x)) -#define PERR_IE_TARGET_FLAGS(x) (*(x + 2)) -#define PERR_IE_TARGET_ADDR(x) (x + 3) -#define PERR_IE_TARGET_SN(x) u32_field_get(x, 9, 0) -#define PERR_IE_TARGET_RCODE(x) u16_field_get(x, 13, 0) - #define MSEC_TO_TU(x) (x*1000/1024) #define SN_GT(x, y) ((s32)(y - x) < 0) #define SN_LT(x, y) ((s32)(x - y) < 0) @@ -932,6 +901,7 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, size_t baselen; u32 path_metric; struct sta_info *sta; + u8 target_count; /* need action_code */ if (len < IEEE80211_MIN_ACTION_SIZE(mesh_action)) @@ -955,9 +925,15 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, return; if (elems->preq) { - if (elems->preq_len != 37) - /* Right now we support just 1 destination and no AE */ + /* Right now we do not support AE (Address Extension) */ + if (AE_F_SET(elems->preq)) + goto free; + + /* Right now we only supports 1 target */ + target_count = PREQ_IE_TARGET_COUNT(elems->preq); + if (target_count != 1) goto free; + path_metric = hwmp_route_info_get(sdata, mgmt, elems->preq, MPATH_PREQ); if (path_metric) diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c index 5e61457be0f3..9e52cc48fc18 100644 --- a/net/mac80211/parse.c +++ b/net/mac80211/parse.c @@ -547,8 +547,13 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, elems->awake_window = (void *)pos; break; case WLAN_EID_PREQ: - elems->preq = pos; - elems->preq_len = elen; + if (ieee80211_mesh_preq_size_ok(pos, elen)) { + elems->preq = pos; + elems->preq_len = elen; + } else { + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + } break; case WLAN_EID_PREP: elems->prep = pos; -- 2.43.0 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/3] Fix overread in PREP frame processing 2026-05-09 23:41 ` Masashi Honma @ 2026-05-09 23:41 ` Masashi Honma 2026-05-09 23:41 ` [PATCH 3/3] Fix PERR " Masashi Honma 2026-05-11 7:47 ` [PATCH 1/3] Fix overread in PREQ " Johannes Berg 2 siblings, 0 replies; 10+ messages in thread From: Masashi Honma @ 2026-05-09 23:41 UTC (permalink / raw) To: linux-wireless; +Cc: johannes, Masashi Honma When the AF flag is enabled, hwmp_prep_frame_process() overreads orig_addr by 2 bytes. Since this occurs within the socket buffer, it does not read across memory boundaries and therefore poses no security risk; however, we will fix it as a precaution. In this fix, a new function mesh_path_parse_reply_frame() is established to separate the implementation of frame format validation and the check for unsupported features. This is intended to facilitate future work when implementing the currently unsupported parts. Assisted-by: Claude:Sonnet 4.6 Signed-off-by: Masashi Honma <masashi.honma@gmail.com> --- include/linux/ieee80211-mesh.h | 18 ++++++++++++++++++ net/mac80211/mesh_hwmp.c | 5 +++-- net/mac80211/parse.c | 9 +++++++-- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/include/linux/ieee80211-mesh.h b/include/linux/ieee80211-mesh.h index 8ff68cf539ff..ddbf475c1cc8 100644 --- a/include/linux/ieee80211-mesh.h +++ b/include/linux/ieee80211-mesh.h @@ -283,4 +283,22 @@ static inline bool ieee80211_mesh_preq_size_ok(const u8 *pos, u8 elen) return true; } +/* IEEE Std 802.11-2016 9.4.2.114 PREP element */ +static inline bool ieee80211_mesh_prep_size_ok(const u8 *pos, u8 elen) +{ + u8 needed; + + needed = 1 /* Flags */ + 1 /* Hop Count */ + 1 /* Element TTL */ + + 6 /* Target Mesh STA Address */ + + 4 /* Target HWMP Sequence Number */ + + (AE_F_SET(pos) ? 6 : 0) /* Target External Address */ + + 4 /* Lifetime */ + 4 /* Metric */ + + 6 /* Originator Mesh STA Address */ + + 4 /* Originator HWMP Sequence Number */; + if (elen != needed) + return false; + + return true; +} + #endif /* LINUX_IEEE80211_MESH_H */ diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index a4984b015995..c70cfc2d6299 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -941,9 +941,10 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, path_metric); } if (elems->prep) { - if (elems->prep_len != 31) - /* Right now we support no AE */ + /* Right now we do not support AE (Address Extension) */ + if (AE_F_SET(elems->prep)) goto free; + path_metric = hwmp_route_info_get(sdata, mgmt, elems->prep, MPATH_PREP); if (path_metric) diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c index 9e52cc48fc18..bbd1e1bc77b4 100644 --- a/net/mac80211/parse.c +++ b/net/mac80211/parse.c @@ -556,8 +556,13 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, } break; case WLAN_EID_PREP: - elems->prep = pos; - elems->prep_len = elen; + if (ieee80211_mesh_prep_size_ok(pos, elen)) { + elems->prep = pos; + elems->prep_len = elen; + } else { + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + } break; case WLAN_EID_PERR: elems->perr = pos; -- 2.43.0 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/3] Fix PERR frame processing 2026-05-09 23:41 ` Masashi Honma 2026-05-09 23:41 ` [PATCH 2/3] Fix overread in PREP " Masashi Honma @ 2026-05-09 23:41 ` Masashi Honma 2026-05-11 7:47 ` [PATCH 1/3] Fix overread in PREQ " Johannes Berg 2 siblings, 0 replies; 10+ messages in thread From: Masashi Honma @ 2026-05-09 23:41 UTC (permalink / raw) To: linux-wireless; +Cc: johannes, Masashi Honma There are no issues with the PERR processing itself; however, to maintain consistency with the previous PREQ/PREP code modifications, I will create a new mesh_path_parse_error_frame() function to separately implement the frame format validation and the "not supported" check. Assisted-by: Claude:Sonnet 4.6 Signed-off-by: Masashi Honma <masashi.honma@gmail.com> --- include/linux/ieee80211-mesh.h | 38 ++++++++++++++++++++++++++++++++++ net/mac80211/mesh_hwmp.c | 11 ++++++++-- net/mac80211/parse.c | 9 ++++++-- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/include/linux/ieee80211-mesh.h b/include/linux/ieee80211-mesh.h index ddbf475c1cc8..1bca65e49309 100644 --- a/include/linux/ieee80211-mesh.h +++ b/include/linux/ieee80211-mesh.h @@ -61,6 +61,7 @@ struct ieee80211s_hdr { #define PREP_IE_TARGET_SN(x) u32_field_get(x, 9, 0) #define PERR_IE_TTL(x) (*(x)) +#define PERR_IE_NUMBER_OF_DST(x) (*(x + 1)) #define PERR_IE_TARGET_FLAGS(x) (*(x + 2)) #define PERR_IE_TARGET_ADDR(x) (x + 3) #define PERR_IE_TARGET_SN(x) u32_field_get(x, 9, 0) @@ -301,4 +302,41 @@ static inline bool ieee80211_mesh_prep_size_ok(const u8 *pos, u8 elen) return true; } +/* IEEE Std 802.11-2016 9.4.2.115 PERR element */ +static inline bool ieee80211_mesh_perr_size_ok(const u8 *pos, u8 elen) +{ + u8 number_of_dst; + u8 needed; + const u8 *start; + int i; + + number_of_dst = PERR_IE_NUMBER_OF_DST(pos); + if (number_of_dst < 1 || number_of_dst > 19) + return false; + + start = pos; + needed = 1 /* Element TTL */ + 1 /* Number of Destinations */; + pos += 2; + + for (i = 0; i < number_of_dst; i++) { + u8 dst_len; + + if (pos - start >= elen) + return false; + + dst_len = 1 /* Flags */ + 6 /* Destination Address */ + + 4 /* HWMP Sequence Number */ + + (AE_F_SET(pos) ? 6 : 0) + /* Destination External Address */ + + 2 /* Reason Code */; + needed += dst_len; + pos += dst_len; + } + + if (elen != needed) + return false; + + return true; +} + #endif /* LINUX_IEEE80211_MESH_H */ diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index c70cfc2d6299..d2295aa54bb4 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -902,6 +902,7 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, u32 path_metric; struct sta_info *sta; u8 target_count; + u8 number_of_dst; /* need action_code */ if (len < IEEE80211_MIN_ACTION_SIZE(mesh_action)) @@ -952,9 +953,15 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, path_metric); } if (elems->perr) { - if (elems->perr_len != 15) - /* Right now we support only one destination per PERR */ + /* Right now we support only one destination per PERR */ + number_of_dst = PERR_IE_NUMBER_OF_DST(elems->perr); + if (number_of_dst != 1) goto free; + + /* Right now we do not support AE (Address Extension) */ + if (PERR_IE_TARGET_FLAGS(elems->perr) & AE_F) + goto free; + hwmp_perr_frame_process(sdata, mgmt, elems->perr); } if (elems->rann) diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c index bbd1e1bc77b4..d84e5e12ad24 100644 --- a/net/mac80211/parse.c +++ b/net/mac80211/parse.c @@ -565,8 +565,13 @@ _ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params, } break; case WLAN_EID_PERR: - elems->perr = pos; - elems->perr_len = elen; + if (ieee80211_mesh_perr_size_ok(pos, elen)) { + elems->perr = pos; + elems->perr_len = elen; + } else { + elem_parse_failed = + IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; + } break; case WLAN_EID_RANN: if (elen >= sizeof(struct ieee80211_rann_ie)) -- 2.43.0 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 1/3] Fix overread in PREQ frame processing 2026-05-09 23:41 ` Masashi Honma 2026-05-09 23:41 ` [PATCH 2/3] Fix overread in PREP " Masashi Honma 2026-05-09 23:41 ` [PATCH 3/3] Fix PERR " Masashi Honma @ 2026-05-11 7:47 ` Johannes Berg 2026-05-11 8:58 ` Masashi Honma 2 siblings, 1 reply; 10+ messages in thread From: Johannes Berg @ 2026-05-11 7:47 UTC (permalink / raw) To: Masashi Honma, linux-wireless Hi, Please send new versions with a version tag ('v2' in the subject etc.), and not in the old thread, that just messes up the threads. Ideally tag which tree these should go to, though I think given the many other things I'll put this into wireless-next anyway, unless you strongly feel it needs to be in wireless? Also, please use appropriate "wifi: mac80211: " prefix in the subject. > +#define PREQ_IE_PREQ_ID(x) u32_field_get(x, 3, 0) This isn't really right since u32_field_get() exists only within mesh_hwmp.c ... it's probably better to modernise all this while at it: #define IEEE80211_MESH_HWMP_FLAGS_AE 0x40 struct ieee80211_mesh_hwmp_target { u8 flags; u8 addr[ETH_ALEN]; __le32 sn; } __packed; struct ieee80211_mesh_hwmp_element { u8 flags; u8 hopcount; u8 ttl; __le32 preq_id; u8 orig_addr[ETH_ALEN]; __le32 orig_sn; /* optional AE, lifetime, metric, target */ u8 variable[]; } __packed; and then some inlines like static inline const struct ieee80211_mesh_hwmp_target * ieee80211_mesh_hwmp_get_target(const struct ieee80211_mesh_hwmp_element *elem) { int offs = 8; // seems wrong if (elem->flags & IEEE80211_MESH_HWMP_FLAGS_AE) offs += ETH_ALEN; return (const void *)&elem->variable[offs]; } static inline u32 ieee80211_mesh_hwmp_get_lifetime(const struct ieee80211_mesh_hwmp_element *elem) { int offs = FIXME; // not sure if (elem->flags & IEEE80211_MESH_HWMP_FLAGS_AE) offs += ETH_ALEN; return (const void *)&elem->variable[offs]; } and restructure the code accordingly? Anyway, I dunno. Maybe we should just go with your original patch for now. Maybe I'm also asking more of you than others because you have an LLM to help ;-) johannes ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/3] Fix overread in PREQ frame processing 2026-05-11 7:47 ` [PATCH 1/3] Fix overread in PREQ " Johannes Berg @ 2026-05-11 8:58 ` Masashi Honma 2026-05-11 9:01 ` Johannes Berg 0 siblings, 1 reply; 10+ messages in thread From: Masashi Honma @ 2026-05-11 8:58 UTC (permalink / raw) To: Johannes Berg; +Cc: linux-wireless Thank you for your reviews! > Please send new versions with a version tag ('v2' in the subject etc.), Yes. I used --subject-prefix incorrectly, so I will correct it from next time. > and not in the old thread, that just messes up the threads. Yes. > Ideally tag which tree these should go to, though I think given the many other > things I'll put this into wireless-next anyway, unless you strongly feel > it needs to be in wireless? I'm happy to put this into wireless-next. > Also, please use appropriate "wifi: mac80211: " prefix in the subject. Yes. > This isn't really right since u32_field_get() exists only within > mesh_hwmp.c ... it's probably better to modernise all this while at it: Ah, yes. Both the build and tests passed, so I overlooked it. > and restructure the code accordingly? > Anyway, I dunno. Maybe we should just go with your original patch for > now. Maybe I'm also asking more of you than others because you have an > LLM to help ;-) If it is not urgent, I would like to proceed with the requested restructuring. Actually, I only used the LLM to find potential vulnerabilities, and I wrote the code myself :) 2026年5月11日(月) 16:47 Johannes Berg <johannes@sipsolutions.net>: > > Hi, > > Please send new versions with a version tag ('v2' in the subject etc.), > and not in the old thread, that just messes up the threads. Ideally tag > which tree these should go to, though I think given the many other > things I'll put this into wireless-next anyway, unless you strongly feel > it needs to be in wireless? > > Also, please use appropriate "wifi: mac80211: " prefix in the subject. > > > +#define PREQ_IE_PREQ_ID(x) u32_field_get(x, 3, 0) > > This isn't really right since u32_field_get() exists only within > mesh_hwmp.c ... it's probably better to modernise all this while at it: > > #define IEEE80211_MESH_HWMP_FLAGS_AE 0x40 > > struct ieee80211_mesh_hwmp_target { > u8 flags; > u8 addr[ETH_ALEN]; > __le32 sn; > } __packed; > > struct ieee80211_mesh_hwmp_element { > u8 flags; > u8 hopcount; > u8 ttl; > __le32 preq_id; > u8 orig_addr[ETH_ALEN]; > __le32 orig_sn; > > /* optional AE, lifetime, metric, target */ > u8 variable[]; > } __packed; > > and then some inlines like > > static inline const struct ieee80211_mesh_hwmp_target * > ieee80211_mesh_hwmp_get_target(const struct ieee80211_mesh_hwmp_element *elem) > { > int offs = 8; // seems wrong > > if (elem->flags & IEEE80211_MESH_HWMP_FLAGS_AE) > offs += ETH_ALEN; > > return (const void *)&elem->variable[offs]; > } > > static inline u32 > ieee80211_mesh_hwmp_get_lifetime(const struct ieee80211_mesh_hwmp_element *elem) > { > int offs = FIXME; // not sure > > if (elem->flags & IEEE80211_MESH_HWMP_FLAGS_AE) > offs += ETH_ALEN; > > return (const void *)&elem->variable[offs]; > } > > and restructure the code accordingly? > > Anyway, I dunno. Maybe we should just go with your original patch for > now. Maybe I'm also asking more of you than others because you have an > LLM to help ;-) > > johannes ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/3] Fix overread in PREQ frame processing 2026-05-11 8:58 ` Masashi Honma @ 2026-05-11 9:01 ` Johannes Berg 0 siblings, 0 replies; 10+ messages in thread From: Johannes Berg @ 2026-05-11 9:01 UTC (permalink / raw) To: Masashi Honma; +Cc: linux-wireless On Mon, 2026-05-11 at 17:58 +0900, Masashi Honma wrote: > > This isn't really right since u32_field_get() exists only within > > mesh_hwmp.c ... it's probably better to modernise all this while at it: > > Ah, yes. Both the build and tests passed, so I overlooked it. Yes, it would, but it's basically not self-contained. More of a code hygiene issue I guess than a real problem right now. > > and restructure the code accordingly? > > Anyway, I dunno. Maybe we should just go with your original patch for > > now. Maybe I'm also asking more of you than others because you have an > > LLM to help ;-) > > If it is not urgent, I would like to proceed with the requested restructuring. Oh sure, as far as I'm concerned there's no urgency, I just didn't want to keep asking you to make changes too much. > Actually, I only used the LLM to find potential vulnerabilities, and I wrote > the code myself :) Oh OK :) Maybe we need that as a kind of Reported-by? Hmm. Or you could send a separate bug report email, say there Claude found it, and then do a Closes: link :-p johannes ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-05-11 9:01 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <8f0a2488540f4a65ea4d837a06225a27a10cc305.camel@sipsolutions.net>
2026-05-08 22:59 ` [PATCH 1/3] Fix overread in PREQ frame processing Masashi Honma
2026-05-08 22:59 ` [PATCH 2/3] Fix overread in PREP " Masashi Honma
2026-05-08 22:59 ` [PATCH 3/3] Fix PERR " Masashi Honma
2026-05-09 9:17 ` [PATCH 1/3] Fix overread in PREQ " Johannes Berg
2026-05-09 23:41 ` Masashi Honma
2026-05-09 23:41 ` [PATCH 2/3] Fix overread in PREP " Masashi Honma
2026-05-09 23:41 ` [PATCH 3/3] Fix PERR " Masashi Honma
2026-05-11 7:47 ` [PATCH 1/3] Fix overread in PREQ " Johannes Berg
2026-05-11 8:58 ` Masashi Honma
2026-05-11 9:01 ` Johannes Berg
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox