cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

nf_sockopt.c (2849B)


      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. */
     15static DEFINE_MUTEX(nf_sockopt_mutex);
     16static LIST_HEAD(nf_sockopts);
     17
     18/* Do exclusive ranges overlap? */
     19static inline int overlap(int min1, int max1, int min2, int max2)
     20{
     21	return max1 > min2 && min1 < max2;
     22}
     23
     24/* Functions to register sockopt ranges (exclusive). */
     25int nf_register_sockopt(struct nf_sockopt_ops *reg)
     26{
     27	struct nf_sockopt_ops *ops;
     28	int ret = 0;
     29
     30	mutex_lock(&nf_sockopt_mutex);
     31	list_for_each_entry(ops, &nf_sockopts, list) {
     32		if (ops->pf == reg->pf
     33		    && (overlap(ops->set_optmin, ops->set_optmax,
     34				reg->set_optmin, reg->set_optmax)
     35			|| overlap(ops->get_optmin, ops->get_optmax,
     36				   reg->get_optmin, reg->get_optmax))) {
     37			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			ret = -EBUSY;
     43			goto out;
     44		}
     45	}
     46
     47	list_add(&reg->list, &nf_sockopts);
     48out:
     49	mutex_unlock(&nf_sockopt_mutex);
     50	return ret;
     51}
     52EXPORT_SYMBOL(nf_register_sockopt);
     53
     54void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
     55{
     56	mutex_lock(&nf_sockopt_mutex);
     57	list_del(&reg->list);
     58	mutex_unlock(&nf_sockopt_mutex);
     59}
     60EXPORT_SYMBOL(nf_unregister_sockopt);
     61
     62static struct nf_sockopt_ops *nf_sockopt_find(struct sock *sk, u_int8_t pf,
     63		int val, int get)
     64{
     65	struct nf_sockopt_ops *ops;
     66
     67	mutex_lock(&nf_sockopt_mutex);
     68	list_for_each_entry(ops, &nf_sockopts, list) {
     69		if (ops->pf == pf) {
     70			if (!try_module_get(ops->owner))
     71				goto out_nosup;
     72
     73			if (get) {
     74				if (val >= ops->get_optmin &&
     75						val < ops->get_optmax)
     76					goto out;
     77			} else {
     78				if (val >= ops->set_optmin &&
     79						val < ops->set_optmax)
     80					goto out;
     81			}
     82			module_put(ops->owner);
     83		}
     84	}
     85out_nosup:
     86	ops = ERR_PTR(-ENOPROTOOPT);
     87out:
     88	mutex_unlock(&nf_sockopt_mutex);
     89	return ops;
     90}
     91
     92int nf_setsockopt(struct sock *sk, u_int8_t pf, int val, sockptr_t opt,
     93		  unsigned int len)
     94{
     95	struct nf_sockopt_ops *ops;
     96	int ret;
     97
     98	ops = nf_sockopt_find(sk, pf, val, 0);
     99	if (IS_ERR(ops))
    100		return PTR_ERR(ops);
    101	ret = ops->set(sk, val, opt, len);
    102	module_put(ops->owner);
    103	return ret;
    104}
    105EXPORT_SYMBOL(nf_setsockopt);
    106
    107int nf_getsockopt(struct sock *sk, u_int8_t pf, int val, char __user *opt,
    108		  int *len)
    109{
    110	struct nf_sockopt_ops *ops;
    111	int ret;
    112
    113	ops = nf_sockopt_find(sk, pf, val, 1);
    114	if (IS_ERR(ops))
    115		return PTR_ERR(ops);
    116	ret = ops->get(sk, val, opt, len);
    117	module_put(ops->owner);
    118	return ret;
    119}
    120EXPORT_SYMBOL(nf_getsockopt);