netlbl_skbuff_getattr() locates the CIPSO option in the IPv4 IP header via cipso_v4_optptr() and hands the bare pointer to cipso_v4_getattr(). The consumer re-reads cipso[1] (option length), cipso[6] (tag type), and then cipso_v4_parsetag_*() re-reads further bytes from the skb. __ip_options_compile() validates these bytes only at parse time. An nftables LOCAL_IN payload write reachable from an unprivileged user namespace can rewrite them after parse and before the SELinux/Smack peer-label consume path (selinux_sock_rcv_skb_compat -> selinux_netlbl_sock_rcv_skb -> netlbl_skbuff_getattr). This is the IPv4 analogue of the CALIPSO IPv6 trust-after-modification fixed in the previous patch: the tag parsers walk the option using attacker- controlled length bytes, producing slab-out-of-bounds reads whose contents feed into the MLS access decision. Validate the option fits within skb_tail_pointer(skb) before invoking cipso_v4_getattr(). The pre-tag-walk guard "ptr + 8 > tail" covers the CIPSO option header (type + length + DOI = 6 bytes) plus the first tag header (type + length = 2 bytes), which are the bytes cipso_v4_getattr() reads to dispatch on the tag. When the bounds check fails the packet has been mutated after parse, so return -EINVAL rather than fall through to the unlabeled path. Runtime confirmation (Smack peer-label policy + nft LOCAL_IN mutation of tag_len): UdpInDatagrams increments to 1 and recvfrom returns the payload, showing netlbl_skbuff_getattr -> cipso_v4_getattr -> cipso_v4_parsetag_rbm -> netlbl_bitmap_walk runs end-to-end past the option's true bound; with this patch the consume path returns -EINVAL at the bounds check and the counter stays 0. Cc: stable@vger.kernel.org Reported-by: Qi Tang Reported-by: Tong Liu Fixes: 04f81f0154e4 ("cipso: don't use IPCB() to locate the CIPSO IP option") Signed-off-by: Qi Tang --- net/netlabel/netlabel_kapi.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index d0d6220b8d59d..c2d3ea751f4e1 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c @@ -1393,11 +1393,24 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb, unsigned char *ptr; switch (family) { - case AF_INET: + case AF_INET: { + const unsigned char *tail = skb_tail_pointer(skb); + u8 opt_len, tag_len; + ptr = cipso_v4_optptr(skb); - if (ptr && cipso_v4_getattr(ptr, secattr) == 0) + if (!ptr) + break; + /* CIPSO header (type+len+DOI = 6) + first tag header (type+len = 2) */ + if (ptr + 8 > tail) + return -EINVAL; + opt_len = ptr[1]; /* total CIPSO option length */ + tag_len = ptr[7]; /* first tag length */ + if (ptr + opt_len > tail || ptr + 6 + tag_len > tail) + return -EINVAL; + if (cipso_v4_getattr(ptr, secattr) == 0) return 0; break; + } #if IS_ENABLED(CONFIG_IPV6) case AF_INET6: { const unsigned char *tail = skb_tail_pointer(skb); -- 2.47.3