Skip to content

Commit

Permalink
Merge tag 'nf-24-09-12' of git://git.kernel.org/pub/scm/linux/kernel/…
Browse files Browse the repository at this point in the history
…git/netfilter/nf

Pablo Neira Ayuso says:

====================
Netfilter fixes for net

The following batch contains two fixes from Florian Westphal:

Patch #1 fixes a sk refcount leak in nft_socket on mismatch.

Patch #2 fixes cgroupsv2 matching from containers due to incorrect
	 level in subtree.

netfilter pull request 24-09-12

* tag 'nf-24-09-12' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
  netfilter: nft_socket: make cgroupsv2 matching work with namespaces
  netfilter: nft_socket: fix sk refcount leaks
====================

Link: https://patch.msgid.link/20240911222520.3606-1-pablo@netfilter.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
  • Loading branch information
Paolo Abeni committed Sep 12, 2024
2 parents 6513eb3 + 7f3287d commit 8700970
Showing 1 changed file with 42 additions and 6 deletions.
48 changes: 42 additions & 6 deletions net/netfilter/nft_socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

struct nft_socket {
enum nft_socket_keys key:8;
u8 level;
u8 level; /* cgroupv2 level to extract */
u8 level_user; /* cgroupv2 level provided by userspace */
u8 len;
union {
u8 dreg;
Expand Down Expand Up @@ -53,6 +54,28 @@ nft_sock_get_eval_cgroupv2(u32 *dest, struct sock *sk, const struct nft_pktinfo
memcpy(dest, &cgid, sizeof(u64));
return true;
}

/* process context only, uses current->nsproxy. */
static noinline int nft_socket_cgroup_subtree_level(void)
{
struct cgroup *cgrp = cgroup_get_from_path("/");
int level;

if (!cgrp)
return -ENOENT;

level = cgrp->level;

cgroup_put(cgrp);

if (WARN_ON_ONCE(level > 255))
return -ERANGE;

if (WARN_ON_ONCE(level < 0))
return -EINVAL;

return level;
}
#endif

static struct sock *nft_socket_do_lookup(const struct nft_pktinfo *pkt)
Expand Down Expand Up @@ -110,21 +133,21 @@ static void nft_socket_eval(const struct nft_expr *expr,
*dest = READ_ONCE(sk->sk_mark);
} else {
regs->verdict.code = NFT_BREAK;
return;
goto out_put_sk;
}
break;
case NFT_SOCKET_WILDCARD:
if (!sk_fullsock(sk)) {
regs->verdict.code = NFT_BREAK;
return;
goto out_put_sk;
}
nft_socket_wildcard(pkt, regs, sk, dest);
break;
#ifdef CONFIG_SOCK_CGROUP_DATA
case NFT_SOCKET_CGROUPV2:
if (!nft_sock_get_eval_cgroupv2(dest, sk, pkt, priv->level)) {
regs->verdict.code = NFT_BREAK;
return;
goto out_put_sk;
}
break;
#endif
Expand All @@ -133,6 +156,7 @@ static void nft_socket_eval(const struct nft_expr *expr,
regs->verdict.code = NFT_BREAK;
}

out_put_sk:
if (sk != skb->sk)
sock_gen_put(sk);
}
Expand Down Expand Up @@ -173,9 +197,10 @@ static int nft_socket_init(const struct nft_ctx *ctx,
case NFT_SOCKET_MARK:
len = sizeof(u32);
break;
#ifdef CONFIG_CGROUPS
#ifdef CONFIG_SOCK_CGROUP_DATA
case NFT_SOCKET_CGROUPV2: {
unsigned int level;
int err;

if (!tb[NFTA_SOCKET_LEVEL])
return -EINVAL;
Expand All @@ -184,6 +209,17 @@ static int nft_socket_init(const struct nft_ctx *ctx,
if (level > 255)
return -EOPNOTSUPP;

err = nft_socket_cgroup_subtree_level();
if (err < 0)
return err;

priv->level_user = level;

level += err;
/* Implies a giant cgroup tree */
if (WARN_ON_ONCE(level > 255))
return -EOPNOTSUPP;

priv->level = level;
len = sizeof(u64);
break;
Expand All @@ -208,7 +244,7 @@ static int nft_socket_dump(struct sk_buff *skb,
if (nft_dump_register(skb, NFTA_SOCKET_DREG, priv->dreg))
return -1;
if (priv->key == NFT_SOCKET_CGROUPV2 &&
nla_put_be32(skb, NFTA_SOCKET_LEVEL, htonl(priv->level)))
nla_put_be32(skb, NFTA_SOCKET_LEVEL, htonl(priv->level_user)))
return -1;
return 0;
}
Expand Down

0 comments on commit 8700970

Please sign in to comment.