⬢ DragonFlyBSD Kernel Audit
DF-3205 / fix.diff
← back to finding ↓ download raw
--- a/sys/vfs/nfs/krpc_subr.c
+++ b/sys/vfs/nfs/krpc_subr.c
@@ -198,7 +198,6 @@
 	struct timeval tv;
 	struct sockbuf sio;
 	int error, rcvflg, timo, secs, len;
-	static u_int32_t static_xid = ~0xFF;
 	u_int32_t xid;
 	u_int16_t tport;
 	u_int32_t saddr;
@@ -278,9 +277,7 @@
 	mhead->m_len = sizeof(*call);
 	bzero((caddr_t)call, sizeof(*call));
 	/* rpc_call part */
-	do {
-		xid = atomic_fetchadd_int(&static_xid, 1);
-	} while (xid == 0);
+	xid = karc4random();
 	call->rp_xid = txdr_unsigned(xid);
 	/* call->rp_direction = 0; */
 	call->rp_rpcvers = txdr_unsigned(2);
@@ -363,7 +360,27 @@
 			}
 			if (error)
 				goto out;
-			len -= sio.sb_cc;
+			/*
+			 * The reply must come from the server we asked
+			 * (address AND port): this UDP socket is never
+			 * connect()ed, so without a source check any
+			 * LAN host that guesses the xid -- trivially
+			 * possible with the old zero-entropy counter --
+			 * becomes the boot client's RPC authority.
+			 */
+			if (from == NULL ||
+			    from->sa_len < sizeof(struct sockaddr_in) ||
+			    ((struct sockaddr_in *)(void *)from)->
+			      sin_addr.s_addr != sa->sin_addr.s_addr ||
+			    ((struct sockaddr_in *)(void *)from)->
+			      sin_port != sa->sin_port) {
+				if (m) {
+					m_freem(m);
+					m = NULL;
+				}
+				continue;
+			}
+			len = (int)sio.sb_cc;
 			m = sio.sb_mb;
 
 			/* Does the reply contain at least a header? */