History

netfilter: nft_socket: add support for cgroupsv2

Allow to match on the cgroupsv2 id from ancestor level.

Pablo Neira Ayuso committed 5 years ago

Commit e0bb96d1 parent 885e8c62 files · +51 −1Browse files

Unified · Split

2 files
  1. include/uapi/linux/netfilter/nf_tables.h +4 −0
  2. net/netfilter/nft_socket.c +47 −1
include/uapi/linux/netfilter/nf_tables.h+4−0
@@ -1014,11 +1014,13 @@ enum nft_rt_attributes { · 1013 unmodified lines
1014 *1014 *
1015 * @NFTA_SOCKET_KEY: socket key to match1015 * @NFTA_SOCKET_KEY: socket key to match
1016 * @NFTA_SOCKET_DREG: destination register1016 * @NFTA_SOCKET_DREG: destination register
1017 * @NFTA_SOCKET_LEVEL: cgroups2 ancestor level (only for cgroupsv2)
1017 */1018 */
1018enum nft_socket_attributes {1019enum nft_socket_attributes {
1019 NFTA_SOCKET_UNSPEC,1020 NFTA_SOCKET_UNSPEC,
1020 NFTA_SOCKET_KEY,1021 NFTA_SOCKET_KEY,
1021 NFTA_SOCKET_DREG,1022 NFTA_SOCKET_DREG,
1023 NFTA_SOCKET_LEVEL,
1022 __NFTA_SOCKET_MAX1024 __NFTA_SOCKET_MAX
1023};1025};
1024#define NFTA_SOCKET_MAX (__NFTA_SOCKET_MAX - 1)1026#define NFTA_SOCKET_MAX (__NFTA_SOCKET_MAX - 1)
@@ -1029,11 +1031,13 @@ enum nft_socket_attributes { · 4 unmodified lines
1029 * @NFT_SOCKET_TRANSPARENT: Value of the IP(V6)_TRANSPARENT socket option1031 * @NFT_SOCKET_TRANSPARENT: Value of the IP(V6)_TRANSPARENT socket option
1030 * @NFT_SOCKET_MARK: Value of the socket mark1032 * @NFT_SOCKET_MARK: Value of the socket mark
1031 * @NFT_SOCKET_WILDCARD: Whether the socket is zero-bound (e.g. 0.0.0.0 or ::0)1033 * @NFT_SOCKET_WILDCARD: Whether the socket is zero-bound (e.g. 0.0.0.0 or ::0)
1034 * @NFT_SOCKET_CGROUPV2: Match on cgroups version 2
1032 */1035 */
1033enum nft_socket_keys {1036enum nft_socket_keys {
1034 NFT_SOCKET_TRANSPARENT,1037 NFT_SOCKET_TRANSPARENT,
1035 NFT_SOCKET_MARK,1038 NFT_SOCKET_MARK,
1036 NFT_SOCKET_WILDCARD,1039 NFT_SOCKET_WILDCARD,
1040 NFT_SOCKET_CGROUPV2,
1037 __NFT_SOCKET_MAX1041 __NFT_SOCKET_MAX
1038};1042};
1039#define NFT_SOCKET_MAX (__NFT_SOCKET_MAX - 1)1043#define NFT_SOCKET_MAX (__NFT_SOCKET_MAX - 1)
net/netfilter/nft_socket.c+47−1
@@ -9,6 +9,7 @@ · 8 unmodified lines
9 9
10struct nft_socket {10struct nft_socket {
11 enum nft_socket_keys key:8;11 enum nft_socket_keys key:8;
12 u8 level;
12 union {13 union {
13 u8 dreg;14 u8 dreg;
14 };15 };
@@ -33,6 +34,26 @@ static void nft_socket_wildcard(const struct nft_pktinfo *pkt, · 18 unmodified lines
33 }34 }
34}35}
35 36
37#ifdef CONFIG_CGROUPS
38static noinline bool
39nft_sock_get_eval_cgroupv2(u32 *dest, const struct nft_pktinfo *pkt, u32 level)
40{
41 struct sock *sk = skb_to_full_sk(pkt->skb);
42 struct cgroup *cgrp;
43
44 if (!sk || !sk_fullsock(sk) || !net_eq(nft_net(pkt), sock_net(sk)))
45 return false;
46
47 cgrp = sock_cgroup_ptr(&sk->sk_cgrp_data);
48 if (level > cgrp->level)
49 return false;
50
51 memcpy(dest, &cgrp->ancestor_ids[level], sizeof(u64));
52
53 return true;
54}
55#endif
56
36static void nft_socket_eval(const struct nft_expr *expr,57static void nft_socket_eval(const struct nft_expr *expr,
37 struct nft_regs *regs,58 struct nft_regs *regs,
38 const struct nft_pktinfo *pkt)59 const struct nft_pktinfo *pkt)
@@ -85,6 +106,14 @@ static void nft_socket_eval(const struct nft_expr *expr, · 46 unmodified lines
85 }106 }
86 nft_socket_wildcard(pkt, regs, sk, dest);107 nft_socket_wildcard(pkt, regs, sk, dest);
87 break;108 break;
109#ifdef CONFIG_CGROUPS
110 case NFT_SOCKET_CGROUPV2:
111 if (!nft_sock_get_eval_cgroupv2(dest, pkt, priv->level)) {
112 regs->verdict.code = NFT_BREAK;
113 return;
114 }
115 break;
116#endif
88 default:117 default:
89 WARN_ON(1);118 WARN_ON(1);
90 regs->verdict.code = NFT_BREAK;119 regs->verdict.code = NFT_BREAK;
@@ -97,6 +126,7 @@ static void nft_socket_eval(const struct nft_expr *expr, · 6 unmodified lines
97static const struct nla_policy nft_socket_policy[NFTA_SOCKET_MAX + 1] = {126static const struct nla_policy nft_socket_policy[NFTA_SOCKET_MAX + 1] = {
98 [NFTA_SOCKET_KEY] = { .type = NLA_U32 },127 [NFTA_SOCKET_KEY] = { .type = NLA_U32 },
99 [NFTA_SOCKET_DREG] = { .type = NLA_U32 },128 [NFTA_SOCKET_DREG] = { .type = NLA_U32 },
129 [NFTA_SOCKET_LEVEL] = { .type = NLA_U32 },
100};130};
101 131
102static int nft_socket_init(const struct nft_ctx *ctx,132static int nft_socket_init(const struct nft_ctx *ctx,
@@ -104,7 +134,7 @@ static int nft_socket_init(const struct nft_ctx *ctx, · 1 unmodified line
104 const struct nlattr * const tb[])134 const struct nlattr * const tb[])
105{135{
106 struct nft_socket *priv = nft_expr_priv(expr);136 struct nft_socket *priv = nft_expr_priv(expr);
107 unsigned int len;137 unsigned int len, level;
108 138
109 if (!tb[NFTA_SOCKET_DREG] || !tb[NFTA_SOCKET_KEY])139 if (!tb[NFTA_SOCKET_DREG] || !tb[NFTA_SOCKET_KEY])
110 return -EINVAL;140 return -EINVAL;
@@ -129,6 +159,19 @@ static int nft_socket_init(const struct nft_ctx *ctx, · 18 unmodified lines
129 case NFT_SOCKET_MARK:159 case NFT_SOCKET_MARK:
130 len = sizeof(u32);160 len = sizeof(u32);
131 break;161 break;
162#ifdef CONFIG_CGROUPS
163 case NFT_SOCKET_CGROUPV2:
164 if (!tb[NFTA_SOCKET_LEVEL])
165 return -EINVAL;
166
167 level = ntohl(nla_get_u32(tb[NFTA_SOCKET_LEVEL]));
168 if (level > 255)
169 return -EOPNOTSUPP;
170
171 priv->level = level;
172 len = sizeof(u64);
173 break;
174#endif
132 default:175 default:
133 return -EOPNOTSUPP;176 return -EOPNOTSUPP;
134 }177 }
@@ -146,6 +189,9 @@ static int nft_socket_dump(struct sk_buff *skb, · 11 unmodified lines
146 return -1;189 return -1;
147 if (nft_dump_register(skb, NFTA_SOCKET_DREG, priv->dreg))190 if (nft_dump_register(skb, NFTA_SOCKET_DREG, priv->dreg))
148 return -1;191 return -1;
192 if (priv->key == NFT_SOCKET_CGROUPV2 &&
193 nla_put_u32(skb, NFTA_SOCKET_LEVEL, htonl(priv->level)))
194 return -1;
149 return 0;195 return 0;
150}196}
151 197