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_srh.c (9072B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/* Kernel module to match Segment Routing Header (SRH) parameters. */
      3
      4/* Author:
      5 * Ahmed Abdelsalam <amsalam20@gmail.com>
      6 */
      7
      8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      9#include <linux/module.h>
     10#include <linux/skbuff.h>
     11#include <linux/ipv6.h>
     12#include <linux/types.h>
     13#include <net/ipv6.h>
     14#include <net/seg6.h>
     15
     16#include <linux/netfilter/x_tables.h>
     17#include <linux/netfilter_ipv6/ip6t_srh.h>
     18#include <linux/netfilter_ipv6/ip6_tables.h>
     19
     20/* Test a struct->mt_invflags and a boolean for inequality */
     21#define NF_SRH_INVF(ptr, flag, boolean)	\
     22	((boolean) ^ !!((ptr)->mt_invflags & (flag)))
     23
     24static bool srh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
     25{
     26	const struct ip6t_srh *srhinfo = par->matchinfo;
     27	struct ipv6_sr_hdr *srh;
     28	struct ipv6_sr_hdr _srh;
     29	int hdrlen, srhoff = 0;
     30
     31	if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL) < 0)
     32		return false;
     33	srh = skb_header_pointer(skb, srhoff, sizeof(_srh), &_srh);
     34	if (!srh)
     35		return false;
     36
     37	hdrlen = ipv6_optlen(srh);
     38	if (skb->len - srhoff < hdrlen)
     39		return false;
     40
     41	if (srh->type != IPV6_SRCRT_TYPE_4)
     42		return false;
     43
     44	if (srh->segments_left > srh->first_segment)
     45		return false;
     46
     47	/* Next Header matching */
     48	if (srhinfo->mt_flags & IP6T_SRH_NEXTHDR)
     49		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_NEXTHDR,
     50				!(srh->nexthdr == srhinfo->next_hdr)))
     51			return false;
     52
     53	/* Header Extension Length matching */
     54	if (srhinfo->mt_flags & IP6T_SRH_LEN_EQ)
     55		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_EQ,
     56				!(srh->hdrlen == srhinfo->hdr_len)))
     57			return false;
     58
     59	if (srhinfo->mt_flags & IP6T_SRH_LEN_GT)
     60		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_GT,
     61				!(srh->hdrlen > srhinfo->hdr_len)))
     62			return false;
     63
     64	if (srhinfo->mt_flags & IP6T_SRH_LEN_LT)
     65		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_LT,
     66				!(srh->hdrlen < srhinfo->hdr_len)))
     67			return false;
     68
     69	/* Segments Left matching */
     70	if (srhinfo->mt_flags & IP6T_SRH_SEGS_EQ)
     71		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_EQ,
     72				!(srh->segments_left == srhinfo->segs_left)))
     73			return false;
     74
     75	if (srhinfo->mt_flags & IP6T_SRH_SEGS_GT)
     76		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_GT,
     77				!(srh->segments_left > srhinfo->segs_left)))
     78			return false;
     79
     80	if (srhinfo->mt_flags & IP6T_SRH_SEGS_LT)
     81		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_LT,
     82				!(srh->segments_left < srhinfo->segs_left)))
     83			return false;
     84
     85	/**
     86	 * Last Entry matching
     87	 * Last_Entry field was introduced in revision 6 of the SRH draft.
     88	 * It was called First_Segment in the previous revision
     89	 */
     90	if (srhinfo->mt_flags & IP6T_SRH_LAST_EQ)
     91		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_EQ,
     92				!(srh->first_segment == srhinfo->last_entry)))
     93			return false;
     94
     95	if (srhinfo->mt_flags & IP6T_SRH_LAST_GT)
     96		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_GT,
     97				!(srh->first_segment > srhinfo->last_entry)))
     98			return false;
     99
    100	if (srhinfo->mt_flags & IP6T_SRH_LAST_LT)
    101		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_LT,
    102				!(srh->first_segment < srhinfo->last_entry)))
    103			return false;
    104
    105	/**
    106	 * Tag matchig
    107	 * Tag field was introduced in revision 6 of the SRH draft.
    108	 */
    109	if (srhinfo->mt_flags & IP6T_SRH_TAG)
    110		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_TAG,
    111				!(srh->tag == srhinfo->tag)))
    112			return false;
    113	return true;
    114}
    115
    116static bool srh1_mt6(const struct sk_buff *skb, struct xt_action_param *par)
    117{
    118	int hdrlen, psidoff, nsidoff, lsidoff, srhoff = 0;
    119	const struct ip6t_srh1 *srhinfo = par->matchinfo;
    120	struct in6_addr *psid, *nsid, *lsid;
    121	struct in6_addr _psid, _nsid, _lsid;
    122	struct ipv6_sr_hdr *srh;
    123	struct ipv6_sr_hdr _srh;
    124
    125	if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL) < 0)
    126		return false;
    127	srh = skb_header_pointer(skb, srhoff, sizeof(_srh), &_srh);
    128	if (!srh)
    129		return false;
    130
    131	hdrlen = ipv6_optlen(srh);
    132	if (skb->len - srhoff < hdrlen)
    133		return false;
    134
    135	if (srh->type != IPV6_SRCRT_TYPE_4)
    136		return false;
    137
    138	if (srh->segments_left > srh->first_segment)
    139		return false;
    140
    141	/* Next Header matching */
    142	if (srhinfo->mt_flags & IP6T_SRH_NEXTHDR)
    143		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_NEXTHDR,
    144				!(srh->nexthdr == srhinfo->next_hdr)))
    145			return false;
    146
    147	/* Header Extension Length matching */
    148	if (srhinfo->mt_flags & IP6T_SRH_LEN_EQ)
    149		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_EQ,
    150				!(srh->hdrlen == srhinfo->hdr_len)))
    151			return false;
    152	if (srhinfo->mt_flags & IP6T_SRH_LEN_GT)
    153		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_GT,
    154				!(srh->hdrlen > srhinfo->hdr_len)))
    155			return false;
    156	if (srhinfo->mt_flags & IP6T_SRH_LEN_LT)
    157		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_LT,
    158				!(srh->hdrlen < srhinfo->hdr_len)))
    159			return false;
    160
    161	/* Segments Left matching */
    162	if (srhinfo->mt_flags & IP6T_SRH_SEGS_EQ)
    163		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_EQ,
    164				!(srh->segments_left == srhinfo->segs_left)))
    165			return false;
    166	if (srhinfo->mt_flags & IP6T_SRH_SEGS_GT)
    167		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_GT,
    168				!(srh->segments_left > srhinfo->segs_left)))
    169			return false;
    170	if (srhinfo->mt_flags & IP6T_SRH_SEGS_LT)
    171		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_LT,
    172				!(srh->segments_left < srhinfo->segs_left)))
    173			return false;
    174
    175	/**
    176	 * Last Entry matching
    177	 * Last_Entry field was introduced in revision 6 of the SRH draft.
    178	 * It was called First_Segment in the previous revision
    179	 */
    180	if (srhinfo->mt_flags & IP6T_SRH_LAST_EQ)
    181		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_EQ,
    182				!(srh->first_segment == srhinfo->last_entry)))
    183			return false;
    184	if (srhinfo->mt_flags & IP6T_SRH_LAST_GT)
    185		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_GT,
    186				!(srh->first_segment > srhinfo->last_entry)))
    187			return false;
    188	if (srhinfo->mt_flags & IP6T_SRH_LAST_LT)
    189		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_LT,
    190				!(srh->first_segment < srhinfo->last_entry)))
    191			return false;
    192
    193	/**
    194	 * Tag matchig
    195	 * Tag field was introduced in revision 6 of the SRH draft
    196	 */
    197	if (srhinfo->mt_flags & IP6T_SRH_TAG)
    198		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_TAG,
    199				!(srh->tag == srhinfo->tag)))
    200			return false;
    201
    202	/* Previous SID matching */
    203	if (srhinfo->mt_flags & IP6T_SRH_PSID) {
    204		if (srh->segments_left == srh->first_segment)
    205			return false;
    206		psidoff = srhoff + sizeof(struct ipv6_sr_hdr) +
    207			  ((srh->segments_left + 1) * sizeof(struct in6_addr));
    208		psid = skb_header_pointer(skb, psidoff, sizeof(_psid), &_psid);
    209		if (!psid)
    210			return false;
    211		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_PSID,
    212				ipv6_masked_addr_cmp(psid, &srhinfo->psid_msk,
    213						     &srhinfo->psid_addr)))
    214			return false;
    215	}
    216
    217	/* Next SID matching */
    218	if (srhinfo->mt_flags & IP6T_SRH_NSID) {
    219		if (srh->segments_left == 0)
    220			return false;
    221		nsidoff = srhoff + sizeof(struct ipv6_sr_hdr) +
    222			  ((srh->segments_left - 1) * sizeof(struct in6_addr));
    223		nsid = skb_header_pointer(skb, nsidoff, sizeof(_nsid), &_nsid);
    224		if (!nsid)
    225			return false;
    226		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_NSID,
    227				ipv6_masked_addr_cmp(nsid, &srhinfo->nsid_msk,
    228						     &srhinfo->nsid_addr)))
    229			return false;
    230	}
    231
    232	/* Last SID matching */
    233	if (srhinfo->mt_flags & IP6T_SRH_LSID) {
    234		lsidoff = srhoff + sizeof(struct ipv6_sr_hdr);
    235		lsid = skb_header_pointer(skb, lsidoff, sizeof(_lsid), &_lsid);
    236		if (!lsid)
    237			return false;
    238		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LSID,
    239				ipv6_masked_addr_cmp(lsid, &srhinfo->lsid_msk,
    240						     &srhinfo->lsid_addr)))
    241			return false;
    242	}
    243	return true;
    244}
    245
    246static int srh_mt6_check(const struct xt_mtchk_param *par)
    247{
    248	const struct ip6t_srh *srhinfo = par->matchinfo;
    249
    250	if (srhinfo->mt_flags & ~IP6T_SRH_MASK) {
    251		pr_info_ratelimited("unknown srh match flags  %X\n",
    252				    srhinfo->mt_flags);
    253		return -EINVAL;
    254	}
    255
    256	if (srhinfo->mt_invflags & ~IP6T_SRH_INV_MASK) {
    257		pr_info_ratelimited("unknown srh invflags %X\n",
    258				    srhinfo->mt_invflags);
    259		return -EINVAL;
    260	}
    261
    262	return 0;
    263}
    264
    265static int srh1_mt6_check(const struct xt_mtchk_param *par)
    266{
    267	const struct ip6t_srh1 *srhinfo = par->matchinfo;
    268
    269	if (srhinfo->mt_flags & ~IP6T_SRH_MASK) {
    270		pr_info_ratelimited("unknown srh match flags  %X\n",
    271				    srhinfo->mt_flags);
    272		return -EINVAL;
    273	}
    274
    275	if (srhinfo->mt_invflags & ~IP6T_SRH_INV_MASK) {
    276		pr_info_ratelimited("unknown srh invflags %X\n",
    277				    srhinfo->mt_invflags);
    278		return -EINVAL;
    279	}
    280
    281	return 0;
    282}
    283
    284static struct xt_match srh_mt6_reg[] __read_mostly = {
    285	{
    286		.name		= "srh",
    287		.revision	= 0,
    288		.family		= NFPROTO_IPV6,
    289		.match		= srh_mt6,
    290		.matchsize	= sizeof(struct ip6t_srh),
    291		.checkentry	= srh_mt6_check,
    292		.me		= THIS_MODULE,
    293	},
    294	{
    295		.name           = "srh",
    296		.revision       = 1,
    297		.family         = NFPROTO_IPV6,
    298		.match          = srh1_mt6,
    299		.matchsize      = sizeof(struct ip6t_srh1),
    300		.checkentry     = srh1_mt6_check,
    301		.me             = THIS_MODULE,
    302	}
    303};
    304
    305static int __init srh_mt6_init(void)
    306{
    307	return xt_register_matches(srh_mt6_reg, ARRAY_SIZE(srh_mt6_reg));
    308}
    309
    310static void __exit srh_mt6_exit(void)
    311{
    312	xt_unregister_matches(srh_mt6_reg, ARRAY_SIZE(srh_mt6_reg));
    313}
    314
    315module_init(srh_mt6_init);
    316module_exit(srh_mt6_exit);
    317
    318MODULE_LICENSE("GPL");
    319MODULE_DESCRIPTION("Xtables: IPv6 Segment Routing Header match");
    320MODULE_AUTHOR("Ahmed Abdelsalam <amsalam20@gmail.com>");