git: 50c962d77370 - main - krpc/clnt_nl: filter RPC replies on vnet

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Sat, 01 Feb 2025 19:33:55 UTC
The branch main has been updated by glebius:

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

commit 50c962d773705f60d32c29f8e4bb2743ab55733b
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2025-02-01 19:27:22 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2025-02-01 19:27:22 +0000

    krpc/clnt_nl: filter RPC replies on vnet
    
    RPC calls are filtered by the Netlink system itself, but the RPC replies
    are not.  With legitimate use the chance of a xid collision is zero, since
    global clients use global atomically updated 32-bit counter for that.
    However, a malicious jail may blindly inject replies guessing the xid,
    where guessing is trivial.  Protect against that checking the vnet, too.
---
 sys/rpc/clnt_nl.c | 13 ++++++++++++-
 sys/rpc/krpc.h    |  5 ++++-
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/sys/rpc/clnt_nl.c b/sys/rpc/clnt_nl.c
index 8f841e4240d7..177566232cb5 100644
--- a/sys/rpc/clnt_nl.c
+++ b/sys/rpc/clnt_nl.c
@@ -269,10 +269,15 @@ clnt_nl_call(CLIENT *cl, struct rpc_callextra *ext, rpcproc_t proc,
 	u_int retries = 0;
 	bool rv __diagused;
 
+	CURVNET_ASSERT_SET();
+
 	cr = malloc(sizeof(struct ct_request), M_RPC, M_WAITOK);
 	*cr = (struct ct_request){
 		.cr_xid = atomic_fetchadd_32(&nl->nl_xid, 1),
 		.cr_error = ETIMEDOUT,
+#ifdef VIMAGE
+		.cr_vnet = curvnet,
+#endif
 	};
 
 	if (ext) {
@@ -394,6 +399,8 @@ clnt_nl_reply(struct nlmsghdr *hdr, struct nl_pstate *npt)
 	struct mchain mc;
 	int error;
 
+	CURVNET_ASSERT_SET();
+
 	if ((error = nl_parse_nlmsg(hdr, &rpcnl_parser, npt, &attrs)) != 0)
 		return (error);
 	if (attrs.data == NULL)
@@ -415,7 +422,11 @@ clnt_nl_reply(struct nlmsghdr *hdr, struct nl_pstate *npt)
 	rw_runlock(&rpcnl_global_lock);
 
 	TAILQ_FOREACH(cr, &nl->nl_pending, cr_link)
-		if (cr->cr_xid == hdr->nlmsg_seq)
+		if (cr->cr_xid == hdr->nlmsg_seq
+#ifdef VIMAGE
+		    && cr->cr_vnet == curvnet
+#endif
+		    )
 			break;
 	if (cr == NULL) {
 		mtx_unlock(&nl->nl_lock);
diff --git a/sys/rpc/krpc.h b/sys/rpc/krpc.h
index 06aa14eeb91f..f77e2d2d7428 100644
--- a/sys/rpc/krpc.h
+++ b/sys/rpc/krpc.h
@@ -49,8 +49,11 @@ struct mbuf *_rpc_copym_into_ext_pgs(struct mbuf *, int);
  */
 struct ct_request {
 	TAILQ_ENTRY(ct_request) cr_link;
-	uint32_t		cr_xid;		/* XID of request */
 	struct mbuf		*cr_mrep;	/* reply received by upcall */
+#ifdef VIMAGE
+	struct vnet		*cr_vnet;
+#endif
+	uint32_t		cr_xid;		/* XID of request */
 	int			cr_error;	/* any error from upcall */
 	char			cr_verf[MAX_AUTH_BYTES]; /* reply verf */
 };