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

ip6t_hbh.c (4931B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* Kernel module to match Hop-by-Hop and Destination parameters. */
      3
      4/* (C) 2001-2002 Andras Kis-Szabo <kisza@sch.bme.hu>
      5 */
      6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      7#include <linux/module.h>
      8#include <linux/skbuff.h>
      9#include <linux/ipv6.h>
     10#include <linux/types.h>
     11#include <net/checksum.h>
     12#include <net/ipv6.h>
     13
     14#include <asm/byteorder.h>
     15
     16#include <linux/netfilter/x_tables.h>
     17#include <linux/netfilter_ipv6/ip6_tables.h>
     18#include <linux/netfilter_ipv6/ip6t_opts.h>
     19
     20MODULE_LICENSE("GPL");
     21MODULE_DESCRIPTION("Xtables: IPv6 Hop-By-Hop and Destination Header match");
     22MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
     23MODULE_ALIAS("ip6t_dst");
     24
     25/*
     26 *  (Type & 0xC0) >> 6
     27 *	0	-> ignorable
     28 *	1	-> must drop the packet
     29 *	2	-> send ICMP PARM PROB regardless and drop packet
     30 *	3	-> Send ICMP if not a multicast address and drop packet
     31 *  (Type & 0x20) >> 5
     32 *	0	-> invariant
     33 *	1	-> can change the routing
     34 *  (Type & 0x1F) Type
     35 *	0	-> Pad1 (only 1 byte!)
     36 *	1	-> PadN LENGTH info (total length = length + 2)
     37 *	C0 | 2	-> JUMBO 4 x x x x ( xxxx > 64k )
     38 *	5	-> RTALERT 2 x x
     39 */
     40
     41static struct xt_match hbh_mt6_reg[] __read_mostly;
     42
     43static bool
     44hbh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
     45{
     46	struct ipv6_opt_hdr _optsh;
     47	const struct ipv6_opt_hdr *oh;
     48	const struct ip6t_opts *optinfo = par->matchinfo;
     49	unsigned int temp;
     50	unsigned int ptr = 0;
     51	unsigned int hdrlen = 0;
     52	bool ret = false;
     53	u8 _opttype;
     54	u8 _optlen;
     55	const u_int8_t *tp = NULL;
     56	const u_int8_t *lp = NULL;
     57	unsigned int optlen;
     58	int err;
     59
     60	err = ipv6_find_hdr(skb, &ptr,
     61			    (par->match == &hbh_mt6_reg[0]) ?
     62			    NEXTHDR_HOP : NEXTHDR_DEST, NULL, NULL);
     63	if (err < 0) {
     64		if (err != -ENOENT)
     65			par->hotdrop = true;
     66		return false;
     67	}
     68
     69	oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh);
     70	if (oh == NULL) {
     71		par->hotdrop = true;
     72		return false;
     73	}
     74
     75	hdrlen = ipv6_optlen(oh);
     76	if (skb->len - ptr < hdrlen) {
     77		/* Packet smaller than it's length field */
     78		return false;
     79	}
     80
     81	pr_debug("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen);
     82
     83	pr_debug("len %02X %04X %02X ",
     84		 optinfo->hdrlen, hdrlen,
     85		 (!(optinfo->flags & IP6T_OPTS_LEN) ||
     86		  ((optinfo->hdrlen == hdrlen) ^
     87		   !!(optinfo->invflags & IP6T_OPTS_INV_LEN))));
     88
     89	ret = (!(optinfo->flags & IP6T_OPTS_LEN) ||
     90	       ((optinfo->hdrlen == hdrlen) ^
     91		!!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
     92
     93	ptr += 2;
     94	hdrlen -= 2;
     95	if (!(optinfo->flags & IP6T_OPTS_OPTS)) {
     96		return ret;
     97	} else {
     98		pr_debug("Strict ");
     99		pr_debug("#%d ", optinfo->optsnr);
    100		for (temp = 0; temp < optinfo->optsnr; temp++) {
    101			/* type field exists ? */
    102			if (hdrlen < 1)
    103				break;
    104			tp = skb_header_pointer(skb, ptr, sizeof(_opttype),
    105						&_opttype);
    106			if (tp == NULL)
    107				break;
    108
    109			/* Type check */
    110			if (*tp != (optinfo->opts[temp] & 0xFF00) >> 8) {
    111				pr_debug("Tbad %02X %02X\n", *tp,
    112					 (optinfo->opts[temp] & 0xFF00) >> 8);
    113				return false;
    114			} else {
    115				pr_debug("Tok ");
    116			}
    117			/* Length check */
    118			if (*tp) {
    119				u16 spec_len;
    120
    121				/* length field exists ? */
    122				if (hdrlen < 2)
    123					break;
    124				lp = skb_header_pointer(skb, ptr + 1,
    125							sizeof(_optlen),
    126							&_optlen);
    127				if (lp == NULL)
    128					break;
    129				spec_len = optinfo->opts[temp] & 0x00FF;
    130
    131				if (spec_len != 0x00FF && spec_len != *lp) {
    132					pr_debug("Lbad %02X %04X\n", *lp,
    133						 spec_len);
    134					return false;
    135				}
    136				pr_debug("Lok ");
    137				optlen = *lp + 2;
    138			} else {
    139				pr_debug("Pad1\n");
    140				optlen = 1;
    141			}
    142
    143			/* Step to the next */
    144			pr_debug("len%04X\n", optlen);
    145
    146			if ((ptr > skb->len - optlen || hdrlen < optlen) &&
    147			    temp < optinfo->optsnr - 1) {
    148				pr_debug("new pointer is too large!\n");
    149				break;
    150			}
    151			ptr += optlen;
    152			hdrlen -= optlen;
    153		}
    154		if (temp == optinfo->optsnr)
    155			return ret;
    156		else
    157			return false;
    158	}
    159
    160	return false;
    161}
    162
    163static int hbh_mt6_check(const struct xt_mtchk_param *par)
    164{
    165	const struct ip6t_opts *optsinfo = par->matchinfo;
    166
    167	if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) {
    168		pr_debug("unknown flags %X\n", optsinfo->invflags);
    169		return -EINVAL;
    170	}
    171
    172	if (optsinfo->flags & IP6T_OPTS_NSTRICT) {
    173		pr_debug("Not strict - not implemented");
    174		return -EINVAL;
    175	}
    176
    177	return 0;
    178}
    179
    180static struct xt_match hbh_mt6_reg[] __read_mostly = {
    181	{
    182		/* Note, hbh_mt6 relies on the order of hbh_mt6_reg */
    183		.name		= "hbh",
    184		.family		= NFPROTO_IPV6,
    185		.match		= hbh_mt6,
    186		.matchsize	= sizeof(struct ip6t_opts),
    187		.checkentry	= hbh_mt6_check,
    188		.me		= THIS_MODULE,
    189	},
    190	{
    191		.name		= "dst",
    192		.family		= NFPROTO_IPV6,
    193		.match		= hbh_mt6,
    194		.matchsize	= sizeof(struct ip6t_opts),
    195		.checkentry	= hbh_mt6_check,
    196		.me		= THIS_MODULE,
    197	},
    198};
    199
    200static int __init hbh_mt6_init(void)
    201{
    202	return xt_register_matches(hbh_mt6_reg, ARRAY_SIZE(hbh_mt6_reg));
    203}
    204
    205static void __exit hbh_mt6_exit(void)
    206{
    207	xt_unregister_matches(hbh_mt6_reg, ARRAY_SIZE(hbh_mt6_reg));
    208}
    209
    210module_init(hbh_mt6_init);
    211module_exit(hbh_mt6_exit);