File Index
Files and directories
Sign in
FILE

reassembly.c

File preview with syntax highlighting.

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