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

xt_policy.c (4772B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* IP tables module for matching IPsec policy
      3 *
      4 * Copyright (c) 2004,2005 Patrick McHardy, <kaber@trash.net>
      5 */
      6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      7#include <linux/kernel.h>
      8#include <linux/module.h>
      9#include <linux/skbuff.h>
     10#include <linux/init.h>
     11#include <net/xfrm.h>
     12
     13#include <linux/netfilter.h>
     14#include <linux/netfilter/xt_policy.h>
     15#include <linux/netfilter/x_tables.h>
     16
     17MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
     18MODULE_DESCRIPTION("Xtables: IPsec policy match");
     19MODULE_LICENSE("GPL");
     20
     21static inline bool
     22xt_addr_cmp(const union nf_inet_addr *a1, const union nf_inet_addr *m,
     23	    const union nf_inet_addr *a2, unsigned short family)
     24{
     25	switch (family) {
     26	case NFPROTO_IPV4:
     27		return ((a1->ip ^ a2->ip) & m->ip) == 0;
     28	case NFPROTO_IPV6:
     29		return ipv6_masked_addr_cmp(&a1->in6, &m->in6, &a2->in6) == 0;
     30	}
     31	return false;
     32}
     33
     34static bool
     35match_xfrm_state(const struct xfrm_state *x, const struct xt_policy_elem *e,
     36		 unsigned short family)
     37{
     38#define MATCH_ADDR(x,y,z)	(!e->match.x ||			       \
     39				 (xt_addr_cmp(&e->x, &e->y, (const union nf_inet_addr *)(z), family) \
     40				  ^ e->invert.x))
     41#define MATCH(x,y)		(!e->match.x || ((e->x == (y)) ^ e->invert.x))
     42
     43	return MATCH_ADDR(saddr, smask, &x->props.saddr) &&
     44	       MATCH_ADDR(daddr, dmask, &x->id.daddr) &&
     45	       MATCH(proto, x->id.proto) &&
     46	       MATCH(mode, x->props.mode) &&
     47	       MATCH(spi, x->id.spi) &&
     48	       MATCH(reqid, x->props.reqid);
     49}
     50
     51static int
     52match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info,
     53		unsigned short family)
     54{
     55	const struct xt_policy_elem *e;
     56	const struct sec_path *sp = skb_sec_path(skb);
     57	int strict = info->flags & XT_POLICY_MATCH_STRICT;
     58	int i, pos;
     59
     60	if (sp == NULL)
     61		return -1;
     62	if (strict && info->len != sp->len)
     63		return 0;
     64
     65	for (i = sp->len - 1; i >= 0; i--) {
     66		pos = strict ? i - sp->len + 1 : 0;
     67		if (pos >= info->len)
     68			return 0;
     69		e = &info->pol[pos];
     70
     71		if (match_xfrm_state(sp->xvec[i], e, family)) {
     72			if (!strict)
     73				return 1;
     74		} else if (strict)
     75			return 0;
     76	}
     77
     78	return strict ? 1 : 0;
     79}
     80
     81static int
     82match_policy_out(const struct sk_buff *skb, const struct xt_policy_info *info,
     83		 unsigned short family)
     84{
     85	const struct xt_policy_elem *e;
     86	const struct dst_entry *dst = skb_dst(skb);
     87	int strict = info->flags & XT_POLICY_MATCH_STRICT;
     88	int i, pos;
     89
     90	if (dst->xfrm == NULL)
     91		return -1;
     92
     93	for (i = 0; dst && dst->xfrm;
     94	     dst = ((struct xfrm_dst *)dst)->child, i++) {
     95		pos = strict ? i : 0;
     96		if (pos >= info->len)
     97			return 0;
     98		e = &info->pol[pos];
     99
    100		if (match_xfrm_state(dst->xfrm, e, family)) {
    101			if (!strict)
    102				return 1;
    103		} else if (strict)
    104			return 0;
    105	}
    106
    107	return strict ? i == info->len : 0;
    108}
    109
    110static bool
    111policy_mt(const struct sk_buff *skb, struct xt_action_param *par)
    112{
    113	const struct xt_policy_info *info = par->matchinfo;
    114	int ret;
    115
    116	if (info->flags & XT_POLICY_MATCH_IN)
    117		ret = match_policy_in(skb, info, xt_family(par));
    118	else
    119		ret = match_policy_out(skb, info, xt_family(par));
    120
    121	if (ret < 0)
    122		ret = info->flags & XT_POLICY_MATCH_NONE ? true : false;
    123	else if (info->flags & XT_POLICY_MATCH_NONE)
    124		ret = false;
    125
    126	return ret;
    127}
    128
    129static int policy_mt_check(const struct xt_mtchk_param *par)
    130{
    131	const struct xt_policy_info *info = par->matchinfo;
    132	const char *errmsg = "neither incoming nor outgoing policy selected";
    133
    134	if (!(info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT)))
    135		goto err;
    136
    137	if (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) |
    138	    (1 << NF_INET_LOCAL_IN)) && info->flags & XT_POLICY_MATCH_OUT) {
    139		errmsg = "output policy not valid in PREROUTING and INPUT";
    140		goto err;
    141	}
    142	if (par->hook_mask & ((1 << NF_INET_POST_ROUTING) |
    143	    (1 << NF_INET_LOCAL_OUT)) && info->flags & XT_POLICY_MATCH_IN) {
    144		errmsg = "input policy not valid in POSTROUTING and OUTPUT";
    145		goto err;
    146	}
    147	if (info->len > XT_POLICY_MAX_ELEM) {
    148		errmsg = "too many policy elements";
    149		goto err;
    150	}
    151	return 0;
    152err:
    153	pr_info_ratelimited("%s\n", errmsg);
    154	return -EINVAL;
    155}
    156
    157static struct xt_match policy_mt_reg[] __read_mostly = {
    158	{
    159		.name		= "policy",
    160		.family		= NFPROTO_IPV4,
    161		.checkentry 	= policy_mt_check,
    162		.match		= policy_mt,
    163		.matchsize	= sizeof(struct xt_policy_info),
    164		.me		= THIS_MODULE,
    165	},
    166	{
    167		.name		= "policy",
    168		.family		= NFPROTO_IPV6,
    169		.checkentry	= policy_mt_check,
    170		.match		= policy_mt,
    171		.matchsize	= sizeof(struct xt_policy_info),
    172		.me		= THIS_MODULE,
    173	},
    174};
    175
    176static int __init policy_mt_init(void)
    177{
    178	return xt_register_matches(policy_mt_reg, ARRAY_SIZE(policy_mt_reg));
    179}
    180
    181static void __exit policy_mt_exit(void)
    182{
    183	xt_unregister_matches(policy_mt_reg, ARRAY_SIZE(policy_mt_reg));
    184}
    185
    186module_init(policy_mt_init);
    187module_exit(policy_mt_exit);
    188MODULE_ALIAS("ipt_policy");
    189MODULE_ALIAS("ip6t_policy");