--- 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? */