Commit 87009709 authored by Paolo Abeni's avatar Paolo Abeni

Merge tag 'nf-24-09-12' of git://git.kernel.org/pub/scm/linux/kernel/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.orgSigned-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents 6513eb3d 7f3287db
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
struct nft_socket { struct nft_socket {
enum nft_socket_keys key:8; enum nft_socket_keys key:8;
u8 level; u8 level; /* cgroupv2 level to extract */
u8 level_user; /* cgroupv2 level provided by userspace */
u8 len; u8 len;
union { union {
u8 dreg; u8 dreg;
...@@ -53,6 +54,28 @@ nft_sock_get_eval_cgroupv2(u32 *dest, struct sock *sk, const struct nft_pktinfo ...@@ -53,6 +54,28 @@ nft_sock_get_eval_cgroupv2(u32 *dest, struct sock *sk, const struct nft_pktinfo
memcpy(dest, &cgid, sizeof(u64)); memcpy(dest, &cgid, sizeof(u64));
return true; 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 #endif
static struct sock *nft_socket_do_lookup(const struct nft_pktinfo *pkt) static struct sock *nft_socket_do_lookup(const struct nft_pktinfo *pkt)
...@@ -110,13 +133,13 @@ static void nft_socket_eval(const struct nft_expr *expr, ...@@ -110,13 +133,13 @@ static void nft_socket_eval(const struct nft_expr *expr,
*dest = READ_ONCE(sk->sk_mark); *dest = READ_ONCE(sk->sk_mark);
} else { } else {
regs->verdict.code = NFT_BREAK; regs->verdict.code = NFT_BREAK;
return; goto out_put_sk;
} }
break; break;
case NFT_SOCKET_WILDCARD: case NFT_SOCKET_WILDCARD:
if (!sk_fullsock(sk)) { if (!sk_fullsock(sk)) {
regs->verdict.code = NFT_BREAK; regs->verdict.code = NFT_BREAK;
return; goto out_put_sk;
} }
nft_socket_wildcard(pkt, regs, sk, dest); nft_socket_wildcard(pkt, regs, sk, dest);
break; break;
...@@ -124,7 +147,7 @@ static void nft_socket_eval(const struct nft_expr *expr, ...@@ -124,7 +147,7 @@ static void nft_socket_eval(const struct nft_expr *expr,
case NFT_SOCKET_CGROUPV2: case NFT_SOCKET_CGROUPV2:
if (!nft_sock_get_eval_cgroupv2(dest, sk, pkt, priv->level)) { if (!nft_sock_get_eval_cgroupv2(dest, sk, pkt, priv->level)) {
regs->verdict.code = NFT_BREAK; regs->verdict.code = NFT_BREAK;
return; goto out_put_sk;
} }
break; break;
#endif #endif
...@@ -133,6 +156,7 @@ static void nft_socket_eval(const struct nft_expr *expr, ...@@ -133,6 +156,7 @@ static void nft_socket_eval(const struct nft_expr *expr,
regs->verdict.code = NFT_BREAK; regs->verdict.code = NFT_BREAK;
} }
out_put_sk:
if (sk != skb->sk) if (sk != skb->sk)
sock_gen_put(sk); sock_gen_put(sk);
} }
...@@ -173,9 +197,10 @@ static int nft_socket_init(const struct nft_ctx *ctx, ...@@ -173,9 +197,10 @@ static int nft_socket_init(const struct nft_ctx *ctx,
case NFT_SOCKET_MARK: case NFT_SOCKET_MARK:
len = sizeof(u32); len = sizeof(u32);
break; break;
#ifdef CONFIG_CGROUPS #ifdef CONFIG_SOCK_CGROUP_DATA
case NFT_SOCKET_CGROUPV2: { case NFT_SOCKET_CGROUPV2: {
unsigned int level; unsigned int level;
int err;
if (!tb[NFTA_SOCKET_LEVEL]) if (!tb[NFTA_SOCKET_LEVEL])
return -EINVAL; return -EINVAL;
...@@ -184,6 +209,17 @@ static int nft_socket_init(const struct nft_ctx *ctx, ...@@ -184,6 +209,17 @@ static int nft_socket_init(const struct nft_ctx *ctx,
if (level > 255) if (level > 255)
return -EOPNOTSUPP; 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; priv->level = level;
len = sizeof(u64); len = sizeof(u64);
break; break;
...@@ -208,7 +244,7 @@ static int nft_socket_dump(struct sk_buff *skb, ...@@ -208,7 +244,7 @@ static int nft_socket_dump(struct sk_buff *skb,
if (nft_dump_register(skb, NFTA_SOCKET_DREG, priv->dreg)) if (nft_dump_register(skb, NFTA_SOCKET_DREG, priv->dreg))
return -1; return -1;
if (priv->key == NFT_SOCKET_CGROUPV2 && 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 -1;
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment