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_sctp.c (5128B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      3#include <linux/module.h>
      4#include <linux/skbuff.h>
      5#include <net/ip.h>
      6#include <net/ipv6.h>
      7#include <net/sctp/sctp.h>
      8#include <linux/sctp.h>
      9
     10#include <linux/netfilter/x_tables.h>
     11#include <linux/netfilter/xt_sctp.h>
     12#include <linux/netfilter_ipv4/ip_tables.h>
     13#include <linux/netfilter_ipv6/ip6_tables.h>
     14
     15MODULE_LICENSE("GPL");
     16MODULE_AUTHOR("Kiran Kumar Immidi");
     17MODULE_DESCRIPTION("Xtables: SCTP protocol packet match");
     18MODULE_ALIAS("ipt_sctp");
     19MODULE_ALIAS("ip6t_sctp");
     20
     21#define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
     22					      || (!!((invflag) & (option)) ^ (cond)))
     23
     24static bool
     25match_flags(const struct xt_sctp_flag_info *flag_info,
     26	    const int flag_count,
     27	    u_int8_t chunktype,
     28	    u_int8_t chunkflags)
     29{
     30	int i;
     31
     32	for (i = 0; i < flag_count; i++)
     33		if (flag_info[i].chunktype == chunktype)
     34			return (chunkflags & flag_info[i].flag_mask) == flag_info[i].flag;
     35
     36	return true;
     37}
     38
     39static inline bool
     40match_packet(const struct sk_buff *skb,
     41	     unsigned int offset,
     42	     const struct xt_sctp_info *info,
     43	     bool *hotdrop)
     44{
     45	u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)];
     46	const struct sctp_chunkhdr *sch;
     47	struct sctp_chunkhdr _sch;
     48	int chunk_match_type = info->chunk_match_type;
     49	const struct xt_sctp_flag_info *flag_info = info->flag_info;
     50	int flag_count = info->flag_count;
     51
     52#ifdef DEBUG
     53	int i = 0;
     54#endif
     55
     56	if (chunk_match_type == SCTP_CHUNK_MATCH_ALL)
     57		SCTP_CHUNKMAP_COPY(chunkmapcopy, info->chunkmap);
     58
     59	do {
     60		sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch);
     61		if (sch == NULL || sch->length == 0) {
     62			pr_debug("Dropping invalid SCTP packet.\n");
     63			*hotdrop = true;
     64			return false;
     65		}
     66#ifdef DEBUG
     67		pr_debug("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d"
     68			 "\tflags: %x\n",
     69			 ++i, offset, sch->type, htons(sch->length),
     70			 sch->flags);
     71#endif
     72		offset += SCTP_PAD4(ntohs(sch->length));
     73
     74		pr_debug("skb->len: %d\toffset: %d\n", skb->len, offset);
     75
     76		if (SCTP_CHUNKMAP_IS_SET(info->chunkmap, sch->type)) {
     77			switch (chunk_match_type) {
     78			case SCTP_CHUNK_MATCH_ANY:
     79				if (match_flags(flag_info, flag_count,
     80					sch->type, sch->flags)) {
     81					return true;
     82				}
     83				break;
     84
     85			case SCTP_CHUNK_MATCH_ALL:
     86				if (match_flags(flag_info, flag_count,
     87				    sch->type, sch->flags))
     88					SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch->type);
     89				break;
     90
     91			case SCTP_CHUNK_MATCH_ONLY:
     92				if (!match_flags(flag_info, flag_count,
     93				    sch->type, sch->flags))
     94					return false;
     95				break;
     96			}
     97		} else {
     98			switch (chunk_match_type) {
     99			case SCTP_CHUNK_MATCH_ONLY:
    100				return false;
    101			}
    102		}
    103	} while (offset < skb->len);
    104
    105	switch (chunk_match_type) {
    106	case SCTP_CHUNK_MATCH_ALL:
    107		return SCTP_CHUNKMAP_IS_CLEAR(chunkmapcopy);
    108	case SCTP_CHUNK_MATCH_ANY:
    109		return false;
    110	case SCTP_CHUNK_MATCH_ONLY:
    111		return true;
    112	}
    113
    114	/* This will never be reached, but required to stop compiler whine */
    115	return false;
    116}
    117
    118static bool
    119sctp_mt(const struct sk_buff *skb, struct xt_action_param *par)
    120{
    121	const struct xt_sctp_info *info = par->matchinfo;
    122	const struct sctphdr *sh;
    123	struct sctphdr _sh;
    124
    125	if (par->fragoff != 0) {
    126		pr_debug("Dropping non-first fragment.. FIXME\n");
    127		return false;
    128	}
    129
    130	sh = skb_header_pointer(skb, par->thoff, sizeof(_sh), &_sh);
    131	if (sh == NULL) {
    132		pr_debug("Dropping evil TCP offset=0 tinygram.\n");
    133		par->hotdrop = true;
    134		return false;
    135	}
    136	pr_debug("spt: %d\tdpt: %d\n", ntohs(sh->source), ntohs(sh->dest));
    137
    138	return  SCCHECK(ntohs(sh->source) >= info->spts[0]
    139			&& ntohs(sh->source) <= info->spts[1],
    140			XT_SCTP_SRC_PORTS, info->flags, info->invflags) &&
    141		SCCHECK(ntohs(sh->dest) >= info->dpts[0]
    142			&& ntohs(sh->dest) <= info->dpts[1],
    143			XT_SCTP_DEST_PORTS, info->flags, info->invflags) &&
    144		SCCHECK(match_packet(skb, par->thoff + sizeof(_sh),
    145				     info, &par->hotdrop),
    146			XT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
    147}
    148
    149static int sctp_mt_check(const struct xt_mtchk_param *par)
    150{
    151	const struct xt_sctp_info *info = par->matchinfo;
    152
    153	if (info->flags & ~XT_SCTP_VALID_FLAGS)
    154		return -EINVAL;
    155	if (info->invflags & ~XT_SCTP_VALID_FLAGS)
    156		return -EINVAL;
    157	if (info->invflags & ~info->flags)
    158		return -EINVAL;
    159	if (!(info->flags & XT_SCTP_CHUNK_TYPES))
    160		return 0;
    161	if (info->chunk_match_type & (SCTP_CHUNK_MATCH_ALL |
    162	    SCTP_CHUNK_MATCH_ANY | SCTP_CHUNK_MATCH_ONLY))
    163		return 0;
    164	return -EINVAL;
    165}
    166
    167static struct xt_match sctp_mt_reg[] __read_mostly = {
    168	{
    169		.name		= "sctp",
    170		.family		= NFPROTO_IPV4,
    171		.checkentry	= sctp_mt_check,
    172		.match		= sctp_mt,
    173		.matchsize	= sizeof(struct xt_sctp_info),
    174		.proto		= IPPROTO_SCTP,
    175		.me		= THIS_MODULE
    176	},
    177	{
    178		.name		= "sctp",
    179		.family		= NFPROTO_IPV6,
    180		.checkentry	= sctp_mt_check,
    181		.match		= sctp_mt,
    182		.matchsize	= sizeof(struct xt_sctp_info),
    183		.proto		= IPPROTO_SCTP,
    184		.me		= THIS_MODULE
    185	},
    186};
    187
    188static int __init sctp_mt_init(void)
    189{
    190	return xt_register_matches(sctp_mt_reg, ARRAY_SIZE(sctp_mt_reg));
    191}
    192
    193static void __exit sctp_mt_exit(void)
    194{
    195	xt_unregister_matches(sctp_mt_reg, ARRAY_SIZE(sctp_mt_reg));
    196}
    197
    198module_init(sctp_mt_init);
    199module_exit(sctp_mt_exit);