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_tcpudp.c (5781B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      3#include <linux/types.h>
      4#include <linux/module.h>
      5#include <net/ip.h>
      6#include <linux/ipv6.h>
      7#include <net/ipv6.h>
      8#include <net/tcp.h>
      9#include <net/udp.h>
     10#include <linux/netfilter/x_tables.h>
     11#include <linux/netfilter/xt_tcpudp.h>
     12#include <linux/netfilter_ipv4/ip_tables.h>
     13#include <linux/netfilter_ipv6/ip6_tables.h>
     14
     15MODULE_DESCRIPTION("Xtables: TCP, UDP and UDP-Lite match");
     16MODULE_LICENSE("GPL");
     17MODULE_ALIAS("xt_tcp");
     18MODULE_ALIAS("xt_udp");
     19MODULE_ALIAS("ipt_udp");
     20MODULE_ALIAS("ipt_tcp");
     21MODULE_ALIAS("ip6t_udp");
     22MODULE_ALIAS("ip6t_tcp");
     23
     24/* Returns 1 if the port is matched by the range, 0 otherwise */
     25static inline bool
     26port_match(u_int16_t min, u_int16_t max, u_int16_t port, bool invert)
     27{
     28	return (port >= min && port <= max) ^ invert;
     29}
     30
     31static bool
     32tcp_find_option(u_int8_t option,
     33		const struct sk_buff *skb,
     34		unsigned int protoff,
     35		unsigned int optlen,
     36		bool invert,
     37		bool *hotdrop)
     38{
     39	/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
     40	const u_int8_t *op;
     41	u_int8_t _opt[60 - sizeof(struct tcphdr)];
     42	unsigned int i;
     43
     44	pr_debug("finding option\n");
     45
     46	if (!optlen)
     47		return invert;
     48
     49	/* If we don't have the whole header, drop packet. */
     50	op = skb_header_pointer(skb, protoff + sizeof(struct tcphdr),
     51				optlen, _opt);
     52	if (op == NULL) {
     53		*hotdrop = true;
     54		return false;
     55	}
     56
     57	for (i = 0; i < optlen; ) {
     58		if (op[i] == option) return !invert;
     59		if (op[i] < 2) i++;
     60		else i += op[i+1]?:1;
     61	}
     62
     63	return invert;
     64}
     65
     66static bool tcp_mt(const struct sk_buff *skb, struct xt_action_param *par)
     67{
     68	const struct tcphdr *th;
     69	struct tcphdr _tcph;
     70	const struct xt_tcp *tcpinfo = par->matchinfo;
     71
     72	if (par->fragoff != 0) {
     73		/* To quote Alan:
     74
     75		   Don't allow a fragment of TCP 8 bytes in. Nobody normal
     76		   causes this. Its a cracker trying to break in by doing a
     77		   flag overwrite to pass the direction checks.
     78		*/
     79		if (par->fragoff == 1) {
     80			pr_debug("Dropping evil TCP offset=1 frag.\n");
     81			par->hotdrop = true;
     82		}
     83		/* Must not be a fragment. */
     84		return false;
     85	}
     86
     87	th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
     88	if (th == NULL) {
     89		/* We've been asked to examine this packet, and we
     90		   can't.  Hence, no choice but to drop. */
     91		pr_debug("Dropping evil TCP offset=0 tinygram.\n");
     92		par->hotdrop = true;
     93		return false;
     94	}
     95
     96	if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
     97			ntohs(th->source),
     98			!!(tcpinfo->invflags & XT_TCP_INV_SRCPT)))
     99		return false;
    100	if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
    101			ntohs(th->dest),
    102			!!(tcpinfo->invflags & XT_TCP_INV_DSTPT)))
    103		return false;
    104	if (!NF_INVF(tcpinfo, XT_TCP_INV_FLAGS,
    105		     (((unsigned char *)th)[13] & tcpinfo->flg_mask) == tcpinfo->flg_cmp))
    106		return false;
    107	if (tcpinfo->option) {
    108		if (th->doff * 4 < sizeof(_tcph)) {
    109			par->hotdrop = true;
    110			return false;
    111		}
    112		if (!tcp_find_option(tcpinfo->option, skb, par->thoff,
    113				     th->doff*4 - sizeof(_tcph),
    114				     tcpinfo->invflags & XT_TCP_INV_OPTION,
    115				     &par->hotdrop))
    116			return false;
    117	}
    118	return true;
    119}
    120
    121static int tcp_mt_check(const struct xt_mtchk_param *par)
    122{
    123	const struct xt_tcp *tcpinfo = par->matchinfo;
    124
    125	/* Must specify no unknown invflags */
    126	return (tcpinfo->invflags & ~XT_TCP_INV_MASK) ? -EINVAL : 0;
    127}
    128
    129static bool udp_mt(const struct sk_buff *skb, struct xt_action_param *par)
    130{
    131	const struct udphdr *uh;
    132	struct udphdr _udph;
    133	const struct xt_udp *udpinfo = par->matchinfo;
    134
    135	/* Must not be a fragment. */
    136	if (par->fragoff != 0)
    137		return false;
    138
    139	uh = skb_header_pointer(skb, par->thoff, sizeof(_udph), &_udph);
    140	if (uh == NULL) {
    141		/* We've been asked to examine this packet, and we
    142		   can't.  Hence, no choice but to drop. */
    143		pr_debug("Dropping evil UDP tinygram.\n");
    144		par->hotdrop = true;
    145		return false;
    146	}
    147
    148	return port_match(udpinfo->spts[0], udpinfo->spts[1],
    149			  ntohs(uh->source),
    150			  !!(udpinfo->invflags & XT_UDP_INV_SRCPT))
    151		&& port_match(udpinfo->dpts[0], udpinfo->dpts[1],
    152			      ntohs(uh->dest),
    153			      !!(udpinfo->invflags & XT_UDP_INV_DSTPT));
    154}
    155
    156static int udp_mt_check(const struct xt_mtchk_param *par)
    157{
    158	const struct xt_udp *udpinfo = par->matchinfo;
    159
    160	/* Must specify no unknown invflags */
    161	return (udpinfo->invflags & ~XT_UDP_INV_MASK) ? -EINVAL : 0;
    162}
    163
    164static struct xt_match tcpudp_mt_reg[] __read_mostly = {
    165	{
    166		.name		= "tcp",
    167		.family		= NFPROTO_IPV4,
    168		.checkentry	= tcp_mt_check,
    169		.match		= tcp_mt,
    170		.matchsize	= sizeof(struct xt_tcp),
    171		.proto		= IPPROTO_TCP,
    172		.me		= THIS_MODULE,
    173	},
    174	{
    175		.name		= "tcp",
    176		.family		= NFPROTO_IPV6,
    177		.checkentry	= tcp_mt_check,
    178		.match		= tcp_mt,
    179		.matchsize	= sizeof(struct xt_tcp),
    180		.proto		= IPPROTO_TCP,
    181		.me		= THIS_MODULE,
    182	},
    183	{
    184		.name		= "udp",
    185		.family		= NFPROTO_IPV4,
    186		.checkentry	= udp_mt_check,
    187		.match		= udp_mt,
    188		.matchsize	= sizeof(struct xt_udp),
    189		.proto		= IPPROTO_UDP,
    190		.me		= THIS_MODULE,
    191	},
    192	{
    193		.name		= "udp",
    194		.family		= NFPROTO_IPV6,
    195		.checkentry	= udp_mt_check,
    196		.match		= udp_mt,
    197		.matchsize	= sizeof(struct xt_udp),
    198		.proto		= IPPROTO_UDP,
    199		.me		= THIS_MODULE,
    200	},
    201	{
    202		.name		= "udplite",
    203		.family		= NFPROTO_IPV4,
    204		.checkentry	= udp_mt_check,
    205		.match		= udp_mt,
    206		.matchsize	= sizeof(struct xt_udp),
    207		.proto		= IPPROTO_UDPLITE,
    208		.me		= THIS_MODULE,
    209	},
    210	{
    211		.name		= "udplite",
    212		.family		= NFPROTO_IPV6,
    213		.checkentry	= udp_mt_check,
    214		.match		= udp_mt,
    215		.matchsize	= sizeof(struct xt_udp),
    216		.proto		= IPPROTO_UDPLITE,
    217		.me		= THIS_MODULE,
    218	},
    219};
    220
    221static int __init tcpudp_mt_init(void)
    222{
    223	return xt_register_matches(tcpudp_mt_reg, ARRAY_SIZE(tcpudp_mt_reg));
    224}
    225
    226static void __exit tcpudp_mt_exit(void)
    227{
    228	xt_unregister_matches(tcpudp_mt_reg, ARRAY_SIZE(tcpudp_mt_reg));
    229}
    230
    231module_init(tcpudp_mt_init);
    232module_exit(tcpudp_mt_exit);