Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[linux-2.6-block.git] / net / netfilter / nft_meta.c
CommitLineData
d2912cb1 1// SPDX-License-Identifier: GPL-2.0-only
96518518 2/*
ef1f7df9 3 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
bd2bbdb4
FW
4 * Copyright (c) 2014 Intel Corporation
5 * Author: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
96518518 6 *
96518518
PM
7 * Development of this code funded by Astaro AG (http://www.astaro.com/)
8 */
9
10#include <linux/kernel.h>
96518518
PM
11#include <linux/netlink.h>
12#include <linux/netfilter.h>
13#include <linux/netfilter/nf_tables.h>
e2a093ff
AR
14#include <linux/in.h>
15#include <linux/ip.h>
16#include <linux/ipv6.h>
afc5be30 17#include <linux/smp.h>
e639f7ab 18#include <linux/static_key.h>
96518518
PM
19#include <net/dst.h>
20#include <net/sock.h>
21#include <net/tcp_states.h> /* for TCP_TIME_WAIT */
22#include <net/netfilter/nf_tables.h>
e639f7ab 23#include <net/netfilter/nf_tables_core.h>
30e103fe 24#include <net/netfilter/nft_meta.h>
c9626a2c 25#include <net/netfilter/nf_tables_offload.h>
96518518 26
b4aae759
FW
27#include <uapi/linux/netfilter_bridge.h> /* NF_BR_PRE_ROUTING */
28
b07edbe1
FW
29static DEFINE_PER_CPU(struct rnd_state, nft_prandom_state);
30
222440b4
FW
31void nft_meta_get_eval(const struct nft_expr *expr,
32 struct nft_regs *regs,
33 const struct nft_pktinfo *pkt)
96518518
PM
34{
35 const struct nft_meta *priv = nft_expr_priv(expr);
36 const struct sk_buff *skb = pkt->skb;
0e5a1c7e 37 const struct net_device *in = nft_in(pkt), *out = nft_out(pkt);
3aed8225 38 struct sock *sk;
49499c3e 39 u32 *dest = &regs->data[priv->dreg];
96518518
PM
40
41 switch (priv->key) {
42 case NFT_META_LEN:
fad136ea 43 *dest = skb->len;
96518518
PM
44 break;
45 case NFT_META_PROTOCOL:
10596608 46 nft_reg_store16(dest, (__force u16)skb->protocol);
96518518 47 break;
124edfa9 48 case NFT_META_NFPROTO:
10596608 49 nft_reg_store8(dest, nft_pf(pkt));
124edfa9 50 break;
4566bf27 51 case NFT_META_L4PROTO:
beac5afa
PNA
52 if (!pkt->tprot_set)
53 goto err;
10596608 54 nft_reg_store8(dest, pkt->tprot);
4566bf27 55 break;
96518518 56 case NFT_META_PRIORITY:
fad136ea 57 *dest = skb->priority;
96518518
PM
58 break;
59 case NFT_META_MARK:
fad136ea 60 *dest = skb->mark;
96518518
PM
61 break;
62 case NFT_META_IIF:
63 if (in == NULL)
64 goto err;
fad136ea 65 *dest = in->ifindex;
96518518
PM
66 break;
67 case NFT_META_OIF:
68 if (out == NULL)
69 goto err;
fad136ea 70 *dest = out->ifindex;
96518518
PM
71 break;
72 case NFT_META_IIFNAME:
73 if (in == NULL)
74 goto err;
fad136ea 75 strncpy((char *)dest, in->name, IFNAMSIZ);
96518518
PM
76 break;
77 case NFT_META_OIFNAME:
78 if (out == NULL)
79 goto err;
fad136ea 80 strncpy((char *)dest, out->name, IFNAMSIZ);
96518518
PM
81 break;
82 case NFT_META_IIFTYPE:
83 if (in == NULL)
84 goto err;
10596608 85 nft_reg_store16(dest, in->type);
96518518
PM
86 break;
87 case NFT_META_OIFTYPE:
88 if (out == NULL)
89 goto err;
10596608 90 nft_reg_store16(dest, out->type);
96518518
PM
91 break;
92 case NFT_META_SKUID:
3aed8225 93 sk = skb_to_full_sk(skb);
f5646501
FL
94 if (!sk || !sk_fullsock(sk) ||
95 !net_eq(nft_net(pkt), sock_net(sk)))
96518518
PM
96 goto err;
97
3aed8225
ED
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);
96518518
PM
102 goto err;
103 }
104
fad136ea 105 *dest = from_kuid_munged(&init_user_ns,
3aed8225
ED
106 sk->sk_socket->file->f_cred->fsuid);
107 read_unlock_bh(&sk->sk_callback_lock);
96518518
PM
108 break;
109 case NFT_META_SKGID:
3aed8225 110 sk = skb_to_full_sk(skb);
f5646501
FL
111 if (!sk || !sk_fullsock(sk) ||
112 !net_eq(nft_net(pkt), sock_net(sk)))
96518518
PM
113 goto err;
114
3aed8225
ED
115 read_lock_bh(&sk->sk_callback_lock);
116 if (sk->sk_socket == NULL ||
117 sk->sk_socket->file == NULL) {
118 read_unlock_bh(&sk->sk_callback_lock);
96518518
PM
119 goto err;
120 }
fad136ea 121 *dest = from_kgid_munged(&init_user_ns,
3aed8225
ED
122 sk->sk_socket->file->f_cred->fsgid);
123 read_unlock_bh(&sk->sk_callback_lock);
96518518 124 break;
06efbd6d 125#ifdef CONFIG_IP_ROUTE_CLASSID
96518518
PM
126 case NFT_META_RTCLASSID: {
127 const struct dst_entry *dst = skb_dst(skb);
128
129 if (dst == NULL)
130 goto err;
fad136ea 131 *dest = dst->tclassid;
96518518
PM
132 break;
133 }
134#endif
135#ifdef CONFIG_NETWORK_SECMARK
136 case NFT_META_SECMARK:
fad136ea 137 *dest = skb->secmark;
96518518
PM
138 break;
139#endif
e2a093ff
AR
140 case NFT_META_PKTTYPE:
141 if (skb->pkt_type != PACKET_LOOPBACK) {
10596608 142 nft_reg_store8(dest, skb->pkt_type);
e2a093ff
AR
143 break;
144 }
145
0e5a1c7e 146 switch (nft_pf(pkt)) {
e2a093ff
AR
147 case NFPROTO_IPV4:
148 if (ipv4_is_multicast(ip_hdr(skb)->daddr))
10596608 149 nft_reg_store8(dest, PACKET_MULTICAST);
e2a093ff 150 else
10596608 151 nft_reg_store8(dest, PACKET_BROADCAST);
e2a093ff
AR
152 break;
153 case NFPROTO_IPV6:
10596608 154 nft_reg_store8(dest, PACKET_MULTICAST);
e2a093ff 155 break;
f169fd69
LZ
156 case NFPROTO_NETDEV:
157 switch (skb->protocol) {
158 case htons(ETH_P_IP): {
159 int noff = skb_network_offset(skb);
160 struct iphdr *iph, _iph;
161
162 iph = skb_header_pointer(skb, noff,
163 sizeof(_iph), &_iph);
164 if (!iph)
165 goto err;
166
167 if (ipv4_is_multicast(iph->daddr))
10596608 168 nft_reg_store8(dest, PACKET_MULTICAST);
f169fd69 169 else
10596608 170 nft_reg_store8(dest, PACKET_BROADCAST);
f169fd69
LZ
171
172 break;
173 }
174 case htons(ETH_P_IPV6):
10596608 175 nft_reg_store8(dest, PACKET_MULTICAST);
f169fd69
LZ
176 break;
177 default:
178 WARN_ON_ONCE(1);
179 goto err;
180 }
181 break;
e2a093ff 182 default:
f169fd69 183 WARN_ON_ONCE(1);
e2a093ff
AR
184 goto err;
185 }
186 break;
afc5be30 187 case NFT_META_CPU:
fad136ea 188 *dest = raw_smp_processor_id();
afc5be30 189 break;
3045d760
AR
190 case NFT_META_IIFGROUP:
191 if (in == NULL)
192 goto err;
fad136ea 193 *dest = in->group;
3045d760
AR
194 break;
195 case NFT_META_OIFGROUP:
196 if (out == NULL)
197 goto err;
fad136ea 198 *dest = out->group;
3045d760 199 break;
e181a543 200#ifdef CONFIG_CGROUP_NET_CLASSID
ce674173 201 case NFT_META_CGROUP:
3aed8225 202 sk = skb_to_full_sk(skb);
f5646501
FL
203 if (!sk || !sk_fullsock(sk) ||
204 !net_eq(nft_net(pkt), sock_net(sk)))
c5035c77 205 goto err;
2a56a1fe 206 *dest = sock_cgroup_classid(&sk->sk_cgrp_data);
ce674173 207 break;
e181a543 208#endif
b07edbe1
FW
209 case NFT_META_PRANDOM: {
210 struct rnd_state *state = this_cpu_ptr(&nft_prandom_state);
211 *dest = prandom_u32_state(state);
212 break;
213 }
f6931f5f
FW
214#ifdef CONFIG_XFRM
215 case NFT_META_SECPATH:
7af8f4ca 216 nft_reg_store8(dest, secpath_exists(skb));
f6931f5f
FW
217 break;
218#endif
0fb4d219 219 case NFT_META_IIFKIND:
220 if (in == NULL || in->rtnl_link_ops == NULL)
221 goto err;
222 strncpy((char *)dest, in->rtnl_link_ops->kind, IFNAMSIZ);
223 break;
224 case NFT_META_OIFKIND:
225 if (out == NULL || out->rtnl_link_ops == NULL)
226 goto err;
227 strncpy((char *)dest, out->rtnl_link_ops->kind, IFNAMSIZ);
228 break;
96518518
PM
229 default:
230 WARN_ON(1);
231 goto err;
232 }
233 return;
234
235err:
a55e22e9 236 regs->verdict.code = NFT_BREAK;
96518518 237}
30e103fe 238EXPORT_SYMBOL_GPL(nft_meta_get_eval);
96518518 239
30e103fe 240void nft_meta_set_eval(const struct nft_expr *expr,
241 struct nft_regs *regs,
242 const struct nft_pktinfo *pkt)
e035b77a
ABG
243{
244 const struct nft_meta *meta = nft_expr_priv(expr);
245 struct sk_buff *skb = pkt->skb;
10596608
LZ
246 u32 *sreg = &regs->data[meta->sreg];
247 u32 value = *sreg;
97a0549b 248 u8 value8;
e035b77a
ABG
249
250 switch (meta->key) {
251 case NFT_META_MARK:
252 skb->mark = value;
253 break;
254 case NFT_META_PRIORITY:
255 skb->priority = value;
256 break;
b4aae759 257 case NFT_META_PKTTYPE:
97a0549b 258 value8 = nft_reg_load8(sreg);
10596608 259
97a0549b
TY
260 if (skb->pkt_type != value8 &&
261 skb_pkt_type_ok(value8) &&
10596608 262 skb_pkt_type_ok(skb->pkt_type))
97a0549b 263 skb->pkt_type = value8;
b4aae759 264 break;
e035b77a 265 case NFT_META_NFTRACE:
97a0549b
TY
266 value8 = nft_reg_load8(sreg);
267
268 skb->nf_trace = !!value8;
e035b77a 269 break;
b473a1f5
CG
270#ifdef CONFIG_NETWORK_SECMARK
271 case NFT_META_SECMARK:
272 skb->secmark = value;
273 break;
274#endif
e035b77a
ABG
275 default:
276 WARN_ON(1);
277 }
278}
30e103fe 279EXPORT_SYMBOL_GPL(nft_meta_set_eval);
e035b77a 280
30e103fe 281const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = {
96518518
PM
282 [NFTA_META_DREG] = { .type = NLA_U32 },
283 [NFTA_META_KEY] = { .type = NLA_U32 },
e035b77a 284 [NFTA_META_SREG] = { .type = NLA_U32 },
96518518 285};
30e103fe 286EXPORT_SYMBOL_GPL(nft_meta_policy);
96518518 287
30e103fe 288int nft_meta_get_init(const struct nft_ctx *ctx,
289 const struct nft_expr *expr,
290 const struct nlattr * const tb[])
96518518 291{
d2caa696 292 struct nft_meta *priv = nft_expr_priv(expr);
45d9bcda 293 unsigned int len;
96518518 294
d2caa696
PM
295 priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
296 switch (priv->key) {
96518518 297 case NFT_META_PROTOCOL:
45d9bcda
PM
298 case NFT_META_IIFTYPE:
299 case NFT_META_OIFTYPE:
300 len = sizeof(u16);
301 break;
124edfa9 302 case NFT_META_NFPROTO:
4566bf27 303 case NFT_META_L4PROTO:
45d9bcda 304 case NFT_META_LEN:
96518518
PM
305 case NFT_META_PRIORITY:
306 case NFT_META_MARK:
307 case NFT_META_IIF:
308 case NFT_META_OIF:
96518518
PM
309 case NFT_META_SKUID:
310 case NFT_META_SKGID:
06efbd6d 311#ifdef CONFIG_IP_ROUTE_CLASSID
96518518
PM
312 case NFT_META_RTCLASSID:
313#endif
314#ifdef CONFIG_NETWORK_SECMARK
315 case NFT_META_SECMARK:
316#endif
e2a093ff 317 case NFT_META_PKTTYPE:
afc5be30 318 case NFT_META_CPU:
3045d760
AR
319 case NFT_META_IIFGROUP:
320 case NFT_META_OIFGROUP:
e181a543 321#ifdef CONFIG_CGROUP_NET_CLASSID
ce674173 322 case NFT_META_CGROUP:
e181a543 323#endif
45d9bcda
PM
324 len = sizeof(u32);
325 break;
326 case NFT_META_IIFNAME:
327 case NFT_META_OIFNAME:
0fb4d219 328 case NFT_META_IIFKIND:
329 case NFT_META_OIFKIND:
45d9bcda 330 len = IFNAMSIZ;
d2caa696 331 break;
b07edbe1
FW
332 case NFT_META_PRANDOM:
333 prandom_init_once(&nft_prandom_state);
334 len = sizeof(u32);
335 break;
f6931f5f
FW
336#ifdef CONFIG_XFRM
337 case NFT_META_SECPATH:
338 len = sizeof(u8);
339 break;
340#endif
96518518
PM
341 default:
342 return -EOPNOTSUPP;
343 }
344
b1c96ed3 345 priv->dreg = nft_parse_register(tb[NFTA_META_DREG]);
27e6d201
PM
346 return nft_validate_register_store(ctx, priv->dreg, NULL,
347 NFT_DATA_VALUE, len);
e035b77a 348}
30e103fe 349EXPORT_SYMBOL_GPL(nft_meta_get_init);
e035b77a 350
f6931f5f
FW
351static int nft_meta_get_validate(const struct nft_ctx *ctx,
352 const struct nft_expr *expr,
353 const struct nft_data **data)
354{
355#ifdef CONFIG_XFRM
356 const struct nft_meta *priv = nft_expr_priv(expr);
357 unsigned int hooks;
358
359 if (priv->key != NFT_META_SECPATH)
360 return 0;
361
36596dad 362 switch (ctx->family) {
f6931f5f
FW
363 case NFPROTO_NETDEV:
364 hooks = 1 << NF_NETDEV_INGRESS;
365 break;
366 case NFPROTO_IPV4:
367 case NFPROTO_IPV6:
368 case NFPROTO_INET:
369 hooks = (1 << NF_INET_PRE_ROUTING) |
370 (1 << NF_INET_LOCAL_IN) |
371 (1 << NF_INET_FORWARD);
372 break;
373 default:
374 return -EOPNOTSUPP;
375 }
376
377 return nft_chain_validate_hooks(ctx->chain, hooks);
378#else
379 return 0;
380#endif
381}
382
30e103fe 383int nft_meta_set_validate(const struct nft_ctx *ctx,
384 const struct nft_expr *expr,
385 const struct nft_data **data)
b4aae759 386{
960fa72f 387 struct nft_meta *priv = nft_expr_priv(expr);
b4aae759
FW
388 unsigned int hooks;
389
960fa72f
LZ
390 if (priv->key != NFT_META_PKTTYPE)
391 return 0;
392
36596dad 393 switch (ctx->family) {
b4aae759
FW
394 case NFPROTO_BRIDGE:
395 hooks = 1 << NF_BR_PRE_ROUTING;
396 break;
397 case NFPROTO_NETDEV:
398 hooks = 1 << NF_NETDEV_INGRESS;
399 break;
96d9f2a7
LZ
400 case NFPROTO_IPV4:
401 case NFPROTO_IPV6:
402 case NFPROTO_INET:
403 hooks = 1 << NF_INET_PRE_ROUTING;
404 break;
b4aae759
FW
405 default:
406 return -EOPNOTSUPP;
407 }
408
409 return nft_chain_validate_hooks(ctx->chain, hooks);
410}
30e103fe 411EXPORT_SYMBOL_GPL(nft_meta_set_validate);
b4aae759 412
30e103fe 413int nft_meta_set_init(const struct nft_ctx *ctx,
414 const struct nft_expr *expr,
415 const struct nlattr * const tb[])
e035b77a
ABG
416{
417 struct nft_meta *priv = nft_expr_priv(expr);
d07db988 418 unsigned int len;
e035b77a
ABG
419 int err;
420
421 priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
d2caa696
PM
422 switch (priv->key) {
423 case NFT_META_MARK:
424 case NFT_META_PRIORITY:
b473a1f5
CG
425#ifdef CONFIG_NETWORK_SECMARK
426 case NFT_META_SECMARK:
427#endif
d07db988
PM
428 len = sizeof(u32);
429 break;
d2caa696 430 case NFT_META_NFTRACE:
d07db988 431 len = sizeof(u8);
d2caa696 432 break;
b4aae759 433 case NFT_META_PKTTYPE:
b4aae759
FW
434 len = sizeof(u8);
435 break;
d2caa696
PM
436 default:
437 return -EOPNOTSUPP;
e035b77a
ABG
438 }
439
b1c96ed3 440 priv->sreg = nft_parse_register(tb[NFTA_META_SREG]);
d07db988 441 err = nft_validate_register_load(priv->sreg, len);
b38895c5
PNA
442 if (err < 0)
443 return err;
e035b77a 444
e639f7ab
FW
445 if (priv->key == NFT_META_NFTRACE)
446 static_branch_inc(&nft_trace_enabled);
447
e035b77a 448 return 0;
96518518 449}
30e103fe 450EXPORT_SYMBOL_GPL(nft_meta_set_init);
96518518 451
30e103fe 452int nft_meta_get_dump(struct sk_buff *skb,
453 const struct nft_expr *expr)
96518518
PM
454{
455 const struct nft_meta *priv = nft_expr_priv(expr);
456
e035b77a
ABG
457 if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
458 goto nla_put_failure;
b1c96ed3 459 if (nft_dump_register(skb, NFTA_META_DREG, priv->dreg))
96518518 460 goto nla_put_failure;
e035b77a
ABG
461 return 0;
462
463nla_put_failure:
464 return -1;
465}
30e103fe 466EXPORT_SYMBOL_GPL(nft_meta_get_dump);
e035b77a 467
30e103fe 468int nft_meta_set_dump(struct sk_buff *skb, const struct nft_expr *expr)
e035b77a
ABG
469{
470 const struct nft_meta *priv = nft_expr_priv(expr);
471
96518518
PM
472 if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
473 goto nla_put_failure;
b1c96ed3 474 if (nft_dump_register(skb, NFTA_META_SREG, priv->sreg))
e035b77a
ABG
475 goto nla_put_failure;
476
96518518
PM
477 return 0;
478
479nla_put_failure:
480 return -1;
481}
30e103fe 482EXPORT_SYMBOL_GPL(nft_meta_set_dump);
96518518 483
30e103fe 484void nft_meta_set_destroy(const struct nft_ctx *ctx,
485 const struct nft_expr *expr)
e639f7ab
FW
486{
487 const struct nft_meta *priv = nft_expr_priv(expr);
488
489 if (priv->key == NFT_META_NFTRACE)
490 static_branch_dec(&nft_trace_enabled);
491}
30e103fe 492EXPORT_SYMBOL_GPL(nft_meta_set_destroy);
e639f7ab 493
c9626a2c
PNA
494static int nft_meta_get_offload(struct nft_offload_ctx *ctx,
495 struct nft_flow_rule *flow,
496 const struct nft_expr *expr)
497{
498 const struct nft_meta *priv = nft_expr_priv(expr);
499 struct nft_offload_reg *reg = &ctx->regs[priv->dreg];
500
501 switch (priv->key) {
502 case NFT_META_PROTOCOL:
503 NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic, n_proto,
504 sizeof(__u16), reg);
505 nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_NETWORK);
506 break;
507 case NFT_META_L4PROTO:
508 NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic, ip_proto,
509 sizeof(__u8), reg);
510 nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_TRANSPORT);
511 break;
512 default:
513 return -EOPNOTSUPP;
514 }
515
516 return 0;
517}
518
e035b77a 519static const struct nft_expr_ops nft_meta_get_ops = {
ef1f7df9 520 .type = &nft_meta_type,
96518518 521 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
e035b77a 522 .eval = nft_meta_get_eval,
d2caa696 523 .init = nft_meta_get_init,
e035b77a 524 .dump = nft_meta_get_dump,
f6931f5f 525 .validate = nft_meta_get_validate,
c9626a2c 526 .offload = nft_meta_get_offload,
ef1f7df9
PM
527};
528
e035b77a
ABG
529static const struct nft_expr_ops nft_meta_set_ops = {
530 .type = &nft_meta_type,
531 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
532 .eval = nft_meta_set_eval,
d2caa696 533 .init = nft_meta_set_init,
e639f7ab 534 .destroy = nft_meta_set_destroy,
e035b77a 535 .dump = nft_meta_set_dump,
960fa72f 536 .validate = nft_meta_set_validate,
e035b77a
ABG
537};
538
539static const struct nft_expr_ops *
540nft_meta_select_ops(const struct nft_ctx *ctx,
541 const struct nlattr * const tb[])
542{
543 if (tb[NFTA_META_KEY] == NULL)
544 return ERR_PTR(-EINVAL);
545
546 if (tb[NFTA_META_DREG] && tb[NFTA_META_SREG])
547 return ERR_PTR(-EINVAL);
548
0ef1efd1
PNA
549#ifdef CONFIG_NF_TABLES_BRIDGE
550 if (ctx->family == NFPROTO_BRIDGE)
551 return ERR_PTR(-EAGAIN);
552#endif
e035b77a
ABG
553 if (tb[NFTA_META_DREG])
554 return &nft_meta_get_ops;
555
556 if (tb[NFTA_META_SREG])
557 return &nft_meta_set_ops;
558
559 return ERR_PTR(-EINVAL);
560}
561
8a22543c 562struct nft_expr_type nft_meta_type __read_mostly = {
ef1f7df9 563 .name = "meta",
d4ef3835 564 .select_ops = nft_meta_select_ops,
96518518
PM
565 .policy = nft_meta_policy,
566 .maxattr = NFTA_META_MAX,
ef1f7df9 567 .owner = THIS_MODULE,
96518518 568};
fb961945
CG
569
570#ifdef CONFIG_NETWORK_SECMARK
571struct nft_secmark {
572 u32 secid;
573 char *ctx;
574};
575
576static const struct nla_policy nft_secmark_policy[NFTA_SECMARK_MAX + 1] = {
577 [NFTA_SECMARK_CTX] = { .type = NLA_STRING, .len = NFT_SECMARK_CTX_MAXLEN },
578};
579
580static int nft_secmark_compute_secid(struct nft_secmark *priv)
581{
582 u32 tmp_secid = 0;
583 int err;
584
585 err = security_secctx_to_secid(priv->ctx, strlen(priv->ctx), &tmp_secid);
586 if (err)
587 return err;
588
589 if (!tmp_secid)
590 return -ENOENT;
591
592 err = security_secmark_relabel_packet(tmp_secid);
593 if (err)
594 return err;
595
596 priv->secid = tmp_secid;
597 return 0;
598}
599
600static void nft_secmark_obj_eval(struct nft_object *obj, struct nft_regs *regs,
601 const struct nft_pktinfo *pkt)
602{
603 const struct nft_secmark *priv = nft_obj_data(obj);
604 struct sk_buff *skb = pkt->skb;
605
606 skb->secmark = priv->secid;
607}
608
609static int nft_secmark_obj_init(const struct nft_ctx *ctx,
610 const struct nlattr * const tb[],
611 struct nft_object *obj)
612{
613 struct nft_secmark *priv = nft_obj_data(obj);
614 int err;
615
616 if (tb[NFTA_SECMARK_CTX] == NULL)
617 return -EINVAL;
618
619 priv->ctx = nla_strdup(tb[NFTA_SECMARK_CTX], GFP_KERNEL);
620 if (!priv->ctx)
621 return -ENOMEM;
622
623 err = nft_secmark_compute_secid(priv);
624 if (err) {
625 kfree(priv->ctx);
626 return err;
627 }
628
629 security_secmark_refcount_inc();
630
631 return 0;
632}
633
634static int nft_secmark_obj_dump(struct sk_buff *skb, struct nft_object *obj,
635 bool reset)
636{
637 struct nft_secmark *priv = nft_obj_data(obj);
638 int err;
639
640 if (nla_put_string(skb, NFTA_SECMARK_CTX, priv->ctx))
641 return -1;
642
643 if (reset) {
644 err = nft_secmark_compute_secid(priv);
645 if (err)
646 return err;
647 }
648
649 return 0;
650}
651
652static void nft_secmark_obj_destroy(const struct nft_ctx *ctx, struct nft_object *obj)
653{
654 struct nft_secmark *priv = nft_obj_data(obj);
655
656 security_secmark_refcount_dec();
657
658 kfree(priv->ctx);
659}
660
661static const struct nft_object_ops nft_secmark_obj_ops = {
662 .type = &nft_secmark_obj_type,
663 .size = sizeof(struct nft_secmark),
664 .init = nft_secmark_obj_init,
665 .eval = nft_secmark_obj_eval,
666 .dump = nft_secmark_obj_dump,
667 .destroy = nft_secmark_obj_destroy,
668};
669struct nft_object_type nft_secmark_obj_type __read_mostly = {
670 .type = NFT_OBJECT_SECMARK,
671 .ops = &nft_secmark_obj_ops,
672 .maxattr = NFTA_SECMARK_MAX,
673 .policy = nft_secmark_policy,
674 .owner = THIS_MODULE,
675};
676#endif /* CONFIG_NETWORK_SECMARK */