~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/netfilter/nft_meta.c

Version: ~ [ linux-5.19-rc8 ] ~ [ linux-5.18.14 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.57 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.133 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.207 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.253 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.289 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.324 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.302 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
  4  * Copyright (c) 2014 Intel Corporation
  5  * Author: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
  6  *
  7  * Development of this code funded by Astaro AG (http://www.astaro.com/)
  8  */
  9 
 10 #include <linux/kernel.h>
 11 #include <linux/netlink.h>
 12 #include <linux/netfilter.h>
 13 #include <linux/netfilter/nf_tables.h>
 14 #include <linux/in.h>
 15 #include <linux/ip.h>
 16 #include <linux/ipv6.h>
 17 #include <linux/smp.h>
 18 #include <linux/static_key.h>
 19 #include <net/dst.h>
 20 #include <net/ip.h>
 21 #include <net/sock.h>
 22 #include <net/tcp_states.h> /* for TCP_TIME_WAIT */
 23 #include <net/netfilter/nf_tables.h>
 24 #include <net/netfilter/nf_tables_core.h>
 25 #include <net/netfilter/nft_meta.h>
 26 #include <net/netfilter/nf_tables_offload.h>
 27 
 28 #include <uapi/linux/netfilter_bridge.h> /* NF_BR_PRE_ROUTING */
 29 
 30 #define NFT_META_SECS_PER_MINUTE        60
 31 #define NFT_META_SECS_PER_HOUR          3600
 32 #define NFT_META_SECS_PER_DAY           86400
 33 #define NFT_META_DAYS_PER_WEEK          7
 34 
 35 static DEFINE_PER_CPU(struct rnd_state, nft_prandom_state);
 36 
 37 static u8 nft_meta_weekday(void)
 38 {
 39         time64_t secs = ktime_get_real_seconds();
 40         unsigned int dse;
 41         u8 wday;
 42 
 43         secs -= NFT_META_SECS_PER_MINUTE * sys_tz.tz_minuteswest;
 44         dse = div_u64(secs, NFT_META_SECS_PER_DAY);
 45         wday = (4 + dse) % NFT_META_DAYS_PER_WEEK;
 46 
 47         return wday;
 48 }
 49 
 50 static u32 nft_meta_hour(time64_t secs)
 51 {
 52         struct tm tm;
 53 
 54         time64_to_tm(secs, 0, &tm);
 55 
 56         return tm.tm_hour * NFT_META_SECS_PER_HOUR
 57                 + tm.tm_min * NFT_META_SECS_PER_MINUTE
 58                 + tm.tm_sec;
 59 }
 60 
 61 static noinline_for_stack void
 62 nft_meta_get_eval_time(enum nft_meta_keys key,
 63                        u32 *dest)
 64 {
 65         switch (key) {
 66         case NFT_META_TIME_NS:
 67                 nft_reg_store64(dest, ktime_get_real_ns());
 68                 break;
 69         case NFT_META_TIME_DAY:
 70                 nft_reg_store8(dest, nft_meta_weekday());
 71                 break;
 72         case NFT_META_TIME_HOUR:
 73                 *dest = nft_meta_hour(ktime_get_real_seconds());
 74                 break;
 75         default:
 76                 break;
 77         }
 78 }
 79 
 80 static noinline bool
 81 nft_meta_get_eval_pkttype_lo(const struct nft_pktinfo *pkt,
 82                              u32 *dest)
 83 {
 84         const struct sk_buff *skb = pkt->skb;
 85 
 86         switch (nft_pf(pkt)) {
 87         case NFPROTO_IPV4:
 88                 if (ipv4_is_multicast(ip_hdr(skb)->daddr))
 89                         nft_reg_store8(dest, PACKET_MULTICAST);
 90                 else
 91                         nft_reg_store8(dest, PACKET_BROADCAST);
 92                 break;
 93         case NFPROTO_IPV6:
 94                 nft_reg_store8(dest, PACKET_MULTICAST);
 95                 break;
 96         case NFPROTO_NETDEV:
 97                 switch (skb->protocol) {
 98                 case htons(ETH_P_IP): {
 99                         int noff = skb_network_offset(skb);
100                         struct iphdr *iph, _iph;
101 
102                         iph = skb_header_pointer(skb, noff,
103                                                  sizeof(_iph), &_iph);
104                         if (!iph)
105                                 return false;
106 
107                         if (ipv4_is_multicast(iph->daddr))
108                                 nft_reg_store8(dest, PACKET_MULTICAST);
109                         else
110                                 nft_reg_store8(dest, PACKET_BROADCAST);
111 
112                         break;
113                 }
114                 case htons(ETH_P_IPV6):
115                         nft_reg_store8(dest, PACKET_MULTICAST);
116                         break;
117                 default:
118                         WARN_ON_ONCE(1);
119                         return false;
120                 }
121                 break;
122         default:
123                 WARN_ON_ONCE(1);
124                 return false;
125         }
126 
127         return true;
128 }
129 
130 static noinline bool
131 nft_meta_get_eval_skugid(enum nft_meta_keys key,
132                          u32 *dest,
133                          const struct nft_pktinfo *pkt)
134 {
135         struct sock *sk = skb_to_full_sk(pkt->skb);
136         struct socket *sock;
137 
138         if (!sk || !sk_fullsock(sk) || !net_eq(nft_net(pkt), sock_net(sk)))
139                 return false;
140 
141         read_lock_bh(&sk->sk_callback_lock);
142         sock = sk->sk_socket;
143         if (!sock || !sock->file) {
144                 read_unlock_bh(&sk->sk_callback_lock);
145                 return false;
146         }
147 
148         switch (key) {
149         case NFT_META_SKUID:
150                 *dest = from_kuid_munged(sock_net(sk)->user_ns,
151                                          sock->file->f_cred->fsuid);
152                 break;
153         case NFT_META_SKGID:
154                 *dest = from_kgid_munged(sock_net(sk)->user_ns,
155                                          sock->file->f_cred->fsgid);
156                 break;
157         default:
158                 break;
159         }
160 
161         read_unlock_bh(&sk->sk_callback_lock);
162         return true;
163 }
164 
165 #ifdef CONFIG_CGROUP_NET_CLASSID
166 static noinline bool
167 nft_meta_get_eval_cgroup(u32 *dest, const struct nft_pktinfo *pkt)
168 {
169         struct sock *sk = skb_to_full_sk(pkt->skb);
170 
171         if (!sk || !sk_fullsock(sk) || !net_eq(nft_net(pkt), sock_net(sk)))
172                 return false;
173 
174         *dest = sock_cgroup_classid(&sk->sk_cgrp_data);
175         return true;
176 }
177 #endif
178 
179 static noinline bool nft_meta_get_eval_kind(enum nft_meta_keys key,
180                                             u32 *dest,
181                                             const struct nft_pktinfo *pkt)
182 {
183         const struct net_device *in = nft_in(pkt), *out = nft_out(pkt);
184 
185         switch (key) {
186         case NFT_META_IIFKIND:
187                 if (!in || !in->rtnl_link_ops)
188                         return false;
189                 strncpy((char *)dest, in->rtnl_link_ops->kind, IFNAMSIZ);
190                 break;
191         case NFT_META_OIFKIND:
192                 if (!out || !out->rtnl_link_ops)
193                         return false;
194                 strncpy((char *)dest, out->rtnl_link_ops->kind, IFNAMSIZ);
195                 break;
196         default:
197                 return false;
198         }
199 
200         return true;
201 }
202 
203 static void nft_meta_store_ifindex(u32 *dest, const struct net_device *dev)
204 {
205         *dest = dev ? dev->ifindex : 0;
206 }
207 
208 static void nft_meta_store_ifname(u32 *dest, const struct net_device *dev)
209 {
210         strncpy((char *)dest, dev ? dev->name : "", IFNAMSIZ);
211 }
212 
213 static bool nft_meta_store_iftype(u32 *dest, const struct net_device *dev)
214 {
215         if (!dev)
216                 return false;
217 
218         nft_reg_store16(dest, dev->type);
219         return true;
220 }
221 
222 static bool nft_meta_store_ifgroup(u32 *dest, const struct net_device *dev)
223 {
224         if (!dev)
225                 return false;
226 
227         *dest = dev->group;
228         return true;
229 }
230 
231 static bool nft_meta_get_eval_ifname(enum nft_meta_keys key, u32 *dest,
232                                      const struct nft_pktinfo *pkt)
233 {
234         switch (key) {
235         case NFT_META_IIFNAME:
236                 nft_meta_store_ifname(dest, nft_in(pkt));
237                 break;
238         case NFT_META_OIFNAME:
239                 nft_meta_store_ifname(dest, nft_out(pkt));
240                 break;
241         case NFT_META_IIF:
242                 nft_meta_store_ifindex(dest, nft_in(pkt));
243                 break;
244         case NFT_META_OIF:
245                 nft_meta_store_ifindex(dest, nft_out(pkt));
246                 break;
247         case NFT_META_IFTYPE:
248                 if (!nft_meta_store_iftype(dest, pkt->skb->dev))
249                         return false;
250                 break;
251         case __NFT_META_IIFTYPE:
252                 if (!nft_meta_store_iftype(dest, nft_in(pkt)))
253                         return false;
254                 break;
255         case NFT_META_OIFTYPE:
256                 if (!nft_meta_store_iftype(dest, nft_out(pkt)))
257                         return false;
258                 break;
259         case NFT_META_IIFGROUP:
260                 if (!nft_meta_store_ifgroup(dest, nft_in(pkt)))
261                         return false;
262                 break;
263         case NFT_META_OIFGROUP:
264                 if (!nft_meta_store_ifgroup(dest, nft_out(pkt)))
265                         return false;
266                 break;
267         default:
268                 return false;
269         }
270 
271         return true;
272 }
273 
274 static noinline u32 nft_prandom_u32(void)
275 {
276         struct rnd_state *state = this_cpu_ptr(&nft_prandom_state);
277 
278         return prandom_u32_state(state);
279 }
280 
281 #ifdef CONFIG_IP_ROUTE_CLASSID
282 static noinline bool
283 nft_meta_get_eval_rtclassid(const struct sk_buff *skb, u32 *dest)
284 {
285         const struct dst_entry *dst = skb_dst(skb);
286 
287         if (!dst)
288                 return false;
289 
290         *dest = dst->tclassid;
291         return true;
292 }
293 #endif
294 
295 static noinline u32 nft_meta_get_eval_sdif(const struct nft_pktinfo *pkt)
296 {
297         switch (nft_pf(pkt)) {
298         case NFPROTO_IPV4:
299                 return inet_sdif(pkt->skb);
300         case NFPROTO_IPV6:
301                 return inet6_sdif(pkt->skb);
302         }
303 
304         return 0;
305 }
306 
307 static noinline void
308 nft_meta_get_eval_sdifname(u32 *dest, const struct nft_pktinfo *pkt)
309 {
310         u32 sdif = nft_meta_get_eval_sdif(pkt);
311         const struct net_device *dev;
312 
313         dev = sdif ? dev_get_by_index_rcu(nft_net(pkt), sdif) : NULL;
314         nft_meta_store_ifname(dest, dev);
315 }
316 
317 void nft_meta_get_eval(const struct nft_expr *expr,
318                        struct nft_regs *regs,
319                        const struct nft_pktinfo *pkt)
320 {
321         const struct nft_meta *priv = nft_expr_priv(expr);
322         const struct sk_buff *skb = pkt->skb;
323         u32 *dest = &regs->data[priv->dreg];
324 
325         switch (priv->key) {
326         case NFT_META_LEN:
327                 *dest = skb->len;
328                 break;
329         case NFT_META_PROTOCOL:
330                 nft_reg_store16(dest, (__force u16)skb->protocol);
331                 break;
332         case NFT_META_NFPROTO:
333                 nft_reg_store8(dest, nft_pf(pkt));
334                 break;
335         case NFT_META_L4PROTO:
336                 if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
337                         goto err;
338                 nft_reg_store8(dest, pkt->tprot);
339                 break;
340         case NFT_META_PRIORITY:
341                 *dest = skb->priority;
342                 break;
343         case NFT_META_MARK:
344                 *dest = skb->mark;
345                 break;
346         case NFT_META_IIF:
347         case NFT_META_OIF:
348         case NFT_META_IIFNAME:
349         case NFT_META_OIFNAME:
350         case NFT_META_IIFTYPE:
351         case NFT_META_OIFTYPE:
352         case NFT_META_IIFGROUP:
353         case NFT_META_OIFGROUP:
354                 if (!nft_meta_get_eval_ifname(priv->key, dest, pkt))
355                         goto err;
356                 break;
357         case NFT_META_SKUID:
358         case NFT_META_SKGID:
359                 if (!nft_meta_get_eval_skugid(priv->key, dest, pkt))
360                         goto err;
361                 break;
362 #ifdef CONFIG_IP_ROUTE_CLASSID
363         case NFT_META_RTCLASSID:
364                 if (!nft_meta_get_eval_rtclassid(skb, dest))
365                         goto err;
366                 break;
367 #endif
368 #ifdef CONFIG_NETWORK_SECMARK
369         case NFT_META_SECMARK:
370                 *dest = skb->secmark;
371                 break;
372 #endif
373         case NFT_META_PKTTYPE:
374                 if (skb->pkt_type != PACKET_LOOPBACK) {
375                         nft_reg_store8(dest, skb->pkt_type);
376                         break;
377                 }
378 
379                 if (!nft_meta_get_eval_pkttype_lo(pkt, dest))
380                         goto err;
381                 break;
382         case NFT_META_CPU:
383                 *dest = raw_smp_processor_id();
384                 break;
385 #ifdef CONFIG_CGROUP_NET_CLASSID
386         case NFT_META_CGROUP:
387                 if (!nft_meta_get_eval_cgroup(dest, pkt))
388                         goto err;
389                 break;
390 #endif
391         case NFT_META_PRANDOM:
392                 *dest = nft_prandom_u32();
393                 break;
394 #ifdef CONFIG_XFRM
395         case NFT_META_SECPATH:
396                 nft_reg_store8(dest, secpath_exists(skb));
397                 break;
398 #endif
399         case NFT_META_IIFKIND:
400         case NFT_META_OIFKIND:
401                 if (!nft_meta_get_eval_kind(priv->key, dest, pkt))
402                         goto err;
403                 break;
404         case NFT_META_TIME_NS:
405         case NFT_META_TIME_DAY:
406         case NFT_META_TIME_HOUR:
407                 nft_meta_get_eval_time(priv->key, dest);
408                 break;
409         case NFT_META_SDIF:
410                 *dest = nft_meta_get_eval_sdif(pkt);
411                 break;
412         case NFT_META_SDIFNAME:
413                 nft_meta_get_eval_sdifname(dest, pkt);
414                 break;
415         default:
416                 WARN_ON(1);
417                 goto err;
418         }
419         return;
420 
421 err:
422         regs->verdict.code = NFT_BREAK;
423 }
424 EXPORT_SYMBOL_GPL(nft_meta_get_eval);
425 
426 void nft_meta_set_eval(const struct nft_expr *expr,
427                        struct nft_regs *regs,
428                        const struct nft_pktinfo *pkt)
429 {
430         const struct nft_meta *meta = nft_expr_priv(expr);
431         struct sk_buff *skb = pkt->skb;
432         u32 *sreg = &regs->data[meta->sreg];
433         u32 value = *sreg;
434         u8 value8;
435 
436         switch (meta->key) {
437         case NFT_META_MARK:
438                 skb->mark = value;
439                 break;
440         case NFT_META_PRIORITY:
441                 skb->priority = value;
442                 break;
443         case NFT_META_PKTTYPE:
444                 value8 = nft_reg_load8(sreg);
445 
446                 if (skb->pkt_type != value8 &&
447                     skb_pkt_type_ok(value8) &&
448                     skb_pkt_type_ok(skb->pkt_type))
449                         skb->pkt_type = value8;
450                 break;
451         case NFT_META_NFTRACE:
452                 value8 = nft_reg_load8(sreg);
453 
454                 skb->nf_trace = !!value8;
455                 break;
456 #ifdef CONFIG_NETWORK_SECMARK
457         case NFT_META_SECMARK:
458                 skb->secmark = value;
459                 break;
460 #endif
461         default:
462                 WARN_ON(1);
463         }
464 }
465 EXPORT_SYMBOL_GPL(nft_meta_set_eval);
466 
467 const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = {
468         [NFTA_META_DREG]        = { .type = NLA_U32 },
469         [NFTA_META_KEY]         = { .type = NLA_U32 },
470         [NFTA_META_SREG]        = { .type = NLA_U32 },
471 };
472 EXPORT_SYMBOL_GPL(nft_meta_policy);
473 
474 int nft_meta_get_init(const struct nft_ctx *ctx,
475                       const struct nft_expr *expr,
476                       const struct nlattr * const tb[])
477 {
478         struct nft_meta *priv = nft_expr_priv(expr);
479         unsigned int len;
480 
481         priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
482         switch (priv->key) {
483         case NFT_META_PROTOCOL:
484         case NFT_META_IIFTYPE:
485         case NFT_META_OIFTYPE:
486                 len = sizeof(u16);
487                 break;
488         case NFT_META_NFPROTO:
489         case NFT_META_L4PROTO:
490         case NFT_META_LEN:
491         case NFT_META_PRIORITY:
492         case NFT_META_MARK:
493         case NFT_META_IIF:
494         case NFT_META_OIF:
495         case NFT_META_SDIF:
496         case NFT_META_SKUID:
497         case NFT_META_SKGID:
498 #ifdef CONFIG_IP_ROUTE_CLASSID
499         case NFT_META_RTCLASSID:
500 #endif
501 #ifdef CONFIG_NETWORK_SECMARK
502         case NFT_META_SECMARK:
503 #endif
504         case NFT_META_PKTTYPE:
505         case NFT_META_CPU:
506         case NFT_META_IIFGROUP:
507         case NFT_META_OIFGROUP:
508 #ifdef CONFIG_CGROUP_NET_CLASSID
509         case NFT_META_CGROUP:
510 #endif
511                 len = sizeof(u32);
512                 break;
513         case NFT_META_IIFNAME:
514         case NFT_META_OIFNAME:
515         case NFT_META_IIFKIND:
516         case NFT_META_OIFKIND:
517         case NFT_META_SDIFNAME:
518                 len = IFNAMSIZ;
519                 break;
520         case NFT_META_PRANDOM:
521                 prandom_init_once(&nft_prandom_state);
522                 len = sizeof(u32);
523                 break;
524 #ifdef CONFIG_XFRM
525         case NFT_META_SECPATH:
526                 len = sizeof(u8);
527                 break;
528 #endif
529         case NFT_META_TIME_NS:
530                 len = sizeof(u64);
531                 break;
532         case NFT_META_TIME_DAY:
533                 len = sizeof(u8);
534                 break;
535         case NFT_META_TIME_HOUR:
536                 len = sizeof(u32);
537                 break;
538         default:
539                 return -EOPNOTSUPP;
540         }
541 
542         return nft_parse_register_store(ctx, tb[NFTA_META_DREG], &priv->dreg,
543                                         NULL, NFT_DATA_VALUE, len);
544 }
545 EXPORT_SYMBOL_GPL(nft_meta_get_init);
546 
547 static int nft_meta_get_validate_sdif(const struct nft_ctx *ctx)
548 {
549         unsigned int hooks;
550 
551         switch (ctx->family) {
552         case NFPROTO_IPV4:
553         case NFPROTO_IPV6:
554         case NFPROTO_INET:
555                 hooks = (1 << NF_INET_LOCAL_IN) |
556                         (1 << NF_INET_FORWARD);
557                 break;
558         default:
559                 return -EOPNOTSUPP;
560         }
561 
562         return nft_chain_validate_hooks(ctx->chain, hooks);
563 }
564 
565 static int nft_meta_get_validate_xfrm(const struct nft_ctx *ctx)
566 {
567 #ifdef CONFIG_XFRM
568         unsigned int hooks;
569 
570         switch (ctx->family) {
571         case NFPROTO_NETDEV:
572                 hooks = 1 << NF_NETDEV_INGRESS;
573                 break;
574         case NFPROTO_IPV4:
575         case NFPROTO_IPV6:
576         case NFPROTO_INET:
577                 hooks = (1 << NF_INET_PRE_ROUTING) |
578                         (1 << NF_INET_LOCAL_IN) |
579                         (1 << NF_INET_FORWARD);
580                 break;
581         default:
582                 return -EOPNOTSUPP;
583         }
584 
585         return nft_chain_validate_hooks(ctx->chain, hooks);
586 #else
587         return 0;
588 #endif
589 }
590 
591 static int nft_meta_get_validate(const struct nft_ctx *ctx,
592                                  const struct nft_expr *expr,
593                                  const struct nft_data **data)
594 {
595         const struct nft_meta *priv = nft_expr_priv(expr);
596 
597         switch (priv->key) {
598         case NFT_META_SECPATH:
599                 return nft_meta_get_validate_xfrm(ctx);
600         case NFT_META_SDIF:
601         case NFT_META_SDIFNAME:
602                 return nft_meta_get_validate_sdif(ctx);
603         default:
604                 break;
605         }
606 
607         return 0;
608 }
609 
610 int nft_meta_set_validate(const struct nft_ctx *ctx,
611                           const struct nft_expr *expr,
612                           const struct nft_data **data)
613 {
614         struct nft_meta *priv = nft_expr_priv(expr);
615         unsigned int hooks;
616 
617         if (priv->key != NFT_META_PKTTYPE)
618                 return 0;
619 
620         switch (ctx->family) {
621         case NFPROTO_BRIDGE:
622                 hooks = 1 << NF_BR_PRE_ROUTING;
623                 break;
624         case NFPROTO_NETDEV:
625                 hooks = 1 << NF_NETDEV_INGRESS;
626                 break;
627         case NFPROTO_IPV4:
628         case NFPROTO_IPV6:
629         case NFPROTO_INET:
630                 hooks = 1 << NF_INET_PRE_ROUTING;
631                 break;
632         default:
633                 return -EOPNOTSUPP;
634         }
635 
636         return nft_chain_validate_hooks(ctx->chain, hooks);
637 }
638 EXPORT_SYMBOL_GPL(nft_meta_set_validate);
639 
640 int nft_meta_set_init(const struct nft_ctx *ctx,
641                       const struct nft_expr *expr,
642                       const struct nlattr * const tb[])
643 {
644         struct nft_meta *priv = nft_expr_priv(expr);
645         unsigned int len;
646         int err;
647 
648         priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
649         switch (priv->key) {
650         case NFT_META_MARK:
651         case NFT_META_PRIORITY:
652 #ifdef CONFIG_NETWORK_SECMARK
653         case NFT_META_SECMARK:
654 #endif
655                 len = sizeof(u32);
656                 break;
657         case NFT_META_NFTRACE:
658                 len = sizeof(u8);
659                 break;
660         case NFT_META_PKTTYPE:
661                 len = sizeof(u8);
662                 break;
663         default:
664                 return -EOPNOTSUPP;
665         }
666 
667         err = nft_parse_register_load(tb[NFTA_META_SREG], &priv->sreg, len);
668         if (err < 0)
669                 return err;
670 
671         if (priv->key == NFT_META_NFTRACE)
672                 static_branch_inc(&nft_trace_enabled);
673 
674         return 0;
675 }
676 EXPORT_SYMBOL_GPL(nft_meta_set_init);
677 
678 int nft_meta_get_dump(struct sk_buff *skb,
679                       const struct nft_expr *expr)
680 {
681         const struct nft_meta *priv = nft_expr_priv(expr);
682 
683         if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
684                 goto nla_put_failure;
685         if (nft_dump_register(skb, NFTA_META_DREG, priv->dreg))
686                 goto nla_put_failure;
687         return 0;
688 
689 nla_put_failure:
690         return -1;
691 }
692 EXPORT_SYMBOL_GPL(nft_meta_get_dump);
693 
694 int nft_meta_set_dump(struct sk_buff *skb, const struct nft_expr *expr)
695 {
696         const struct nft_meta *priv = nft_expr_priv(expr);
697 
698         if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
699                 goto nla_put_failure;
700         if (nft_dump_register(skb, NFTA_META_SREG, priv->sreg))
701                 goto nla_put_failure;
702 
703         return 0;
704 
705 nla_put_failure:
706         return -1;
707 }
708 EXPORT_SYMBOL_GPL(nft_meta_set_dump);
709 
710 void nft_meta_set_destroy(const struct nft_ctx *ctx,
711                           const struct nft_expr *expr)
712 {
713         const struct nft_meta *priv = nft_expr_priv(expr);
714 
715         if (priv->key == NFT_META_NFTRACE)
716                 static_branch_dec(&nft_trace_enabled);
717 }
718 EXPORT_SYMBOL_GPL(nft_meta_set_destroy);
719 
720 static int nft_meta_get_offload(struct nft_offload_ctx *ctx,
721                                 struct nft_flow_rule *flow,
722                                 const struct nft_expr *expr)
723 {
724         const struct nft_meta *priv = nft_expr_priv(expr);
725         struct nft_offload_reg *reg = &ctx->regs[priv->dreg];
726 
727         switch (priv->key) {
728         case NFT_META_PROTOCOL:
729                 NFT_OFFLOAD_MATCH_EXACT(FLOW_DISSECTOR_KEY_BASIC, basic, n_proto,
730                                         sizeof(__u16), reg);
731                 nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_NETWORK);
732                 break;
733         case NFT_META_L4PROTO:
734                 NFT_OFFLOAD_MATCH_EXACT(FLOW_DISSECTOR_KEY_BASIC, basic, ip_proto,
735                                         sizeof(__u8), reg);
736                 nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_TRANSPORT);
737                 break;
738         case NFT_META_IIF:
739                 NFT_OFFLOAD_MATCH_EXACT(FLOW_DISSECTOR_KEY_META, meta,
740                                         ingress_ifindex, sizeof(__u32), reg);
741                 break;
742         case NFT_META_IIFTYPE:
743                 NFT_OFFLOAD_MATCH_EXACT(FLOW_DISSECTOR_KEY_META, meta,
744                                         ingress_iftype, sizeof(__u16), reg);
745                 break;
746         default:
747                 return -EOPNOTSUPP;
748         }
749 
750         return 0;
751 }
752 
753 static const struct nft_expr_ops nft_meta_get_ops = {
754         .type           = &nft_meta_type,
755         .size           = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
756         .eval           = nft_meta_get_eval,
757         .init           = nft_meta_get_init,
758         .dump           = nft_meta_get_dump,
759         .validate       = nft_meta_get_validate,
760         .offload        = nft_meta_get_offload,
761 };
762 
763 static const struct nft_expr_ops nft_meta_set_ops = {
764         .type           = &nft_meta_type,
765         .size           = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
766         .eval           = nft_meta_set_eval,
767         .init           = nft_meta_set_init,
768         .destroy        = nft_meta_set_destroy,
769         .dump           = nft_meta_set_dump,
770         .validate       = nft_meta_set_validate,
771 };
772 
773 static const struct nft_expr_ops *
774 nft_meta_select_ops(const struct nft_ctx *ctx,
775                     const struct nlattr * const tb[])
776 {
777         if (tb[NFTA_META_KEY] == NULL)
778                 return ERR_PTR(-EINVAL);
779 
780         if (tb[NFTA_META_DREG] && tb[NFTA_META_SREG])
781                 return ERR_PTR(-EINVAL);
782 
783 #if IS_ENABLED(CONFIG_NF_TABLES_BRIDGE) && IS_MODULE(CONFIG_NFT_BRIDGE_META)
784         if (ctx->family == NFPROTO_BRIDGE)
785                 return ERR_PTR(-EAGAIN);
786 #endif
787         if (tb[NFTA_META_DREG])
788                 return &nft_meta_get_ops;
789 
790         if (tb[NFTA_META_SREG])
791                 return &nft_meta_set_ops;
792 
793         return ERR_PTR(-EINVAL);
794 }
795 
796 struct nft_expr_type nft_meta_type __read_mostly = {
797         .name           = "meta",
798         .select_ops     = nft_meta_select_ops,
799         .policy         = nft_meta_policy,
800         .maxattr        = NFTA_META_MAX,
801         .owner          = THIS_MODULE,
802 };
803 
804 #ifdef CONFIG_NETWORK_SECMARK
805 struct nft_secmark {
806         u32 secid;
807         char *ctx;
808 };
809 
810 static const struct nla_policy nft_secmark_policy[NFTA_SECMARK_MAX + 1] = {
811         [NFTA_SECMARK_CTX]     = { .type = NLA_STRING, .len = NFT_SECMARK_CTX_MAXLEN },
812 };
813 
814 static int nft_secmark_compute_secid(struct nft_secmark *priv)
815 {
816         u32 tmp_secid = 0;
817         int err;
818 
819         err = security_secctx_to_secid(priv->ctx, strlen(priv->ctx), &tmp_secid);
820         if (err)
821                 return err;
822 
823         if (!tmp_secid)
824                 return -ENOENT;
825 
826         err = security_secmark_relabel_packet(tmp_secid);
827         if (err)
828                 return err;
829 
830         priv->secid = tmp_secid;
831         return 0;
832 }
833 
834 static void nft_secmark_obj_eval(struct nft_object *obj, struct nft_regs *regs,
835                                  const struct nft_pktinfo *pkt)
836 {
837         const struct nft_secmark *priv = nft_obj_data(obj);
838         struct sk_buff *skb = pkt->skb;
839 
840         skb->secmark = priv->secid;
841 }
842 
843 static int nft_secmark_obj_init(const struct nft_ctx *ctx,
844                                 const struct nlattr * const tb[],
845                                 struct nft_object *obj)
846 {
847         struct nft_secmark *priv = nft_obj_data(obj);
848         int err;
849 
850         if (tb[NFTA_SECMARK_CTX] == NULL)
851                 return -EINVAL;
852 
853         priv->ctx = nla_strdup(tb[NFTA_SECMARK_CTX], GFP_KERNEL);
854         if (!priv->ctx)
855                 return -ENOMEM;
856 
857         err = nft_secmark_compute_secid(priv);
858         if (err) {
859                 kfree(priv->ctx);
860                 return err;
861         }
862 
863         security_secmark_refcount_inc();
864 
865         return 0;
866 }
867 
868 static int nft_secmark_obj_dump(struct sk_buff *skb, struct nft_object *obj,
869                                 bool reset)
870 {
871         struct nft_secmark *priv = nft_obj_data(obj);
872         int err;
873 
874         if (nla_put_string(skb, NFTA_SECMARK_CTX, priv->ctx))
875                 return -1;
876 
877         if (reset) {
878                 err = nft_secmark_compute_secid(priv);
879                 if (err)
880                         return err;
881         }
882 
883         return 0;
884 }
885 
886 static void nft_secmark_obj_destroy(const struct nft_ctx *ctx, struct nft_object *obj)
887 {
888         struct nft_secmark *priv = nft_obj_data(obj);
889 
890         security_secmark_refcount_dec();
891 
892         kfree(priv->ctx);
893 }
894 
895 static const struct nft_object_ops nft_secmark_obj_ops = {
896         .type           = &nft_secmark_obj_type,
897         .size           = sizeof(struct nft_secmark),
898         .init           = nft_secmark_obj_init,
899         .eval           = nft_secmark_obj_eval,
900         .dump           = nft_secmark_obj_dump,
901         .destroy        = nft_secmark_obj_destroy,
902 };
903 struct nft_object_type nft_secmark_obj_type __read_mostly = {
904         .type           = NFT_OBJECT_SECMARK,
905         .ops            = &nft_secmark_obj_ops,
906         .maxattr        = NFTA_SECMARK_MAX,
907         .policy         = nft_secmark_policy,
908         .owner          = THIS_MODULE,
909 };
910 #endif /* CONFIG_NETWORK_SECMARK */
911 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp