LCOV - code coverage report
Current view: top level - net/netfilter - core.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 16 274 5.8 %
Date: 2021-04-22 12:43:58 Functions: 3 22 13.6 %

          Line data    Source code
       1             : /* netfilter.c: look after the filters for various protocols.
       2             :  * Heavily influenced by the old firewall.c by David Bonn and Alan Cox.
       3             :  *
       4             :  * Thanks to Rob `CmdrTaco' Malda for not influencing this code in any
       5             :  * way.
       6             :  *
       7             :  * This code is GPL.
       8             :  */
       9             : #include <linux/kernel.h>
      10             : #include <linux/netfilter.h>
      11             : #include <net/protocol.h>
      12             : #include <linux/init.h>
      13             : #include <linux/skbuff.h>
      14             : #include <linux/wait.h>
      15             : #include <linux/module.h>
      16             : #include <linux/interrupt.h>
      17             : #include <linux/if.h>
      18             : #include <linux/netdevice.h>
      19             : #include <linux/netfilter_ipv6.h>
      20             : #include <linux/inetdevice.h>
      21             : #include <linux/proc_fs.h>
      22             : #include <linux/mutex.h>
      23             : #include <linux/mm.h>
      24             : #include <linux/rcupdate.h>
      25             : #include <net/net_namespace.h>
      26             : #include <net/netfilter/nf_queue.h>
      27             : #include <net/sock.h>
      28             : 
      29             : #include "nf_internals.h"
      30             : 
      31             : const struct nf_ipv6_ops __rcu *nf_ipv6_ops __read_mostly;
      32             : EXPORT_SYMBOL_GPL(nf_ipv6_ops);
      33             : 
      34             : DEFINE_PER_CPU(bool, nf_skb_duplicated);
      35             : EXPORT_SYMBOL_GPL(nf_skb_duplicated);
      36             : 
      37             : #ifdef CONFIG_JUMP_LABEL
      38             : struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
      39             : EXPORT_SYMBOL(nf_hooks_needed);
      40             : #endif
      41             : 
      42             : static DEFINE_MUTEX(nf_hook_mutex);
      43             : 
      44             : /* max hooks per family/hooknum */
      45             : #define MAX_HOOK_COUNT          1024
      46             : 
      47             : #define nf_entry_dereference(e) \
      48             :         rcu_dereference_protected(e, lockdep_is_held(&nf_hook_mutex))
      49             : 
      50           0 : static struct nf_hook_entries *allocate_hook_entries_size(u16 num)
      51             : {
      52           0 :         struct nf_hook_entries *e;
      53           0 :         size_t alloc = sizeof(*e) +
      54           0 :                        sizeof(struct nf_hook_entry) * num +
      55             :                        sizeof(struct nf_hook_ops *) * num +
      56             :                        sizeof(struct nf_hook_entries_rcu_head);
      57             : 
      58           0 :         if (num == 0)
      59             :                 return NULL;
      60             : 
      61           0 :         e = kvzalloc(alloc, GFP_KERNEL);
      62           0 :         if (e)
      63           0 :                 e->num_hook_entries = num;
      64             :         return e;
      65             : }
      66             : 
      67           0 : static void __nf_hook_entries_free(struct rcu_head *h)
      68             : {
      69           0 :         struct nf_hook_entries_rcu_head *head;
      70             : 
      71           0 :         head = container_of(h, struct nf_hook_entries_rcu_head, head);
      72           0 :         kvfree(head->allocation);
      73           0 : }
      74             : 
      75           0 : static void nf_hook_entries_free(struct nf_hook_entries *e)
      76             : {
      77           0 :         struct nf_hook_entries_rcu_head *head;
      78           0 :         struct nf_hook_ops **ops;
      79           0 :         unsigned int num;
      80             : 
      81           0 :         if (!e)
      82             :                 return;
      83             : 
      84           0 :         num = e->num_hook_entries;
      85           0 :         ops = nf_hook_entries_get_hook_ops(e);
      86           0 :         head = (void *)&ops[num];
      87           0 :         head->allocation = e;
      88           0 :         call_rcu(&head->head, __nf_hook_entries_free);
      89             : }
      90             : 
      91           0 : static unsigned int accept_all(void *priv,
      92             :                                struct sk_buff *skb,
      93             :                                const struct nf_hook_state *state)
      94             : {
      95           0 :         return NF_ACCEPT; /* ACCEPT makes nf_hook_slow call next hook */
      96             : }
      97             : 
      98             : static const struct nf_hook_ops dummy_ops = {
      99             :         .hook = accept_all,
     100             :         .priority = INT_MIN,
     101             : };
     102             : 
     103             : static struct nf_hook_entries *
     104           0 : nf_hook_entries_grow(const struct nf_hook_entries *old,
     105             :                      const struct nf_hook_ops *reg)
     106             : {
     107           0 :         unsigned int i, alloc_entries, nhooks, old_entries;
     108           0 :         struct nf_hook_ops **orig_ops = NULL;
     109           0 :         struct nf_hook_ops **new_ops;
     110           0 :         struct nf_hook_entries *new;
     111           0 :         bool inserted = false;
     112             : 
     113           0 :         alloc_entries = 1;
     114           0 :         old_entries = old ? old->num_hook_entries : 0;
     115             : 
     116           0 :         if (old) {
     117           0 :                 orig_ops = nf_hook_entries_get_hook_ops(old);
     118             : 
     119           0 :                 for (i = 0; i < old_entries; i++) {
     120           0 :                         if (orig_ops[i] != &dummy_ops)
     121           0 :                                 alloc_entries++;
     122             :                 }
     123             :         }
     124             : 
     125           0 :         if (alloc_entries > MAX_HOOK_COUNT)
     126           0 :                 return ERR_PTR(-E2BIG);
     127             : 
     128           0 :         new = allocate_hook_entries_size(alloc_entries);
     129           0 :         if (!new)
     130           0 :                 return ERR_PTR(-ENOMEM);
     131             : 
     132           0 :         new_ops = nf_hook_entries_get_hook_ops(new);
     133             : 
     134           0 :         i = 0;
     135           0 :         nhooks = 0;
     136           0 :         while (i < old_entries) {
     137           0 :                 if (orig_ops[i] == &dummy_ops) {
     138           0 :                         ++i;
     139           0 :                         continue;
     140             :                 }
     141             : 
     142           0 :                 if (inserted || reg->priority > orig_ops[i]->priority) {
     143           0 :                         new_ops[nhooks] = (void *)orig_ops[i];
     144           0 :                         new->hooks[nhooks] = old->hooks[i];
     145           0 :                         i++;
     146             :                 } else {
     147           0 :                         new_ops[nhooks] = (void *)reg;
     148           0 :                         new->hooks[nhooks].hook = reg->hook;
     149           0 :                         new->hooks[nhooks].priv = reg->priv;
     150           0 :                         inserted = true;
     151             :                 }
     152           0 :                 nhooks++;
     153             :         }
     154             : 
     155           0 :         if (!inserted) {
     156           0 :                 new_ops[nhooks] = (void *)reg;
     157           0 :                 new->hooks[nhooks].hook = reg->hook;
     158           0 :                 new->hooks[nhooks].priv = reg->priv;
     159             :         }
     160             : 
     161             :         return new;
     162             : }
     163             : 
     164           0 : static void hooks_validate(const struct nf_hook_entries *hooks)
     165             : {
     166             : #ifdef CONFIG_DEBUG_MISC
     167             :         struct nf_hook_ops **orig_ops;
     168             :         int prio = INT_MIN;
     169             :         size_t i = 0;
     170             : 
     171             :         orig_ops = nf_hook_entries_get_hook_ops(hooks);
     172             : 
     173             :         for (i = 0; i < hooks->num_hook_entries; i++) {
     174             :                 if (orig_ops[i] == &dummy_ops)
     175             :                         continue;
     176             : 
     177             :                 WARN_ON(orig_ops[i]->priority < prio);
     178             : 
     179             :                 if (orig_ops[i]->priority > prio)
     180             :                         prio = orig_ops[i]->priority;
     181             :         }
     182             : #endif
     183           0 : }
     184             : 
     185           0 : int nf_hook_entries_insert_raw(struct nf_hook_entries __rcu **pp,
     186             :                                 const struct nf_hook_ops *reg)
     187             : {
     188           0 :         struct nf_hook_entries *new_hooks;
     189           0 :         struct nf_hook_entries *p;
     190             : 
     191           0 :         p = rcu_dereference_raw(*pp);
     192           0 :         new_hooks = nf_hook_entries_grow(p, reg);
     193           0 :         if (IS_ERR(new_hooks))
     194           0 :                 return PTR_ERR(new_hooks);
     195             : 
     196           0 :         hooks_validate(new_hooks);
     197             : 
     198           0 :         rcu_assign_pointer(*pp, new_hooks);
     199             : 
     200           0 :         BUG_ON(p == new_hooks);
     201           0 :         nf_hook_entries_free(p);
     202           0 :         return 0;
     203             : }
     204             : EXPORT_SYMBOL_GPL(nf_hook_entries_insert_raw);
     205             : 
     206             : /*
     207             :  * __nf_hook_entries_try_shrink - try to shrink hook array
     208             :  *
     209             :  * @old -- current hook blob at @pp
     210             :  * @pp -- location of hook blob
     211             :  *
     212             :  * Hook unregistration must always succeed, so to-be-removed hooks
     213             :  * are replaced by a dummy one that will just move to next hook.
     214             :  *
     215             :  * This counts the current dummy hooks, attempts to allocate new blob,
     216             :  * copies the live hooks, then replaces and discards old one.
     217             :  *
     218             :  * return values:
     219             :  *
     220             :  * Returns address to free, or NULL.
     221             :  */
     222           0 : static void *__nf_hook_entries_try_shrink(struct nf_hook_entries *old,
     223             :                                           struct nf_hook_entries __rcu **pp)
     224             : {
     225           0 :         unsigned int i, j, skip = 0, hook_entries;
     226           0 :         struct nf_hook_entries *new = NULL;
     227           0 :         struct nf_hook_ops **orig_ops;
     228           0 :         struct nf_hook_ops **new_ops;
     229             : 
     230           0 :         if (WARN_ON_ONCE(!old))
     231             :                 return NULL;
     232             : 
     233           0 :         orig_ops = nf_hook_entries_get_hook_ops(old);
     234           0 :         for (i = 0; i < old->num_hook_entries; i++) {
     235           0 :                 if (orig_ops[i] == &dummy_ops)
     236           0 :                         skip++;
     237             :         }
     238             : 
     239             :         /* if skip == hook_entries all hooks have been removed */
     240           0 :         hook_entries = old->num_hook_entries;
     241           0 :         if (skip == hook_entries)
     242           0 :                 goto out_assign;
     243             : 
     244           0 :         if (skip == 0)
     245             :                 return NULL;
     246             : 
     247           0 :         hook_entries -= skip;
     248           0 :         new = allocate_hook_entries_size(hook_entries);
     249           0 :         if (!new)
     250             :                 return NULL;
     251             : 
     252           0 :         new_ops = nf_hook_entries_get_hook_ops(new);
     253           0 :         for (i = 0, j = 0; i < old->num_hook_entries; i++) {
     254           0 :                 if (orig_ops[i] == &dummy_ops)
     255           0 :                         continue;
     256           0 :                 new->hooks[j] = old->hooks[i];
     257           0 :                 new_ops[j] = (void *)orig_ops[i];
     258           0 :                 j++;
     259             :         }
     260           0 :         hooks_validate(new);
     261           0 : out_assign:
     262           0 :         rcu_assign_pointer(*pp, new);
     263           0 :         return old;
     264             : }
     265             : 
     266             : static struct nf_hook_entries __rcu **
     267           0 : nf_hook_entry_head(struct net *net, int pf, unsigned int hooknum,
     268             :                    struct net_device *dev)
     269             : {
     270           0 :         switch (pf) {
     271             :         case NFPROTO_NETDEV:
     272           0 :                 break;
     273             : #ifdef CONFIG_NETFILTER_FAMILY_ARP
     274             :         case NFPROTO_ARP:
     275             :                 if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_arp) <= hooknum))
     276             :                         return NULL;
     277             :                 return net->nf.hooks_arp + hooknum;
     278             : #endif
     279             : #ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
     280             :         case NFPROTO_BRIDGE:
     281             :                 if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_bridge) <= hooknum))
     282             :                         return NULL;
     283             :                 return net->nf.hooks_bridge + hooknum;
     284             : #endif
     285             : #ifdef CONFIG_NETFILTER_INGRESS
     286             :         case NFPROTO_INET:
     287             :                 if (WARN_ON_ONCE(hooknum != NF_INET_INGRESS))
     288             :                         return NULL;
     289             :                 if (!dev || dev_net(dev) != net) {
     290             :                         WARN_ON_ONCE(1);
     291             :                         return NULL;
     292             :                 }
     293             :                 return &dev->nf_hooks_ingress;
     294             : #endif
     295           0 :         case NFPROTO_IPV4:
     296           0 :                 if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_ipv4) <= hooknum))
     297             :                         return NULL;
     298           0 :                 return net->nf.hooks_ipv4 + hooknum;
     299           0 :         case NFPROTO_IPV6:
     300           0 :                 if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_ipv6) <= hooknum))
     301             :                         return NULL;
     302           0 :                 return net->nf.hooks_ipv6 + hooknum;
     303             : #if IS_ENABLED(CONFIG_DECNET)
     304             :         case NFPROTO_DECNET:
     305             :                 if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_decnet) <= hooknum))
     306             :                         return NULL;
     307             :                 return net->nf.hooks_decnet + hooknum;
     308             : #endif
     309             :         default:
     310           0 :                 WARN_ON_ONCE(1);
     311           0 :                 return NULL;
     312             :         }
     313             : 
     314             : #ifdef CONFIG_NETFILTER_INGRESS
     315             :         if (hooknum == NF_NETDEV_INGRESS) {
     316             :                 if (dev && dev_net(dev) == net)
     317             :                         return &dev->nf_hooks_ingress;
     318             :         }
     319             : #endif
     320           0 :         WARN_ON_ONCE(1);
     321           0 :         return NULL;
     322             : }
     323             : 
     324           0 : static int nf_ingress_check(struct net *net, const struct nf_hook_ops *reg,
     325             :                             int hooknum)
     326             : {
     327             : #ifndef CONFIG_NETFILTER_INGRESS
     328           0 :         if (reg->hooknum == hooknum)
     329             :                 return -EOPNOTSUPP;
     330             : #endif
     331           0 :         if (reg->hooknum != hooknum ||
     332             :             !reg->dev || dev_net(reg->dev) != net)
     333           0 :                 return -EINVAL;
     334             : 
     335             :         return 0;
     336             : }
     337             : 
     338             : static inline bool nf_ingress_hook(const struct nf_hook_ops *reg, int pf)
     339             : {
     340             :         if ((pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS) ||
     341             :             (pf == NFPROTO_INET && reg->hooknum == NF_INET_INGRESS))
     342             :                 return true;
     343             : 
     344             :         return false;
     345             : }
     346             : 
     347           0 : static void nf_static_key_inc(const struct nf_hook_ops *reg, int pf)
     348             : {
     349             : #ifdef CONFIG_JUMP_LABEL
     350             :         int hooknum;
     351             : 
     352             :         if (pf == NFPROTO_INET && reg->hooknum == NF_INET_INGRESS) {
     353             :                 pf = NFPROTO_NETDEV;
     354             :                 hooknum = NF_NETDEV_INGRESS;
     355             :         } else {
     356             :                 hooknum = reg->hooknum;
     357             :         }
     358             :         static_key_slow_inc(&nf_hooks_needed[pf][hooknum]);
     359             : #endif
     360           0 : }
     361             : 
     362             : static void nf_static_key_dec(const struct nf_hook_ops *reg, int pf)
     363             : {
     364             : #ifdef CONFIG_JUMP_LABEL
     365             :         int hooknum;
     366             : 
     367             :         if (pf == NFPROTO_INET && reg->hooknum == NF_INET_INGRESS) {
     368             :                 pf = NFPROTO_NETDEV;
     369             :                 hooknum = NF_NETDEV_INGRESS;
     370             :         } else {
     371             :                 hooknum = reg->hooknum;
     372             :         }
     373             :         static_key_slow_dec(&nf_hooks_needed[pf][hooknum]);
     374             : #endif
     375             : }
     376             : 
     377           0 : static int __nf_register_net_hook(struct net *net, int pf,
     378             :                                   const struct nf_hook_ops *reg)
     379             : {
     380           0 :         struct nf_hook_entries *p, *new_hooks;
     381           0 :         struct nf_hook_entries __rcu **pp;
     382           0 :         int err;
     383             : 
     384           0 :         switch (pf) {
     385             :         case NFPROTO_NETDEV:
     386           0 :                 err = nf_ingress_check(net, reg, NF_NETDEV_INGRESS);
     387           0 :                 if (err < 0)
     388           0 :                         return err;
     389             :                 break;
     390           0 :         case NFPROTO_INET:
     391           0 :                 if (reg->hooknum != NF_INET_INGRESS)
     392             :                         break;
     393             : 
     394           0 :                 err = nf_ingress_check(net, reg, NF_INET_INGRESS);
     395             :                 if (err < 0)
     396             :                         return err;
     397             :                 break;
     398             :         }
     399             : 
     400           0 :         pp = nf_hook_entry_head(net, pf, reg->hooknum, reg->dev);
     401           0 :         if (!pp)
     402             :                 return -EINVAL;
     403             : 
     404           0 :         mutex_lock(&nf_hook_mutex);
     405             : 
     406           0 :         p = nf_entry_dereference(*pp);
     407           0 :         new_hooks = nf_hook_entries_grow(p, reg);
     408             : 
     409           0 :         if (!IS_ERR(new_hooks))
     410           0 :                 rcu_assign_pointer(*pp, new_hooks);
     411             : 
     412           0 :         mutex_unlock(&nf_hook_mutex);
     413           0 :         if (IS_ERR(new_hooks))
     414           0 :                 return PTR_ERR(new_hooks);
     415             : 
     416           0 :         hooks_validate(new_hooks);
     417             : #ifdef CONFIG_NETFILTER_INGRESS
     418             :         if (nf_ingress_hook(reg, pf))
     419             :                 net_inc_ingress_queue();
     420             : #endif
     421           0 :         nf_static_key_inc(reg, pf);
     422             : 
     423           0 :         BUG_ON(p == new_hooks);
     424           0 :         nf_hook_entries_free(p);
     425           0 :         return 0;
     426             : }
     427             : 
     428             : /*
     429             :  * nf_remove_net_hook - remove a hook from blob
     430             :  *
     431             :  * @oldp: current address of hook blob
     432             :  * @unreg: hook to unregister
     433             :  *
     434             :  * This cannot fail, hook unregistration must always succeed.
     435             :  * Therefore replace the to-be-removed hook with a dummy hook.
     436             :  */
     437           0 : static bool nf_remove_net_hook(struct nf_hook_entries *old,
     438             :                                const struct nf_hook_ops *unreg)
     439             : {
     440           0 :         struct nf_hook_ops **orig_ops;
     441           0 :         unsigned int i;
     442             : 
     443           0 :         orig_ops = nf_hook_entries_get_hook_ops(old);
     444           0 :         for (i = 0; i < old->num_hook_entries; i++) {
     445           0 :                 if (orig_ops[i] != unreg)
     446           0 :                         continue;
     447           0 :                 WRITE_ONCE(old->hooks[i].hook, accept_all);
     448           0 :                 WRITE_ONCE(orig_ops[i], (void *)&dummy_ops);
     449           0 :                 return true;
     450             :         }
     451             : 
     452             :         return false;
     453             : }
     454             : 
     455           0 : static void __nf_unregister_net_hook(struct net *net, int pf,
     456             :                                      const struct nf_hook_ops *reg)
     457             : {
     458           0 :         struct nf_hook_entries __rcu **pp;
     459           0 :         struct nf_hook_entries *p;
     460             : 
     461           0 :         pp = nf_hook_entry_head(net, pf, reg->hooknum, reg->dev);
     462           0 :         if (!pp)
     463             :                 return;
     464             : 
     465           0 :         mutex_lock(&nf_hook_mutex);
     466             : 
     467           0 :         p = nf_entry_dereference(*pp);
     468           0 :         if (WARN_ON_ONCE(!p)) {
     469           0 :                 mutex_unlock(&nf_hook_mutex);
     470           0 :                 return;
     471             :         }
     472             : 
     473           0 :         if (nf_remove_net_hook(p, reg)) {
     474             : #ifdef CONFIG_NETFILTER_INGRESS
     475             :                 if (nf_ingress_hook(reg, pf))
     476             :                         net_dec_ingress_queue();
     477             : #endif
     478           0 :                 nf_static_key_dec(reg, pf);
     479             :         } else {
     480           0 :                 WARN_ONCE(1, "hook not found, pf %d num %d", pf, reg->hooknum);
     481             :         }
     482             : 
     483           0 :         p = __nf_hook_entries_try_shrink(p, pp);
     484           0 :         mutex_unlock(&nf_hook_mutex);
     485           0 :         if (!p)
     486             :                 return;
     487             : 
     488           0 :         nf_queue_nf_hook_drop(net);
     489           0 :         nf_hook_entries_free(p);
     490             : }
     491             : 
     492           0 : void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg)
     493             : {
     494           0 :         if (reg->pf == NFPROTO_INET) {
     495           0 :                 if (reg->hooknum == NF_INET_INGRESS) {
     496           0 :                         __nf_unregister_net_hook(net, NFPROTO_INET, reg);
     497             :                 } else {
     498           0 :                         __nf_unregister_net_hook(net, NFPROTO_IPV4, reg);
     499           0 :                         __nf_unregister_net_hook(net, NFPROTO_IPV6, reg);
     500             :                 }
     501             :         } else {
     502           0 :                 __nf_unregister_net_hook(net, reg->pf, reg);
     503             :         }
     504           0 : }
     505             : EXPORT_SYMBOL(nf_unregister_net_hook);
     506             : 
     507           0 : void nf_hook_entries_delete_raw(struct nf_hook_entries __rcu **pp,
     508             :                                 const struct nf_hook_ops *reg)
     509             : {
     510           0 :         struct nf_hook_entries *p;
     511             : 
     512           0 :         p = rcu_dereference_raw(*pp);
     513           0 :         if (nf_remove_net_hook(p, reg)) {
     514           0 :                 p = __nf_hook_entries_try_shrink(p, pp);
     515           0 :                 nf_hook_entries_free(p);
     516             :         }
     517           0 : }
     518             : EXPORT_SYMBOL_GPL(nf_hook_entries_delete_raw);
     519             : 
     520           0 : int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg)
     521             : {
     522           0 :         int err;
     523             : 
     524           0 :         if (reg->pf == NFPROTO_INET) {
     525           0 :                 if (reg->hooknum == NF_INET_INGRESS) {
     526           0 :                         err = __nf_register_net_hook(net, NFPROTO_INET, reg);
     527           0 :                         if (err < 0)
     528             :                                 return err;
     529             :                 } else {
     530           0 :                         err = __nf_register_net_hook(net, NFPROTO_IPV4, reg);
     531           0 :                         if (err < 0)
     532             :                                 return err;
     533             : 
     534           0 :                         err = __nf_register_net_hook(net, NFPROTO_IPV6, reg);
     535           0 :                         if (err < 0) {
     536           0 :                                 __nf_unregister_net_hook(net, NFPROTO_IPV4, reg);
     537           0 :                                 return err;
     538             :                         }
     539             :                 }
     540             :         } else {
     541           0 :                 err = __nf_register_net_hook(net, reg->pf, reg);
     542           0 :                 if (err < 0)
     543             :                         return err;
     544             :         }
     545             : 
     546             :         return 0;
     547             : }
     548             : EXPORT_SYMBOL(nf_register_net_hook);
     549             : 
     550           0 : int nf_register_net_hooks(struct net *net, const struct nf_hook_ops *reg,
     551             :                           unsigned int n)
     552             : {
     553           0 :         unsigned int i;
     554           0 :         int err = 0;
     555             : 
     556           0 :         for (i = 0; i < n; i++) {
     557           0 :                 err = nf_register_net_hook(net, &reg[i]);
     558           0 :                 if (err)
     559           0 :                         goto err;
     560             :         }
     561             :         return err;
     562             : 
     563           0 : err:
     564           0 :         if (i > 0)
     565           0 :                 nf_unregister_net_hooks(net, reg, i);
     566             :         return err;
     567             : }
     568             : EXPORT_SYMBOL(nf_register_net_hooks);
     569             : 
     570           0 : void nf_unregister_net_hooks(struct net *net, const struct nf_hook_ops *reg,
     571             :                              unsigned int hookcount)
     572             : {
     573           0 :         unsigned int i;
     574             : 
     575           0 :         for (i = 0; i < hookcount; i++)
     576           0 :                 nf_unregister_net_hook(net, &reg[i]);
     577           0 : }
     578             : EXPORT_SYMBOL(nf_unregister_net_hooks);
     579             : 
     580             : /* Returns 1 if okfn() needs to be executed by the caller,
     581             :  * -EPERM for NF_DROP, 0 otherwise.  Caller must hold rcu_read_lock. */
     582           0 : int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state,
     583             :                  const struct nf_hook_entries *e, unsigned int s)
     584             : {
     585           0 :         unsigned int verdict;
     586           0 :         int ret;
     587             : 
     588           0 :         for (; s < e->num_hook_entries; s++) {
     589           0 :                 verdict = nf_hook_entry_hookfn(&e->hooks[s], skb, state);
     590           0 :                 switch (verdict & NF_VERDICT_MASK) {
     591             :                 case NF_ACCEPT:
     592             :                         break;
     593           0 :                 case NF_DROP:
     594           0 :                         kfree_skb(skb);
     595           0 :                         ret = NF_DROP_GETERR(verdict);
     596           0 :                         if (ret == 0)
     597           0 :                                 ret = -EPERM;
     598             :                         return ret;
     599           0 :                 case NF_QUEUE:
     600           0 :                         ret = nf_queue(skb, state, s, verdict);
     601           0 :                         if (ret == 1)
     602           0 :                                 continue;
     603             :                         return ret;
     604             :                 default:
     605             :                         /* Implicit handling for NF_STOLEN, as well as any other
     606             :                          * non conventional verdicts.
     607             :                          */
     608             :                         return 0;
     609             :                 }
     610             :         }
     611             : 
     612             :         return 1;
     613             : }
     614             : EXPORT_SYMBOL(nf_hook_slow);
     615             : 
     616           0 : void nf_hook_slow_list(struct list_head *head, struct nf_hook_state *state,
     617             :                        const struct nf_hook_entries *e)
     618             : {
     619           0 :         struct sk_buff *skb, *next;
     620           0 :         struct list_head sublist;
     621           0 :         int ret;
     622             : 
     623           0 :         INIT_LIST_HEAD(&sublist);
     624             : 
     625           0 :         list_for_each_entry_safe(skb, next, head, list) {
     626           0 :                 skb_list_del_init(skb);
     627           0 :                 ret = nf_hook_slow(skb, state, e, 0);
     628           0 :                 if (ret == 1)
     629           0 :                         list_add_tail(&skb->list, &sublist);
     630             :         }
     631             :         /* Put passed packets back on main list */
     632           0 :         list_splice(&sublist, head);
     633           0 : }
     634             : EXPORT_SYMBOL(nf_hook_slow_list);
     635             : 
     636             : /* This needs to be compiled in any case to avoid dependencies between the
     637             :  * nfnetlink_queue code and nf_conntrack.
     638             :  */
     639             : struct nfnl_ct_hook __rcu *nfnl_ct_hook __read_mostly;
     640             : EXPORT_SYMBOL_GPL(nfnl_ct_hook);
     641             : 
     642             : struct nf_ct_hook __rcu *nf_ct_hook __read_mostly;
     643             : EXPORT_SYMBOL_GPL(nf_ct_hook);
     644             : 
     645             : #if IS_ENABLED(CONFIG_NF_CONNTRACK)
     646             : /* This does not belong here, but locally generated errors need it if connection
     647             :    tracking in use: without this, connection may not be in hash table, and hence
     648             :    manufactured ICMP or RST packets will not be associated with it. */
     649             : void (*ip_ct_attach)(struct sk_buff *, const struct sk_buff *)
     650             :                 __rcu __read_mostly;
     651             : EXPORT_SYMBOL(ip_ct_attach);
     652             : 
     653             : struct nf_nat_hook __rcu *nf_nat_hook __read_mostly;
     654             : EXPORT_SYMBOL_GPL(nf_nat_hook);
     655             : 
     656             : void nf_ct_attach(struct sk_buff *new, const struct sk_buff *skb)
     657             : {
     658             :         void (*attach)(struct sk_buff *, const struct sk_buff *);
     659             : 
     660             :         if (skb->_nfct) {
     661             :                 rcu_read_lock();
     662             :                 attach = rcu_dereference(ip_ct_attach);
     663             :                 if (attach)
     664             :                         attach(new, skb);
     665             :                 rcu_read_unlock();
     666             :         }
     667             : }
     668             : EXPORT_SYMBOL(nf_ct_attach);
     669             : 
     670             : void nf_conntrack_destroy(struct nf_conntrack *nfct)
     671             : {
     672             :         struct nf_ct_hook *ct_hook;
     673             : 
     674             :         rcu_read_lock();
     675             :         ct_hook = rcu_dereference(nf_ct_hook);
     676             :         BUG_ON(ct_hook == NULL);
     677             :         ct_hook->destroy(nfct);
     678             :         rcu_read_unlock();
     679             : }
     680             : EXPORT_SYMBOL(nf_conntrack_destroy);
     681             : 
     682             : bool nf_ct_get_tuple_skb(struct nf_conntrack_tuple *dst_tuple,
     683             :                          const struct sk_buff *skb)
     684             : {
     685             :         struct nf_ct_hook *ct_hook;
     686             :         bool ret = false;
     687             : 
     688             :         rcu_read_lock();
     689             :         ct_hook = rcu_dereference(nf_ct_hook);
     690             :         if (ct_hook)
     691             :                 ret = ct_hook->get_tuple_skb(dst_tuple, skb);
     692             :         rcu_read_unlock();
     693             :         return ret;
     694             : }
     695             : EXPORT_SYMBOL(nf_ct_get_tuple_skb);
     696             : 
     697             : /* Built-in default zone used e.g. by modules. */
     698             : const struct nf_conntrack_zone nf_ct_zone_dflt = {
     699             :         .id     = NF_CT_DEFAULT_ZONE_ID,
     700             :         .dir    = NF_CT_DEFAULT_ZONE_DIR,
     701             : };
     702             : EXPORT_SYMBOL_GPL(nf_ct_zone_dflt);
     703             : #endif /* CONFIG_NF_CONNTRACK */
     704             : 
     705             : static void __net_init
     706           2 : __netfilter_net_init(struct nf_hook_entries __rcu **e, int max)
     707             : {
     708           2 :         int h;
     709             : 
     710          12 :         for (h = 0; h < max; h++)
     711          10 :                 RCU_INIT_POINTER(e[h], NULL);
     712           2 : }
     713             : 
     714           1 : static int __net_init netfilter_net_init(struct net *net)
     715             : {
     716           1 :         __netfilter_net_init(net->nf.hooks_ipv4, ARRAY_SIZE(net->nf.hooks_ipv4));
     717           1 :         __netfilter_net_init(net->nf.hooks_ipv6, ARRAY_SIZE(net->nf.hooks_ipv6));
     718             : #ifdef CONFIG_NETFILTER_FAMILY_ARP
     719             :         __netfilter_net_init(net->nf.hooks_arp, ARRAY_SIZE(net->nf.hooks_arp));
     720             : #endif
     721             : #ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
     722             :         __netfilter_net_init(net->nf.hooks_bridge, ARRAY_SIZE(net->nf.hooks_bridge));
     723             : #endif
     724             : #if IS_ENABLED(CONFIG_DECNET)
     725             :         __netfilter_net_init(net->nf.hooks_decnet, ARRAY_SIZE(net->nf.hooks_decnet));
     726             : #endif
     727             : 
     728             : #ifdef CONFIG_PROC_FS
     729           1 :         net->nf.proc_netfilter = proc_net_mkdir(net, "netfilter",
     730             :                                                 net->proc_net);
     731           1 :         if (!net->nf.proc_netfilter) {
     732           0 :                 if (!net_eq(net, &init_net))
     733             :                         pr_err("cannot create netfilter proc entry");
     734             : 
     735           0 :                 return -ENOMEM;
     736             :         }
     737             : #endif
     738             : 
     739             :         return 0;
     740             : }
     741             : 
     742           0 : static void __net_exit netfilter_net_exit(struct net *net)
     743             : {
     744           0 :         remove_proc_entry("netfilter", net->proc_net);
     745           0 : }
     746             : 
     747             : static struct pernet_operations netfilter_net_ops = {
     748             :         .init = netfilter_net_init,
     749             :         .exit = netfilter_net_exit,
     750             : };
     751             : 
     752           1 : int __init netfilter_init(void)
     753             : {
     754           1 :         int ret;
     755             : 
     756           1 :         ret = register_pernet_subsys(&netfilter_net_ops);
     757           1 :         if (ret < 0)
     758           0 :                 goto err;
     759             : 
     760           1 :         ret = netfilter_log_init();
     761           1 :         if (ret < 0)
     762           0 :                 goto err_pernet;
     763             : 
     764             :         return 0;
     765           0 : err_pernet:
     766           0 :         unregister_pernet_subsys(&netfilter_net_ops);
     767             : err:
     768             :         return ret;
     769             : }

Generated by: LCOV version 1.14