https://github.com/0xdeadbeefnetwork/Copy_Fail2-Electric_Boogaloo

https://afflicted.sh/blog/posts/copy-fail-2.html

the bug

MSG_SPLICE_PAGES attaches pages from a pipe directly to an skb — no copy, the skb’s frags reference the pipe buffer’s pages. for TCP the path sets SKBFL_SHARED_FRAG on those skbs, which downstream consumers check before mutating frag bytes. for the IPv4/IPv6 datagram append paths, the flag was never set. so a UDP skb built with MSG_SPLICE_PAGES looked, to a downstream consumer, like an ordinary uncloned nonlinear skb whose frags it could mutate freely.

the consumer in question is esp_input():

// net/ipv4/esp4.c (pre-fix) } else if (!skb_has_frag_list(skb)) { nfrags = skb_shinfo(skb)->nr_frags; nfrags++;

goto skip_cow;

}

skip_cow jumps past the skb_cow_data() call. the remaining code path runs the AEAD decrypt in place over the existing scatterlist — which, since the frags are pipe pages we still hold open in userspace, are page-cache pages of whatever file we spliced from.

the kernel writes the decrypt output into those pages. they are still mapped into our pipe. they are also still the page cache for the file. so the kernel just wrote attacker-influenced bytes into the page cache of any readable file we can splice().

the Fixes: chain spans 2017 (esp no-COW fast path for both v4 and v6) and 2023 (UDP/UDP6 MSG_SPLICE_PAGES support). every mainline kernel that has all four sits in scope