| From afa9a05e6c4971bd5586f1b304e14d61fb3d9385 Mon Sep 17 00:00:00 2001 |
| From: Yang Yang <n05ec@lzu.edu.cn> |
| Date: Thu, 26 Mar 2026 03:44:41 +0000 |
| Subject: vxlan: validate ND option lengths in vxlan_na_create |
| |
| From: Yang Yang <n05ec@lzu.edu.cn> |
| |
| commit afa9a05e6c4971bd5586f1b304e14d61fb3d9385 upstream. |
| |
| vxlan_na_create() walks ND options according to option-provided |
| lengths. A malformed option can make the parser advance beyond the |
| computed option span or use a too-short source LLADDR option payload. |
| |
| Validate option lengths against the remaining NS option area before |
| advancing, and only read source LLADDR when the option is large enough |
| for an Ethernet address. |
| |
| Fixes: 4b29dba9c085 ("vxlan: fix nonfunctional neigh_reduce()") |
| Cc: stable@vger.kernel.org |
| Reported-by: Yifan Wu <yifanwucs@gmail.com> |
| Reported-by: Juefei Pu <tomapufckgml@gmail.com> |
| Tested-by: Ao Zhou <n05ec@lzu.edu.cn> |
| Co-developed-by: Yuan Tan <tanyuan98@outlook.com> |
| Signed-off-by: Yuan Tan <tanyuan98@outlook.com> |
| Suggested-by: Xin Liu <bird@lzu.edu.cn> |
| Signed-off-by: Yang Yang <n05ec@lzu.edu.cn> |
| Reviewed-by: Ido Schimmel <idosch@nvidia.com> |
| Acked-by: Nikolay Aleksandrov <razor@blackwall.org> |
| Link: https://patch.msgid.link/20260326034441.2037420-4-n05ec@lzu.edu.cn |
| Signed-off-by: Jakub Kicinski <kuba@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/vxlan/vxlan_core.c | 6 ++++-- |
| 1 file changed, 4 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/net/vxlan/vxlan_core.c |
| +++ b/drivers/net/vxlan/vxlan_core.c |
| @@ -1964,12 +1964,14 @@ static struct sk_buff *vxlan_na_create(s |
| ns_olen = request->len - skb_network_offset(request) - |
| sizeof(struct ipv6hdr) - sizeof(*ns); |
| for (i = 0; i < ns_olen-1; i += (ns->opt[i+1]<<3)) { |
| - if (!ns->opt[i + 1]) { |
| + if (!ns->opt[i + 1] || i + (ns->opt[i + 1] << 3) > ns_olen) { |
| kfree_skb(reply); |
| return NULL; |
| } |
| if (ns->opt[i] == ND_OPT_SOURCE_LL_ADDR) { |
| - daddr = ns->opt + i + sizeof(struct nd_opt_hdr); |
| + if ((ns->opt[i + 1] << 3) >= |
| + sizeof(struct nd_opt_hdr) + ETH_ALEN) |
| + daddr = ns->opt + i + sizeof(struct nd_opt_hdr); |
| break; |
| } |
| } |