From ae2ca32781a90abe987e128ca167ab400a87f369 Mon Sep 17 00:00:00 2001 From: "R. Christian McDonald" Date: Mon, 23 Oct 2023 13:23:55 +0200 Subject: [PATCH] netlink: fix potential llentry lock leak in newneigh handler The netlink newneigh handler has the potential to leak the lock on llentry objects in the kernel. This patch reconciles several paths through the newneigh handler that could result in a lock leak. MFC after: 1 week Reviewed by: markj, kp Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D42307 --- sys/netlink/route/neigh.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/sys/netlink/route/neigh.c b/sys/netlink/route/neigh.c index 9914e7febf5..5be0c1f9d91 100644 --- a/sys/netlink/route/neigh.c +++ b/sys/netlink/route/neigh.c @@ -436,17 +436,18 @@ rtnl_handle_newneigh(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate * struct llentry *lle_tmp = lla_lookup(llt, LLE_EXCLUSIVE, attrs.nda_dst); if (lle_tmp != NULL) { error = EEXIST; - if (hdr->nlmsg_flags & NLM_F_EXCL) { - LLE_WUNLOCK(lle_tmp); - lle_tmp = NULL; - } else if (hdr->nlmsg_flags & NLM_F_REPLACE) { + if (hdr->nlmsg_flags & NLM_F_REPLACE) { + error = EPERM; if ((lle_tmp->la_flags & LLE_IFADDR) == 0) { + error = 0; /* success */ lltable_unlink_entry(llt, lle_tmp); + llentry_free(lle_tmp); + lle_tmp = NULL; lltable_link_entry(llt, lle); - error = 0; - } else - error = EPERM; + } } + if (lle_tmp) + LLE_WUNLOCK(lle_tmp); } else { if (hdr->nlmsg_flags & NLM_F_CREATE) lltable_link_entry(llt, lle); @@ -456,14 +457,11 @@ rtnl_handle_newneigh(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate * IF_AFDATA_WUNLOCK(attrs.nda_ifp); if (error != 0) { - if (lle != NULL) - llentry_free(lle); + /* throw away the newly allocated llentry */ + llentry_free(lle); return (error); } - if (lle_tmp != NULL) - llentry_free(lle_tmp); - /* XXX: We're inside epoch */ EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_RESOLVED); LLE_WUNLOCK(lle);