xfrm: include mark in MIGRATE_STATE SA collision check
The SA lookup tuple is (daddr, spi, proto, family, mark), but the
EEXIST pre-check and the xfrm_state_insert() vs xfrm_state_add()
decision only considered daddr and family, ignoring mark.
A migration that only changes the mark inserts a duplicate SA tuple
into the hash tables.
The collision check is implemented as xfrm_state_mark_collides(),
which walks the SPI hash bucket for the target tuple and excludes the
state being migrated by pointer, rather than doing a separate
exact-match lookup followed by a wildcard lookup and comparing the
result against self.
Before:
root@west:~# ip xfrm state add src 10.1.1.1 dst 10.1.1.2 proto esp \
spi 0x1000 reqid 100 mode tunnel aead "rfc4106(gcm(aes))" \
0x1111111111111111111111111111111111111111 96 \
mark 0x1 mask 0xff
root@west:~# ip xfrm state add src 10.1.1.1 dst 10.1.1.2 proto esp \
spi 0x1000 reqid 100 mode tunnel aead "rfc4106(gcm(aes))" \
0x1111111111111111111111111111111111111111 96 \
mark 0x2 mask 0xff
root@west:~# ip xfrm state migrate dst 10.1.1.2 proto esp spi 0x1000 \
mark 0x1 mask 0xff \
new-dst 10.1.1.2 new-src 10.1.1.1 new-reqid 100 \
new-mark 0x2 mask 0xff
ip x s
src 10.1.1.1 dst 10.1.1.2
proto esp spi 0x00001000 reqid 100 mode tunnel
replay-window 0
mark 0x2/0xff
aead rfc4106(gcm(aes)) 0x1111111111111111111111111111111111111111 96
anti-replay context: seq 0x0, oseq 0x0, bitmap 0x00000000
src 10.1.1.1 dst 10.1.1.2
proto esp spi 0x00001000 reqid 100 mode tunnel
replay-window 0
mark 0x2/0xff
aead rfc4106(gcm(aes)) 0x1111111111111111111111111111111111111111 96
anti-replay context: seq 0x0, oseq 0x0, bitmap 0x00000000
sel src 0.0.0.0/0 dst 0.0.0.0/0
Notice two states with same mark 0x2/0xff.
After:
Error: New SA tuple already occupied.
Fixes: a9d155ea9b44 ("xfrm: add XFRM_MSG_MIGRATE_STATE for single SA migration")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Antony Antony <antony.antony@secunet.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
3 files changed