]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
netfilter: nfnetlink_osf: fix potential NULL dereference in ttl check
authorFernando Fernandez Mancera <fmancera@suse.de>
Fri, 17 Apr 2026 16:20:57 +0000 (18:20 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 20 Apr 2026 21:45:44 +0000 (23:45 +0200)
The nf_osf_ttl() function accessed skb->dev to perform a local interface
address lookup without verifying that the device pointer was valid.

Additionally, the implementation utilized an in_dev_for_each_ifa_rcu
loop to match the packet source address against local interface
addresses. It assumed that packets from the same subnet should not see a
decrement on the initial TTL. A packet might appear it is from the same
subnet but it actually isn't especially in modern environments with
containers and virtual switching.

Remove the device dereference and interface loop. Replace the logic with
a switch statement that evaluates the TTL according to the ttl_check.

Fixes: 11eeef41d5f6 ("netfilter: passive OS fingerprint xtables match")
Reported-by: Kito Xu (veritas501) <hxzene@gmail.com>
Closes: https://lore.kernel.org/netfilter-devel/20260414074556.2512750-1-hxzene@gmail.com/
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/nfnetlink_osf.c

index 9b209241029be6a5113729072006fe8b70e44c0e..acb753ec5697a5bd989ab5ac0265efe04a0bf01c 100644 (file)
@@ -31,26 +31,18 @@ EXPORT_SYMBOL_GPL(nf_osf_fingers);
 static inline int nf_osf_ttl(const struct sk_buff *skb,
                             int ttl_check, unsigned char f_ttl)
 {
-       struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
        const struct iphdr *ip = ip_hdr(skb);
-       const struct in_ifaddr *ifa;
-       int ret = 0;
 
-       if (ttl_check == NF_OSF_TTL_TRUE)
+       switch (ttl_check) {
+       case NF_OSF_TTL_TRUE:
                return ip->ttl == f_ttl;
-       if (ttl_check == NF_OSF_TTL_NOCHECK)
-               return 1;
-       else if (ip->ttl <= f_ttl)
+               break;
+       case NF_OSF_TTL_NOCHECK:
                return 1;
-
-       in_dev_for_each_ifa_rcu(ifa, in_dev) {
-               if (inet_ifa_match(ip->saddr, ifa)) {
-                       ret = (ip->ttl == f_ttl);
-                       break;
-               }
+       case NF_OSF_TTL_LESS:
+       default:
+               return ip->ttl <= f_ttl;
        }
-
-       return ret;
 }
 
 struct nf_osf_hdr_ctx {