git: eff832ae7b24 - stable/14 - netlink: fix potential llentry lock leak in newneigh handler

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Wed, 01 Nov 2023 09:06:05 UTC
The branch stable/14 has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=eff832ae7b248c499464cad93c365a1594715e07

commit eff832ae7b248c499464cad93c365a1594715e07
Author:     R. Christian McDonald <rcm@rcm.sh>
AuthorDate: 2023-10-23 11:23:55 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2023-11-01 09:05:49 +0000

    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
    
    (cherry picked from commit ae2ca32781a90abe987e128ca167ab400a87f369)
---
 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 9914e7febf57..5be0c1f9d91f 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);