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

reassembly.c (15215B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *	IPv6 fragment reassembly
      4 *	Linux INET6 implementation
      5 *
      6 *	Authors:
      7 *	Pedro Roque		<roque@di.fc.ul.pt>
      8 *
      9 *	Based on: net/ipv4/ip_fragment.c
     10 */
     11
     12/*
     13 *	Fixes:
     14 *	Andi Kleen	Make it work with multiple hosts.
     15 *			More RFC compliance.
     16 *
     17 *      Horst von Brand Add missing #include <linux/string.h>
     18 *	Alexey Kuznetsov	SMP races, threading, cleanup.
     19 *	Patrick McHardy		LRU queue of frag heads for evictor.
     20 *	Mitsuru KANDA @USAGI	Register inet6_protocol{}.
     21 *	David Stevens and
     22 *	YOSHIFUJI,H. @USAGI	Always remove fragment header to
     23 *				calculate ICV correctly.
     24 */
     25
     26#define pr_fmt(fmt) "IPv6: " fmt
     27
     28#include <linux/errno.h>
     29#include <linux/types.h>
     30#include <linux/string.h>
     31#include <linux/socket.h>
     32#include <linux/sockios.h>
     33#include <linux/jiffies.h>
     34#include <linux/net.h>
     35#include <linux/list.h>
     36#include <linux/netdevice.h>
     37#include <linux/in6.h>
     38#include <linux/ipv6.h>
     39#include <linux/icmpv6.h>
     40#include <linux/random.h>
     41#include <linux/jhash.h>
     42#include <linux/skbuff.h>
     43#include <linux/slab.h>
     44#include <linux/export.h>
     45#include <linux/tcp.h>
     46#include <linux/udp.h>
     47
     48#include <net/sock.h>
     49#include <net/snmp.h>
     50
     51#include <net/ipv6.h>
     52#include <net/ip6_route.h>
     53#include <net/protocol.h>
     54#include <net/transp_v6.h>
     55#include <net/rawv6.h>
     56#include <net/ndisc.h>
     57#include <net/addrconf.h>
     58#include <net/ipv6_frag.h>
     59#include <net/inet_ecn.h>
     60
     61static const char ip6_frag_cache_name[] = "ip6-frags";
     62
     63static u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h)
     64{
     65	return 1 << (ipv6_get_dsfield(ipv6h) & INET_ECN_MASK);
     66}
     67
     68static struct inet_frags ip6_frags;
     69
     70static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *skb,
     71			  struct sk_buff *prev_tail, struct net_device *dev);
     72
     73static void ip6_frag_expire(struct timer_list *t)
     74{
     75	struct inet_frag_queue *frag = from_timer(frag, t, timer);
     76	struct frag_queue *fq;
     77
     78	fq = container_of(frag, struct frag_queue, q);
     79
     80	ip6frag_expire_frag_queue(fq->q.fqdir->net, fq);
     81}
     82
     83static struct frag_queue *
     84fq_find(struct net *net, __be32 id, const struct ipv6hdr *hdr, int iif)
     85{
     86	struct frag_v6_compare_key key = {
     87		.id = id,
     88		.saddr = hdr->saddr,
     89		.daddr = hdr->daddr,
     90		.user = IP6_DEFRAG_LOCAL_DELIVER,
     91		.iif = iif,
     92	};
     93	struct inet_frag_queue *q;
     94
     95	if (!(ipv6_addr_type(&hdr->daddr) & (IPV6_ADDR_MULTICAST |
     96					    IPV6_ADDR_LINKLOCAL)))
     97		key.iif = 0;
     98
     99	q = inet_frag_find(net->ipv6.fqdir, &key);
    100	if (!q)
    101		return NULL;
    102
    103	return container_of(q, struct frag_queue, q);
    104}
    105
    106static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
    107			  struct frag_hdr *fhdr, int nhoff,
    108			  u32 *prob_offset)
    109{
    110	struct net *net = dev_net(skb_dst(skb)->dev);
    111	int offset, end, fragsize;
    112	struct sk_buff *prev_tail;
    113	struct net_device *dev;
    114	int err = -ENOENT;
    115	u8 ecn;
    116
    117	if (fq->q.flags & INET_FRAG_COMPLETE)
    118		goto err;
    119
    120	err = -EINVAL;
    121	offset = ntohs(fhdr->frag_off) & ~0x7;
    122	end = offset + (ntohs(ipv6_hdr(skb)->payload_len) -
    123			((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1)));
    124
    125	if ((unsigned int)end > IPV6_MAXPLEN) {
    126		*prob_offset = (u8 *)&fhdr->frag_off - skb_network_header(skb);
    127		/* note that if prob_offset is set, the skb is freed elsewhere,
    128		 * we do not free it here.
    129		 */
    130		return -1;
    131	}
    132
    133	ecn = ip6_frag_ecn(ipv6_hdr(skb));
    134
    135	if (skb->ip_summed == CHECKSUM_COMPLETE) {
    136		const unsigned char *nh = skb_network_header(skb);
    137		skb->csum = csum_sub(skb->csum,
    138				     csum_partial(nh, (u8 *)(fhdr + 1) - nh,
    139						  0));
    140	}
    141
    142	/* Is this the final fragment? */
    143	if (!(fhdr->frag_off & htons(IP6_MF))) {
    144		/* If we already have some bits beyond end
    145		 * or have different end, the segment is corrupted.
    146		 */
    147		if (end < fq->q.len ||
    148		    ((fq->q.flags & INET_FRAG_LAST_IN) && end != fq->q.len))
    149			goto discard_fq;
    150		fq->q.flags |= INET_FRAG_LAST_IN;
    151		fq->q.len = end;
    152	} else {
    153		/* Check if the fragment is rounded to 8 bytes.
    154		 * Required by the RFC.
    155		 */
    156		if (end & 0x7) {
    157			/* RFC2460 says always send parameter problem in
    158			 * this case. -DaveM
    159			 */
    160			*prob_offset = offsetof(struct ipv6hdr, payload_len);
    161			return -1;
    162		}
    163		if (end > fq->q.len) {
    164			/* Some bits beyond end -> corruption. */
    165			if (fq->q.flags & INET_FRAG_LAST_IN)
    166				goto discard_fq;
    167			fq->q.len = end;
    168		}
    169	}
    170
    171	if (end == offset)
    172		goto discard_fq;
    173
    174	err = -ENOMEM;
    175	/* Point into the IP datagram 'data' part. */
    176	if (!pskb_pull(skb, (u8 *) (fhdr + 1) - skb->data))
    177		goto discard_fq;
    178
    179	err = pskb_trim_rcsum(skb, end - offset);
    180	if (err)
    181		goto discard_fq;
    182
    183	/* Note : skb->rbnode and skb->dev share the same location. */
    184	dev = skb->dev;
    185	/* Makes sure compiler wont do silly aliasing games */
    186	barrier();
    187
    188	prev_tail = fq->q.fragments_tail;
    189	err = inet_frag_queue_insert(&fq->q, skb, offset, end);
    190	if (err)
    191		goto insert_error;
    192
    193	if (dev)
    194		fq->iif = dev->ifindex;
    195
    196	fq->q.stamp = skb->tstamp;
    197	fq->q.mono_delivery_time = skb->mono_delivery_time;
    198	fq->q.meat += skb->len;
    199	fq->ecn |= ecn;
    200	add_frag_mem_limit(fq->q.fqdir, skb->truesize);
    201
    202	fragsize = -skb_network_offset(skb) + skb->len;
    203	if (fragsize > fq->q.max_size)
    204		fq->q.max_size = fragsize;
    205
    206	/* The first fragment.
    207	 * nhoffset is obtained from the first fragment, of course.
    208	 */
    209	if (offset == 0) {
    210		fq->nhoffset = nhoff;
    211		fq->q.flags |= INET_FRAG_FIRST_IN;
    212	}
    213
    214	if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
    215	    fq->q.meat == fq->q.len) {
    216		unsigned long orefdst = skb->_skb_refdst;
    217
    218		skb->_skb_refdst = 0UL;
    219		err = ip6_frag_reasm(fq, skb, prev_tail, dev);
    220		skb->_skb_refdst = orefdst;
    221		return err;
    222	}
    223
    224	skb_dst_drop(skb);
    225	return -EINPROGRESS;
    226
    227insert_error:
    228	if (err == IPFRAG_DUP) {
    229		kfree_skb(skb);
    230		return -EINVAL;
    231	}
    232	err = -EINVAL;
    233	__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
    234			IPSTATS_MIB_REASM_OVERLAPS);
    235discard_fq:
    236	inet_frag_kill(&fq->q);
    237	__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
    238			IPSTATS_MIB_REASMFAILS);
    239err:
    240	kfree_skb(skb);
    241	return err;
    242}
    243
    244/*
    245 *	Check if this packet is complete.
    246 *
    247 *	It is called with locked fq, and caller must check that
    248 *	queue is eligible for reassembly i.e. it is not COMPLETE,
    249 *	the last and the first frames arrived and all the bits are here.
    250 */
    251static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *skb,
    252			  struct sk_buff *prev_tail, struct net_device *dev)
    253{
    254	struct net *net = fq->q.fqdir->net;
    255	unsigned int nhoff;
    256	void *reasm_data;
    257	int payload_len;
    258	u8 ecn;
    259
    260	inet_frag_kill(&fq->q);
    261
    262	ecn = ip_frag_ecn_table[fq->ecn];
    263	if (unlikely(ecn == 0xff))
    264		goto out_fail;
    265
    266	reasm_data = inet_frag_reasm_prepare(&fq->q, skb, prev_tail);
    267	if (!reasm_data)
    268		goto out_oom;
    269
    270	payload_len = ((skb->data - skb_network_header(skb)) -
    271		       sizeof(struct ipv6hdr) + fq->q.len -
    272		       sizeof(struct frag_hdr));
    273	if (payload_len > IPV6_MAXPLEN)
    274		goto out_oversize;
    275
    276	/* We have to remove fragment header from datagram and to relocate
    277	 * header in order to calculate ICV correctly. */
    278	nhoff = fq->nhoffset;
    279	skb_network_header(skb)[nhoff] = skb_transport_header(skb)[0];
    280	memmove(skb->head + sizeof(struct frag_hdr), skb->head,
    281		(skb->data - skb->head) - sizeof(struct frag_hdr));
    282	if (skb_mac_header_was_set(skb))
    283		skb->mac_header += sizeof(struct frag_hdr);
    284	skb->network_header += sizeof(struct frag_hdr);
    285
    286	skb_reset_transport_header(skb);
    287
    288	inet_frag_reasm_finish(&fq->q, skb, reasm_data, true);
    289
    290	skb->dev = dev;
    291	ipv6_hdr(skb)->payload_len = htons(payload_len);
    292	ipv6_change_dsfield(ipv6_hdr(skb), 0xff, ecn);
    293	IP6CB(skb)->nhoff = nhoff;
    294	IP6CB(skb)->flags |= IP6SKB_FRAGMENTED;
    295	IP6CB(skb)->frag_max_size = fq->q.max_size;
    296
    297	/* Yes, and fold redundant checksum back. 8) */
    298	skb_postpush_rcsum(skb, skb_network_header(skb),
    299			   skb_network_header_len(skb));
    300
    301	rcu_read_lock();
    302	__IP6_INC_STATS(net, __in6_dev_stats_get(dev, skb), IPSTATS_MIB_REASMOKS);
    303	rcu_read_unlock();
    304	fq->q.rb_fragments = RB_ROOT;
    305	fq->q.fragments_tail = NULL;
    306	fq->q.last_run_head = NULL;
    307	return 1;
    308
    309out_oversize:
    310	net_dbg_ratelimited("ip6_frag_reasm: payload len = %d\n", payload_len);
    311	goto out_fail;
    312out_oom:
    313	net_dbg_ratelimited("ip6_frag_reasm: no memory for reassembly\n");
    314out_fail:
    315	rcu_read_lock();
    316	__IP6_INC_STATS(net, __in6_dev_stats_get(dev, skb), IPSTATS_MIB_REASMFAILS);
    317	rcu_read_unlock();
    318	inet_frag_kill(&fq->q);
    319	return -1;
    320}
    321
    322static int ipv6_frag_rcv(struct sk_buff *skb)
    323{
    324	struct frag_hdr *fhdr;
    325	struct frag_queue *fq;
    326	const struct ipv6hdr *hdr = ipv6_hdr(skb);
    327	struct net *net = dev_net(skb_dst(skb)->dev);
    328	u8 nexthdr;
    329	int iif;
    330
    331	if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED)
    332		goto fail_hdr;
    333
    334	__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMREQDS);
    335
    336	/* Jumbo payload inhibits frag. header */
    337	if (hdr->payload_len == 0)
    338		goto fail_hdr;
    339
    340	if (!pskb_may_pull(skb, (skb_transport_offset(skb) +
    341				 sizeof(struct frag_hdr))))
    342		goto fail_hdr;
    343
    344	hdr = ipv6_hdr(skb);
    345	fhdr = (struct frag_hdr *)skb_transport_header(skb);
    346
    347	if (!(fhdr->frag_off & htons(IP6_OFFSET | IP6_MF))) {
    348		/* It is not a fragmented frame */
    349		skb->transport_header += sizeof(struct frag_hdr);
    350		__IP6_INC_STATS(net,
    351				ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMOKS);
    352
    353		IP6CB(skb)->nhoff = (u8 *)fhdr - skb_network_header(skb);
    354		IP6CB(skb)->flags |= IP6SKB_FRAGMENTED;
    355		IP6CB(skb)->frag_max_size = ntohs(hdr->payload_len) +
    356					    sizeof(struct ipv6hdr);
    357		return 1;
    358	}
    359
    360	/* RFC 8200, Section 4.5 Fragment Header:
    361	 * If the first fragment does not include all headers through an
    362	 * Upper-Layer header, then that fragment should be discarded and
    363	 * an ICMP Parameter Problem, Code 3, message should be sent to
    364	 * the source of the fragment, with the Pointer field set to zero.
    365	 */
    366	nexthdr = hdr->nexthdr;
    367	if (ipv6frag_thdr_truncated(skb, skb_transport_offset(skb), &nexthdr)) {
    368		__IP6_INC_STATS(net, __in6_dev_get_safely(skb->dev),
    369				IPSTATS_MIB_INHDRERRORS);
    370		icmpv6_param_prob(skb, ICMPV6_HDR_INCOMP, 0);
    371		return -1;
    372	}
    373
    374	iif = skb->dev ? skb->dev->ifindex : 0;
    375	fq = fq_find(net, fhdr->identification, hdr, iif);
    376	if (fq) {
    377		u32 prob_offset = 0;
    378		int ret;
    379
    380		spin_lock(&fq->q.lock);
    381
    382		fq->iif = iif;
    383		ret = ip6_frag_queue(fq, skb, fhdr, IP6CB(skb)->nhoff,
    384				     &prob_offset);
    385
    386		spin_unlock(&fq->q.lock);
    387		inet_frag_put(&fq->q);
    388		if (prob_offset) {
    389			__IP6_INC_STATS(net, __in6_dev_get_safely(skb->dev),
    390					IPSTATS_MIB_INHDRERRORS);
    391			/* icmpv6_param_prob() calls kfree_skb(skb) */
    392			icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, prob_offset);
    393		}
    394		return ret;
    395	}
    396
    397	__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMFAILS);
    398	kfree_skb(skb);
    399	return -1;
    400
    401fail_hdr:
    402	__IP6_INC_STATS(net, __in6_dev_get_safely(skb->dev),
    403			IPSTATS_MIB_INHDRERRORS);
    404	icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb_network_header_len(skb));
    405	return -1;
    406}
    407
    408static const struct inet6_protocol frag_protocol = {
    409	.handler	=	ipv6_frag_rcv,
    410	.flags		=	INET6_PROTO_NOPOLICY,
    411};
    412
    413#ifdef CONFIG_SYSCTL
    414
    415static struct ctl_table ip6_frags_ns_ctl_table[] = {
    416	{
    417		.procname	= "ip6frag_high_thresh",
    418		.maxlen		= sizeof(unsigned long),
    419		.mode		= 0644,
    420		.proc_handler	= proc_doulongvec_minmax,
    421	},
    422	{
    423		.procname	= "ip6frag_low_thresh",
    424		.maxlen		= sizeof(unsigned long),
    425		.mode		= 0644,
    426		.proc_handler	= proc_doulongvec_minmax,
    427	},
    428	{
    429		.procname	= "ip6frag_time",
    430		.maxlen		= sizeof(int),
    431		.mode		= 0644,
    432		.proc_handler	= proc_dointvec_jiffies,
    433	},
    434	{ }
    435};
    436
    437/* secret interval has been deprecated */
    438static int ip6_frags_secret_interval_unused;
    439static struct ctl_table ip6_frags_ctl_table[] = {
    440	{
    441		.procname	= "ip6frag_secret_interval",
    442		.data		= &ip6_frags_secret_interval_unused,
    443		.maxlen		= sizeof(int),
    444		.mode		= 0644,
    445		.proc_handler	= proc_dointvec_jiffies,
    446	},
    447	{ }
    448};
    449
    450static int __net_init ip6_frags_ns_sysctl_register(struct net *net)
    451{
    452	struct ctl_table *table;
    453	struct ctl_table_header *hdr;
    454
    455	table = ip6_frags_ns_ctl_table;
    456	if (!net_eq(net, &init_net)) {
    457		table = kmemdup(table, sizeof(ip6_frags_ns_ctl_table), GFP_KERNEL);
    458		if (!table)
    459			goto err_alloc;
    460
    461	}
    462	table[0].data	= &net->ipv6.fqdir->high_thresh;
    463	table[0].extra1	= &net->ipv6.fqdir->low_thresh;
    464	table[1].data	= &net->ipv6.fqdir->low_thresh;
    465	table[1].extra2	= &net->ipv6.fqdir->high_thresh;
    466	table[2].data	= &net->ipv6.fqdir->timeout;
    467
    468	hdr = register_net_sysctl(net, "net/ipv6", table);
    469	if (!hdr)
    470		goto err_reg;
    471
    472	net->ipv6.sysctl.frags_hdr = hdr;
    473	return 0;
    474
    475err_reg:
    476	if (!net_eq(net, &init_net))
    477		kfree(table);
    478err_alloc:
    479	return -ENOMEM;
    480}
    481
    482static void __net_exit ip6_frags_ns_sysctl_unregister(struct net *net)
    483{
    484	struct ctl_table *table;
    485
    486	table = net->ipv6.sysctl.frags_hdr->ctl_table_arg;
    487	unregister_net_sysctl_table(net->ipv6.sysctl.frags_hdr);
    488	if (!net_eq(net, &init_net))
    489		kfree(table);
    490}
    491
    492static struct ctl_table_header *ip6_ctl_header;
    493
    494static int ip6_frags_sysctl_register(void)
    495{
    496	ip6_ctl_header = register_net_sysctl(&init_net, "net/ipv6",
    497			ip6_frags_ctl_table);
    498	return ip6_ctl_header == NULL ? -ENOMEM : 0;
    499}
    500
    501static void ip6_frags_sysctl_unregister(void)
    502{
    503	unregister_net_sysctl_table(ip6_ctl_header);
    504}
    505#else
    506static int ip6_frags_ns_sysctl_register(struct net *net)
    507{
    508	return 0;
    509}
    510
    511static void ip6_frags_ns_sysctl_unregister(struct net *net)
    512{
    513}
    514
    515static int ip6_frags_sysctl_register(void)
    516{
    517	return 0;
    518}
    519
    520static void ip6_frags_sysctl_unregister(void)
    521{
    522}
    523#endif
    524
    525static int __net_init ipv6_frags_init_net(struct net *net)
    526{
    527	int res;
    528
    529	res = fqdir_init(&net->ipv6.fqdir, &ip6_frags, net);
    530	if (res < 0)
    531		return res;
    532
    533	net->ipv6.fqdir->high_thresh = IPV6_FRAG_HIGH_THRESH;
    534	net->ipv6.fqdir->low_thresh = IPV6_FRAG_LOW_THRESH;
    535	net->ipv6.fqdir->timeout = IPV6_FRAG_TIMEOUT;
    536
    537	res = ip6_frags_ns_sysctl_register(net);
    538	if (res < 0)
    539		fqdir_exit(net->ipv6.fqdir);
    540	return res;
    541}
    542
    543static void __net_exit ipv6_frags_pre_exit_net(struct net *net)
    544{
    545	fqdir_pre_exit(net->ipv6.fqdir);
    546}
    547
    548static void __net_exit ipv6_frags_exit_net(struct net *net)
    549{
    550	ip6_frags_ns_sysctl_unregister(net);
    551	fqdir_exit(net->ipv6.fqdir);
    552}
    553
    554static struct pernet_operations ip6_frags_ops = {
    555	.init		= ipv6_frags_init_net,
    556	.pre_exit	= ipv6_frags_pre_exit_net,
    557	.exit		= ipv6_frags_exit_net,
    558};
    559
    560static const struct rhashtable_params ip6_rhash_params = {
    561	.head_offset		= offsetof(struct inet_frag_queue, node),
    562	.hashfn			= ip6frag_key_hashfn,
    563	.obj_hashfn		= ip6frag_obj_hashfn,
    564	.obj_cmpfn		= ip6frag_obj_cmpfn,
    565	.automatic_shrinking	= true,
    566};
    567
    568int __init ipv6_frag_init(void)
    569{
    570	int ret;
    571
    572	ip6_frags.constructor = ip6frag_init;
    573	ip6_frags.destructor = NULL;
    574	ip6_frags.qsize = sizeof(struct frag_queue);
    575	ip6_frags.frag_expire = ip6_frag_expire;
    576	ip6_frags.frags_cache_name = ip6_frag_cache_name;
    577	ip6_frags.rhash_params = ip6_rhash_params;
    578	ret = inet_frags_init(&ip6_frags);
    579	if (ret)
    580		goto out;
    581
    582	ret = inet6_add_protocol(&frag_protocol, IPPROTO_FRAGMENT);
    583	if (ret)
    584		goto err_protocol;
    585
    586	ret = ip6_frags_sysctl_register();
    587	if (ret)
    588		goto err_sysctl;
    589
    590	ret = register_pernet_subsys(&ip6_frags_ops);
    591	if (ret)
    592		goto err_pernet;
    593
    594out:
    595	return ret;
    596
    597err_pernet:
    598	ip6_frags_sysctl_unregister();
    599err_sysctl:
    600	inet6_del_protocol(&frag_protocol, IPPROTO_FRAGMENT);
    601err_protocol:
    602	inet_frags_fini(&ip6_frags);
    603	goto out;
    604}
    605
    606void ipv6_frag_exit(void)
    607{
    608	ip6_frags_sysctl_unregister();
    609	unregister_pernet_subsys(&ip6_frags_ops);
    610	inet6_del_protocol(&frag_protocol, IPPROTO_FRAGMENT);
    611	inet_frags_fini(&ip6_frags);
    612}