LCOV - code coverage report
Current view: top level - net/netfilter - nf_sockopt.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 0 59 0.0 %
Date: 2021-04-22 12:43:58 Functions: 0 5 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : #include <linux/kernel.h>
       3             : #include <linux/init.h>
       4             : #include <linux/module.h>
       5             : #include <linux/skbuff.h>
       6             : #include <linux/netfilter.h>
       7             : #include <linux/mutex.h>
       8             : #include <net/sock.h>
       9             : 
      10             : #include "nf_internals.h"
      11             : 
      12             : /* Sockopts only registered and called from user context, so
      13             :    net locking would be overkill.  Also, [gs]etsockopt calls may
      14             :    sleep. */
      15             : static DEFINE_MUTEX(nf_sockopt_mutex);
      16             : static LIST_HEAD(nf_sockopts);
      17             : 
      18             : /* Do exclusive ranges overlap? */
      19           0 : static inline int overlap(int min1, int max1, int min2, int max2)
      20             : {
      21           0 :         return max1 > min2 && min1 < max2;
      22             : }
      23             : 
      24             : /* Functions to register sockopt ranges (exclusive). */
      25           0 : int nf_register_sockopt(struct nf_sockopt_ops *reg)
      26             : {
      27           0 :         struct nf_sockopt_ops *ops;
      28           0 :         int ret = 0;
      29             : 
      30           0 :         mutex_lock(&nf_sockopt_mutex);
      31           0 :         list_for_each_entry(ops, &nf_sockopts, list) {
      32           0 :                 if (ops->pf == reg->pf
      33           0 :                     && (overlap(ops->set_optmin, ops->set_optmax,
      34             :                                 reg->set_optmin, reg->set_optmax)
      35           0 :                         || overlap(ops->get_optmin, ops->get_optmax,
      36             :                                    reg->get_optmin, reg->get_optmax))) {
      37           0 :                         pr_debug("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n",
      38             :                                 ops->set_optmin, ops->set_optmax,
      39             :                                 ops->get_optmin, ops->get_optmax,
      40             :                                 reg->set_optmin, reg->set_optmax,
      41             :                                 reg->get_optmin, reg->get_optmax);
      42           0 :                         ret = -EBUSY;
      43           0 :                         goto out;
      44             :                 }
      45             :         }
      46             : 
      47           0 :         list_add(&reg->list, &nf_sockopts);
      48           0 : out:
      49           0 :         mutex_unlock(&nf_sockopt_mutex);
      50           0 :         return ret;
      51             : }
      52             : EXPORT_SYMBOL(nf_register_sockopt);
      53             : 
      54           0 : void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
      55             : {
      56           0 :         mutex_lock(&nf_sockopt_mutex);
      57           0 :         list_del(&reg->list);
      58           0 :         mutex_unlock(&nf_sockopt_mutex);
      59           0 : }
      60             : EXPORT_SYMBOL(nf_unregister_sockopt);
      61             : 
      62           0 : static struct nf_sockopt_ops *nf_sockopt_find(struct sock *sk, u_int8_t pf,
      63             :                 int val, int get)
      64             : {
      65           0 :         struct nf_sockopt_ops *ops;
      66             : 
      67           0 :         mutex_lock(&nf_sockopt_mutex);
      68           0 :         list_for_each_entry(ops, &nf_sockopts, list) {
      69           0 :                 if (ops->pf == pf) {
      70           0 :                         if (!try_module_get(ops->owner))
      71             :                                 goto out_nosup;
      72             : 
      73           0 :                         if (get) {
      74           0 :                                 if (val >= ops->get_optmin &&
      75           0 :                                                 val < ops->get_optmax)
      76           0 :                                         goto out;
      77             :                         } else {
      78           0 :                                 if (val >= ops->set_optmin &&
      79           0 :                                                 val < ops->set_optmax)
      80           0 :                                         goto out;
      81             :                         }
      82           0 :                         module_put(ops->owner);
      83             :                 }
      84             :         }
      85           0 : out_nosup:
      86           0 :         ops = ERR_PTR(-ENOPROTOOPT);
      87           0 : out:
      88           0 :         mutex_unlock(&nf_sockopt_mutex);
      89           0 :         return ops;
      90             : }
      91             : 
      92           0 : int nf_setsockopt(struct sock *sk, u_int8_t pf, int val, sockptr_t opt,
      93             :                   unsigned int len)
      94             : {
      95           0 :         struct nf_sockopt_ops *ops;
      96           0 :         int ret;
      97             : 
      98           0 :         ops = nf_sockopt_find(sk, pf, val, 0);
      99           0 :         if (IS_ERR(ops))
     100           0 :                 return PTR_ERR(ops);
     101           0 :         ret = ops->set(sk, val, opt, len);
     102           0 :         module_put(ops->owner);
     103           0 :         return ret;
     104             : }
     105             : EXPORT_SYMBOL(nf_setsockopt);
     106             : 
     107           0 : int nf_getsockopt(struct sock *sk, u_int8_t pf, int val, char __user *opt,
     108             :                   int *len)
     109             : {
     110           0 :         struct nf_sockopt_ops *ops;
     111           0 :         int ret;
     112             : 
     113           0 :         ops = nf_sockopt_find(sk, pf, val, 1);
     114           0 :         if (IS_ERR(ops))
     115           0 :                 return PTR_ERR(ops);
     116           0 :         ret = ops->get(sk, val, opt, len);
     117           0 :         module_put(ops->owner);
     118           0 :         return ret;
     119             : }
     120             : EXPORT_SYMBOL(nf_getsockopt);

Generated by: LCOV version 1.14