tcp: correctly crypto_alloc_hash return check
[deliverable/linux.git] / net / netfilter / nft_meta.c
1 /*
2 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/netlink.h>
15 #include <linux/netfilter.h>
16 #include <linux/netfilter/nf_tables.h>
17 #include <linux/in.h>
18 #include <linux/ip.h>
19 #include <linux/ipv6.h>
20 #include <linux/smp.h>
21 #include <linux/static_key.h>
22 #include <net/dst.h>
23 #include <net/sock.h>
24 #include <net/tcp_states.h> /* for TCP_TIME_WAIT */
25 #include <net/netfilter/nf_tables.h>
26 #include <net/netfilter/nf_tables_core.h>
27 #include <net/netfilter/nft_meta.h>
28
29 #include <uapi/linux/netfilter_bridge.h> /* NF_BR_PRE_ROUTING */
30
31 void nft_meta_get_eval(const struct nft_expr *expr,
32 struct nft_regs *regs,
33 const struct nft_pktinfo *pkt)
34 {
35 const struct nft_meta *priv = nft_expr_priv(expr);
36 const struct sk_buff *skb = pkt->skb;
37 const struct net_device *in = pkt->in, *out = pkt->out;
38 struct sock *sk;
39 u32 *dest = &regs->data[priv->dreg];
40
41 switch (priv->key) {
42 case NFT_META_LEN:
43 *dest = skb->len;
44 break;
45 case NFT_META_PROTOCOL:
46 *dest = 0;
47 *(__be16 *)dest = skb->protocol;
48 break;
49 case NFT_META_NFPROTO:
50 *dest = pkt->pf;
51 break;
52 case NFT_META_L4PROTO:
53 *dest = pkt->tprot;
54 break;
55 case NFT_META_PRIORITY:
56 *dest = skb->priority;
57 break;
58 case NFT_META_MARK:
59 *dest = skb->mark;
60 break;
61 case NFT_META_IIF:
62 if (in == NULL)
63 goto err;
64 *dest = in->ifindex;
65 break;
66 case NFT_META_OIF:
67 if (out == NULL)
68 goto err;
69 *dest = out->ifindex;
70 break;
71 case NFT_META_IIFNAME:
72 if (in == NULL)
73 goto err;
74 strncpy((char *)dest, in->name, IFNAMSIZ);
75 break;
76 case NFT_META_OIFNAME:
77 if (out == NULL)
78 goto err;
79 strncpy((char *)dest, out->name, IFNAMSIZ);
80 break;
81 case NFT_META_IIFTYPE:
82 if (in == NULL)
83 goto err;
84 *dest = 0;
85 *(u16 *)dest = in->type;
86 break;
87 case NFT_META_OIFTYPE:
88 if (out == NULL)
89 goto err;
90 *dest = 0;
91 *(u16 *)dest = out->type;
92 break;
93 case NFT_META_SKUID:
94 sk = skb_to_full_sk(skb);
95 if (!sk || !sk_fullsock(sk))
96 goto err;
97
98 read_lock_bh(&sk->sk_callback_lock);
99 if (sk->sk_socket == NULL ||
100 sk->sk_socket->file == NULL) {
101 read_unlock_bh(&sk->sk_callback_lock);
102 goto err;
103 }
104
105 *dest = from_kuid_munged(&init_user_ns,
106 sk->sk_socket->file->f_cred->fsuid);
107 read_unlock_bh(&sk->sk_callback_lock);
108 break;
109 case NFT_META_SKGID:
110 sk = skb_to_full_sk(skb);
111 if (!sk || !sk_fullsock(sk))
112 goto err;
113
114 read_lock_bh(&sk->sk_callback_lock);
115 if (sk->sk_socket == NULL ||
116 sk->sk_socket->file == NULL) {
117 read_unlock_bh(&sk->sk_callback_lock);
118 goto err;
119 }
120 *dest = from_kgid_munged(&init_user_ns,
121 sk->sk_socket->file->f_cred->fsgid);
122 read_unlock_bh(&sk->sk_callback_lock);
123 break;
124 #ifdef CONFIG_IP_ROUTE_CLASSID
125 case NFT_META_RTCLASSID: {
126 const struct dst_entry *dst = skb_dst(skb);
127
128 if (dst == NULL)
129 goto err;
130 *dest = dst->tclassid;
131 break;
132 }
133 #endif
134 #ifdef CONFIG_NETWORK_SECMARK
135 case NFT_META_SECMARK:
136 *dest = skb->secmark;
137 break;
138 #endif
139 case NFT_META_PKTTYPE:
140 if (skb->pkt_type != PACKET_LOOPBACK) {
141 *dest = skb->pkt_type;
142 break;
143 }
144
145 switch (pkt->pf) {
146 case NFPROTO_IPV4:
147 if (ipv4_is_multicast(ip_hdr(skb)->daddr))
148 *dest = PACKET_MULTICAST;
149 else
150 *dest = PACKET_BROADCAST;
151 break;
152 case NFPROTO_IPV6:
153 if (ipv6_hdr(skb)->daddr.s6_addr[0] == 0xFF)
154 *dest = PACKET_MULTICAST;
155 else
156 *dest = PACKET_BROADCAST;
157 break;
158 default:
159 WARN_ON(1);
160 goto err;
161 }
162 break;
163 case NFT_META_CPU:
164 *dest = raw_smp_processor_id();
165 break;
166 case NFT_META_IIFGROUP:
167 if (in == NULL)
168 goto err;
169 *dest = in->group;
170 break;
171 case NFT_META_OIFGROUP:
172 if (out == NULL)
173 goto err;
174 *dest = out->group;
175 break;
176 #ifdef CONFIG_CGROUP_NET_CLASSID
177 case NFT_META_CGROUP:
178 sk = skb_to_full_sk(skb);
179 if (!sk || !sk_fullsock(sk))
180 goto err;
181 *dest = sock_cgroup_classid(&sk->sk_cgrp_data);
182 break;
183 #endif
184 default:
185 WARN_ON(1);
186 goto err;
187 }
188 return;
189
190 err:
191 regs->verdict.code = NFT_BREAK;
192 }
193 EXPORT_SYMBOL_GPL(nft_meta_get_eval);
194
195 /* don't change or set _LOOPBACK, _USER, etc. */
196 static bool pkt_type_ok(u32 p)
197 {
198 return p == PACKET_HOST || p == PACKET_BROADCAST ||
199 p == PACKET_MULTICAST || p == PACKET_OTHERHOST;
200 }
201
202 void nft_meta_set_eval(const struct nft_expr *expr,
203 struct nft_regs *regs,
204 const struct nft_pktinfo *pkt)
205 {
206 const struct nft_meta *meta = nft_expr_priv(expr);
207 struct sk_buff *skb = pkt->skb;
208 u32 value = regs->data[meta->sreg];
209
210 switch (meta->key) {
211 case NFT_META_MARK:
212 skb->mark = value;
213 break;
214 case NFT_META_PRIORITY:
215 skb->priority = value;
216 break;
217 case NFT_META_PKTTYPE:
218 if (skb->pkt_type != value &&
219 pkt_type_ok(value) && pkt_type_ok(skb->pkt_type))
220 skb->pkt_type = value;
221 break;
222 case NFT_META_NFTRACE:
223 skb->nf_trace = 1;
224 break;
225 default:
226 WARN_ON(1);
227 }
228 }
229 EXPORT_SYMBOL_GPL(nft_meta_set_eval);
230
231 const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = {
232 [NFTA_META_DREG] = { .type = NLA_U32 },
233 [NFTA_META_KEY] = { .type = NLA_U32 },
234 [NFTA_META_SREG] = { .type = NLA_U32 },
235 };
236 EXPORT_SYMBOL_GPL(nft_meta_policy);
237
238 int nft_meta_get_init(const struct nft_ctx *ctx,
239 const struct nft_expr *expr,
240 const struct nlattr * const tb[])
241 {
242 struct nft_meta *priv = nft_expr_priv(expr);
243 unsigned int len;
244
245 priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
246 switch (priv->key) {
247 case NFT_META_PROTOCOL:
248 case NFT_META_IIFTYPE:
249 case NFT_META_OIFTYPE:
250 len = sizeof(u16);
251 break;
252 case NFT_META_NFPROTO:
253 case NFT_META_L4PROTO:
254 case NFT_META_LEN:
255 case NFT_META_PRIORITY:
256 case NFT_META_MARK:
257 case NFT_META_IIF:
258 case NFT_META_OIF:
259 case NFT_META_SKUID:
260 case NFT_META_SKGID:
261 #ifdef CONFIG_IP_ROUTE_CLASSID
262 case NFT_META_RTCLASSID:
263 #endif
264 #ifdef CONFIG_NETWORK_SECMARK
265 case NFT_META_SECMARK:
266 #endif
267 case NFT_META_PKTTYPE:
268 case NFT_META_CPU:
269 case NFT_META_IIFGROUP:
270 case NFT_META_OIFGROUP:
271 #ifdef CONFIG_CGROUP_NET_CLASSID
272 case NFT_META_CGROUP:
273 #endif
274 len = sizeof(u32);
275 break;
276 case NFT_META_IIFNAME:
277 case NFT_META_OIFNAME:
278 len = IFNAMSIZ;
279 break;
280 default:
281 return -EOPNOTSUPP;
282 }
283
284 priv->dreg = nft_parse_register(tb[NFTA_META_DREG]);
285 return nft_validate_register_store(ctx, priv->dreg, NULL,
286 NFT_DATA_VALUE, len);
287 }
288 EXPORT_SYMBOL_GPL(nft_meta_get_init);
289
290 static int nft_meta_set_init_pkttype(const struct nft_ctx *ctx)
291 {
292 unsigned int hooks;
293
294 switch (ctx->afi->family) {
295 case NFPROTO_BRIDGE:
296 hooks = 1 << NF_BR_PRE_ROUTING;
297 break;
298 case NFPROTO_NETDEV:
299 hooks = 1 << NF_NETDEV_INGRESS;
300 break;
301 default:
302 return -EOPNOTSUPP;
303 }
304
305 return nft_chain_validate_hooks(ctx->chain, hooks);
306 }
307
308 int nft_meta_set_init(const struct nft_ctx *ctx,
309 const struct nft_expr *expr,
310 const struct nlattr * const tb[])
311 {
312 struct nft_meta *priv = nft_expr_priv(expr);
313 unsigned int len;
314 int err;
315
316 priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
317 switch (priv->key) {
318 case NFT_META_MARK:
319 case NFT_META_PRIORITY:
320 len = sizeof(u32);
321 break;
322 case NFT_META_NFTRACE:
323 len = sizeof(u8);
324 break;
325 case NFT_META_PKTTYPE:
326 err = nft_meta_set_init_pkttype(ctx);
327 if (err)
328 return err;
329 len = sizeof(u8);
330 break;
331 default:
332 return -EOPNOTSUPP;
333 }
334
335 priv->sreg = nft_parse_register(tb[NFTA_META_SREG]);
336 err = nft_validate_register_load(priv->sreg, len);
337 if (err < 0)
338 return err;
339
340 if (priv->key == NFT_META_NFTRACE)
341 static_branch_inc(&nft_trace_enabled);
342
343 return 0;
344 }
345 EXPORT_SYMBOL_GPL(nft_meta_set_init);
346
347 int nft_meta_get_dump(struct sk_buff *skb,
348 const struct nft_expr *expr)
349 {
350 const struct nft_meta *priv = nft_expr_priv(expr);
351
352 if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
353 goto nla_put_failure;
354 if (nft_dump_register(skb, NFTA_META_DREG, priv->dreg))
355 goto nla_put_failure;
356 return 0;
357
358 nla_put_failure:
359 return -1;
360 }
361 EXPORT_SYMBOL_GPL(nft_meta_get_dump);
362
363 int nft_meta_set_dump(struct sk_buff *skb,
364 const struct nft_expr *expr)
365 {
366 const struct nft_meta *priv = nft_expr_priv(expr);
367
368 if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
369 goto nla_put_failure;
370 if (nft_dump_register(skb, NFTA_META_SREG, priv->sreg))
371 goto nla_put_failure;
372
373 return 0;
374
375 nla_put_failure:
376 return -1;
377 }
378 EXPORT_SYMBOL_GPL(nft_meta_set_dump);
379
380 void nft_meta_set_destroy(const struct nft_ctx *ctx,
381 const struct nft_expr *expr)
382 {
383 const struct nft_meta *priv = nft_expr_priv(expr);
384
385 if (priv->key == NFT_META_NFTRACE)
386 static_branch_dec(&nft_trace_enabled);
387 }
388 EXPORT_SYMBOL_GPL(nft_meta_set_destroy);
389
390 static struct nft_expr_type nft_meta_type;
391 static const struct nft_expr_ops nft_meta_get_ops = {
392 .type = &nft_meta_type,
393 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
394 .eval = nft_meta_get_eval,
395 .init = nft_meta_get_init,
396 .dump = nft_meta_get_dump,
397 };
398
399 static const struct nft_expr_ops nft_meta_set_ops = {
400 .type = &nft_meta_type,
401 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
402 .eval = nft_meta_set_eval,
403 .init = nft_meta_set_init,
404 .destroy = nft_meta_set_destroy,
405 .dump = nft_meta_set_dump,
406 };
407
408 static const struct nft_expr_ops *
409 nft_meta_select_ops(const struct nft_ctx *ctx,
410 const struct nlattr * const tb[])
411 {
412 if (tb[NFTA_META_KEY] == NULL)
413 return ERR_PTR(-EINVAL);
414
415 if (tb[NFTA_META_DREG] && tb[NFTA_META_SREG])
416 return ERR_PTR(-EINVAL);
417
418 if (tb[NFTA_META_DREG])
419 return &nft_meta_get_ops;
420
421 if (tb[NFTA_META_SREG])
422 return &nft_meta_set_ops;
423
424 return ERR_PTR(-EINVAL);
425 }
426
427 static struct nft_expr_type nft_meta_type __read_mostly = {
428 .name = "meta",
429 .select_ops = &nft_meta_select_ops,
430 .policy = nft_meta_policy,
431 .maxattr = NFTA_META_MAX,
432 .owner = THIS_MODULE,
433 };
434
435 static int __init nft_meta_module_init(void)
436 {
437 return nft_register_expr(&nft_meta_type);
438 }
439
440 static void __exit nft_meta_module_exit(void)
441 {
442 nft_unregister_expr(&nft_meta_type);
443 }
444
445 module_init(nft_meta_module_init);
446 module_exit(nft_meta_module_exit);
447
448 MODULE_LICENSE("GPL");
449 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
450 MODULE_ALIAS_NFT_EXPR("meta");
This page took 0.044499 seconds and 5 git commands to generate.