Commit e0bb96db authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

netfilter: nft_socket: add support for cgroupsv2

Allow to match on the cgroupsv2 id from ancestor level.
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 885e8c68
...@@ -1014,11 +1014,13 @@ enum nft_rt_attributes { ...@@ -1014,11 +1014,13 @@ enum nft_rt_attributes {
* *
* @NFTA_SOCKET_KEY: socket key to match * @NFTA_SOCKET_KEY: socket key to match
* @NFTA_SOCKET_DREG: destination register * @NFTA_SOCKET_DREG: destination register
* @NFTA_SOCKET_LEVEL: cgroups2 ancestor level (only for cgroupsv2)
*/ */
enum nft_socket_attributes { enum nft_socket_attributes {
NFTA_SOCKET_UNSPEC, NFTA_SOCKET_UNSPEC,
NFTA_SOCKET_KEY, NFTA_SOCKET_KEY,
NFTA_SOCKET_DREG, NFTA_SOCKET_DREG,
NFTA_SOCKET_LEVEL,
__NFTA_SOCKET_MAX __NFTA_SOCKET_MAX
}; };
#define NFTA_SOCKET_MAX (__NFTA_SOCKET_MAX - 1) #define NFTA_SOCKET_MAX (__NFTA_SOCKET_MAX - 1)
...@@ -1029,11 +1031,13 @@ enum nft_socket_attributes { ...@@ -1029,11 +1031,13 @@ enum nft_socket_attributes {
* @NFT_SOCKET_TRANSPARENT: Value of the IP(V6)_TRANSPARENT socket option * @NFT_SOCKET_TRANSPARENT: Value of the IP(V6)_TRANSPARENT socket option
* @NFT_SOCKET_MARK: Value of the socket mark * @NFT_SOCKET_MARK: Value of the socket mark
* @NFT_SOCKET_WILDCARD: Whether the socket is zero-bound (e.g. 0.0.0.0 or ::0) * @NFT_SOCKET_WILDCARD: Whether the socket is zero-bound (e.g. 0.0.0.0 or ::0)
* @NFT_SOCKET_CGROUPV2: Match on cgroups version 2
*/ */
enum nft_socket_keys { enum nft_socket_keys {
NFT_SOCKET_TRANSPARENT, NFT_SOCKET_TRANSPARENT,
NFT_SOCKET_MARK, NFT_SOCKET_MARK,
NFT_SOCKET_WILDCARD, NFT_SOCKET_WILDCARD,
NFT_SOCKET_CGROUPV2,
__NFT_SOCKET_MAX __NFT_SOCKET_MAX
}; };
#define NFT_SOCKET_MAX (__NFT_SOCKET_MAX - 1) #define NFT_SOCKET_MAX (__NFT_SOCKET_MAX - 1)
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
struct nft_socket { struct nft_socket {
enum nft_socket_keys key:8; enum nft_socket_keys key:8;
u8 level;
union { union {
u8 dreg; u8 dreg;
}; };
...@@ -33,6 +34,26 @@ static void nft_socket_wildcard(const struct nft_pktinfo *pkt, ...@@ -33,6 +34,26 @@ static void nft_socket_wildcard(const struct nft_pktinfo *pkt,
} }
} }
#ifdef CONFIG_CGROUPS
static noinline bool
nft_sock_get_eval_cgroupv2(u32 *dest, const struct nft_pktinfo *pkt, u32 level)
{
struct sock *sk = skb_to_full_sk(pkt->skb);
struct cgroup *cgrp;
if (!sk || !sk_fullsock(sk) || !net_eq(nft_net(pkt), sock_net(sk)))
return false;
cgrp = sock_cgroup_ptr(&sk->sk_cgrp_data);
if (level > cgrp->level)
return false;
memcpy(dest, &cgrp->ancestor_ids[level], sizeof(u64));
return true;
}
#endif
static void nft_socket_eval(const struct nft_expr *expr, static void nft_socket_eval(const struct nft_expr *expr,
struct nft_regs *regs, struct nft_regs *regs,
const struct nft_pktinfo *pkt) const struct nft_pktinfo *pkt)
...@@ -85,6 +106,14 @@ static void nft_socket_eval(const struct nft_expr *expr, ...@@ -85,6 +106,14 @@ static void nft_socket_eval(const struct nft_expr *expr,
} }
nft_socket_wildcard(pkt, regs, sk, dest); nft_socket_wildcard(pkt, regs, sk, dest);
break; break;
#ifdef CONFIG_CGROUPS
case NFT_SOCKET_CGROUPV2:
if (!nft_sock_get_eval_cgroupv2(dest, pkt, priv->level)) {
regs->verdict.code = NFT_BREAK;
return;
}
break;
#endif
default: default:
WARN_ON(1); WARN_ON(1);
regs->verdict.code = NFT_BREAK; regs->verdict.code = NFT_BREAK;
...@@ -97,6 +126,7 @@ static void nft_socket_eval(const struct nft_expr *expr, ...@@ -97,6 +126,7 @@ static void nft_socket_eval(const struct nft_expr *expr,
static const struct nla_policy nft_socket_policy[NFTA_SOCKET_MAX + 1] = { static const struct nla_policy nft_socket_policy[NFTA_SOCKET_MAX + 1] = {
[NFTA_SOCKET_KEY] = { .type = NLA_U32 }, [NFTA_SOCKET_KEY] = { .type = NLA_U32 },
[NFTA_SOCKET_DREG] = { .type = NLA_U32 }, [NFTA_SOCKET_DREG] = { .type = NLA_U32 },
[NFTA_SOCKET_LEVEL] = { .type = NLA_U32 },
}; };
static int nft_socket_init(const struct nft_ctx *ctx, static int nft_socket_init(const struct nft_ctx *ctx,
...@@ -104,7 +134,7 @@ static int nft_socket_init(const struct nft_ctx *ctx, ...@@ -104,7 +134,7 @@ static int nft_socket_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nft_socket *priv = nft_expr_priv(expr); struct nft_socket *priv = nft_expr_priv(expr);
unsigned int len; unsigned int len, level;
if (!tb[NFTA_SOCKET_DREG] || !tb[NFTA_SOCKET_KEY]) if (!tb[NFTA_SOCKET_DREG] || !tb[NFTA_SOCKET_KEY])
return -EINVAL; return -EINVAL;
...@@ -129,6 +159,19 @@ static int nft_socket_init(const struct nft_ctx *ctx, ...@@ -129,6 +159,19 @@ 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
case NFT_SOCKET_CGROUPV2:
if (!tb[NFTA_SOCKET_LEVEL])
return -EINVAL;
level = ntohl(nla_get_u32(tb[NFTA_SOCKET_LEVEL]));
if (level > 255)
return -EOPNOTSUPP;
priv->level = level;
len = sizeof(u64);
break;
#endif
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -146,6 +189,9 @@ static int nft_socket_dump(struct sk_buff *skb, ...@@ -146,6 +189,9 @@ static int nft_socket_dump(struct sk_buff *skb,
return -1; return -1;
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 &&
nla_put_u32(skb, NFTA_SOCKET_LEVEL, htonl(priv->level)))
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