A gateway's amt_rcv() admits a Membership Query or Multicast Data message when "saddr != remote_ip" is false. remote_ip is 0 before discovery has learned a relay (and is reset to 0 by amt_dev_open(), by amt_dev_stop(), and when the gateway gives up after its Requests go unanswered), so a packet whose source is 0.0.0.0 would otherwise pass the equality check and could spoof a Query or inject multicast data. IPv4 input accepts a 0.0.0.0 source only on a limited broadcast or a link-local (224.0.0.0/24) multicast destination, so the sender has to be on the gateway's link. A forged Query must also carry the gateway's nonce. That is 0 until the next discovery tick re-randomizes it, because amt_dev_open() and the give-up path in amt_event_send_request() zero amt->nonce along with remote_ip. The Query handler then sets ready4 or ready6, mac and qi, and moves the gateway to AMT_STATUS_RECEIVED_QUERY. From there amt_event_send_discovery() returns early and amt_advertisement_handler() rejects every Advertisement, so discovery stays blocked until the Request retries run out and the device is back in AMT_STATUS_INIT with nonce 0. The Data check is defense in depth: amt_multicast_data_handler() already requires AMT_STATUS_SENT_UPDATE, which a gateway with no relay reaches only after such a forged Query, or in the short window in which the give-up path has cleared remote_ip but not yet reset the status. Reject both when no relay is learned: a 0 remote_ip must match nothing, so guard the check with !remote_ip. A Query is queued before its event worker processes it, so the relay address can also change in that window. Recheck the packet source against the current remote_ip in the handler and discard stale Queries. Discovery is unaffected because Relay Advertisements are validated against discovery_ip, not remote_ip. Found by code inspection while writing the IPv6 receive path for the AMT IPv6 outer transport; not triggered at runtime. The Sashiko AI review of an earlier posting pointed out the nonce condition, the blocked discovery and that the Data check is defense in depth. Fixes: cbc21dc1cfe9 ("amt: add data plane of amt interface") Fixes: 30e22a6ebca0 ("amt: use workqueue for gateway side message handling") Assisted-by: LLM Signed-off-by: Omar Ramadan --- drivers/net/amt.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/amt.c b/drivers/net/amt.c index fc3900e25..9f59ec6c4 100644 --- a/drivers/net/amt.c +++ b/drivers/net/amt.c @@ -2527,6 +2527,10 @@ static bool amt_membership_query_handler(struct amt_dev *amt, if (amtmq->reserved || amtmq->version) return true; + /* A deferred query may outlive a relay address change. */ + if (ip_hdr(skb)->saddr != READ_ONCE(amt->remote_ip)) + return true; + if (amtmq->nonce != amt->nonce) return true; @@ -3005,7 +3009,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb) } goto out; case AMT_MSG_MULTICAST_DATA: - if (saddr != remote_ip) { + if (!remote_ip || saddr != remote_ip) { netdev_dbg(amt->dev, "Invalid Relay IP\n"); err = true; goto drop; @@ -3016,7 +3020,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb) else goto out; case AMT_MSG_MEMBERSHIP_QUERY: - if (saddr != remote_ip) { + if (!remote_ip || saddr != remote_ip) { netdev_dbg(amt->dev, "Invalid Relay IP\n"); err = true; goto drop; -- 2.43.0