Commit 87009709 authored by Paolo Abeni's avatar Paolo Abeni
Browse files
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: default avatarPaolo Abeni <pabeni@redhat.com>
parents 6513eb3d 7f3287db
Loading
Loading
Loading
Loading
+42 −6
Original line number Diff line number Diff line
@@ -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;
@@ -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)
@@ -110,13 +133,13 @@ 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;
@@ -124,7 +147,7 @@ static void nft_socket_eval(const struct nft_expr *expr,
	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
@@ -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);
}
@@ -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;
@@ -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;
@@ -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;
}