hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/net/ipv6/reassembly.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * IPv6 fragment reassembly
34 * Linux INET6 implementation
....@@ -6,11 +7,6 @@
67 * Pedro Roque <roque@di.fc.ul.pt>
78 *
89 * Based on: net/ipv4/ip_fragment.c
9
- *
10
- * This program is free software; you can redistribute it and/or
11
- * modify it under the terms of the GNU General Public License
12
- * as published by the Free Software Foundation; either version
13
- * 2 of the License, or (at your option) any later version.
1410 */
1511
1612 /*
....@@ -46,6 +42,8 @@
4642 #include <linux/skbuff.h>
4743 #include <linux/slab.h>
4844 #include <linux/export.h>
45
+#include <linux/tcp.h>
46
+#include <linux/udp.h>
4947
5048 #include <net/sock.h>
5149 #include <net/snmp.h>
....@@ -76,12 +74,10 @@
7674 {
7775 struct inet_frag_queue *frag = from_timer(frag, t, timer);
7876 struct frag_queue *fq;
79
- struct net *net;
8077
8178 fq = container_of(frag, struct frag_queue, q);
82
- net = container_of(fq->q.net, struct net, ipv6.frags);
8379
84
- ip6frag_expire_frag_queue(net, fq);
80
+ ip6frag_expire_frag_queue(fq->q.fqdir->net, fq);
8581 }
8682
8783 static struct frag_queue *
....@@ -100,7 +96,7 @@
10096 IPV6_ADDR_LINKLOCAL)))
10197 key.iif = 0;
10298
103
- q = inet_frag_find(&net->ipv6.frags, &key);
99
+ q = inet_frag_find(net->ipv6.fqdir, &key);
104100 if (!q)
105101 return NULL;
106102
....@@ -200,7 +196,7 @@
200196 fq->q.stamp = skb->tstamp;
201197 fq->q.meat += skb->len;
202198 fq->ecn |= ecn;
203
- add_frag_mem_limit(fq->q.net, skb->truesize);
199
+ add_frag_mem_limit(fq->q.fqdir, skb->truesize);
204200
205201 fragsize = -skb_network_offset(skb) + skb->len;
206202 if (fragsize > fq->q.max_size)
....@@ -254,7 +250,7 @@
254250 static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *skb,
255251 struct sk_buff *prev_tail, struct net_device *dev)
256252 {
257
- struct net *net = container_of(fq->q.net, struct net, ipv6.frags);
253
+ struct net *net = fq->q.fqdir->net;
258254 unsigned int nhoff;
259255 void *reasm_data;
260256 int payload_len;
....@@ -288,7 +284,7 @@
288284
289285 skb_reset_transport_header(skb);
290286
291
- inet_frag_reasm_finish(&fq->q, skb, reasm_data);
287
+ inet_frag_reasm_finish(&fq->q, skb, reasm_data, true);
292288
293289 skb->dev = dev;
294290 ipv6_hdr(skb)->payload_len = htons(payload_len);
....@@ -302,9 +298,8 @@
302298 skb_network_header_len(skb));
303299
304300 rcu_read_lock();
305
- __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS);
301
+ __IP6_INC_STATS(net, __in6_dev_stats_get(dev, skb), IPSTATS_MIB_REASMOKS);
306302 rcu_read_unlock();
307
- fq->q.fragments = NULL;
308303 fq->q.rb_fragments = RB_ROOT;
309304 fq->q.fragments_tail = NULL;
310305 fq->q.last_run_head = NULL;
....@@ -317,7 +312,7 @@
317312 net_dbg_ratelimited("ip6_frag_reasm: no memory for reassembly\n");
318313 out_fail:
319314 rcu_read_lock();
320
- __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
315
+ __IP6_INC_STATS(net, __in6_dev_stats_get(dev, skb), IPSTATS_MIB_REASMFAILS);
321316 rcu_read_unlock();
322317 inet_frag_kill(&fq->q);
323318 return -1;
....@@ -329,6 +324,7 @@
329324 struct frag_queue *fq;
330325 const struct ipv6hdr *hdr = ipv6_hdr(skb);
331326 struct net *net = dev_net(skb_dst(skb)->dev);
327
+ u8 nexthdr;
332328 int iif;
333329
334330 if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED)
....@@ -358,6 +354,20 @@
358354 IP6CB(skb)->frag_max_size = ntohs(hdr->payload_len) +
359355 sizeof(struct ipv6hdr);
360356 return 1;
357
+ }
358
+
359
+ /* RFC 8200, Section 4.5 Fragment Header:
360
+ * If the first fragment does not include all headers through an
361
+ * Upper-Layer header, then that fragment should be discarded and
362
+ * an ICMP Parameter Problem, Code 3, message should be sent to
363
+ * the source of the fragment, with the Pointer field set to zero.
364
+ */
365
+ nexthdr = hdr->nexthdr;
366
+ if (ipv6frag_thdr_truncated(skb, skb_transport_offset(skb), &nexthdr)) {
367
+ __IP6_INC_STATS(net, __in6_dev_get_safely(skb->dev),
368
+ IPSTATS_MIB_INHDRERRORS);
369
+ icmpv6_param_prob(skb, ICMPV6_HDR_INCOMP, 0);
370
+ return -1;
361371 }
362372
363373 iif = skb->dev ? skb->dev->ifindex : 0;
....@@ -404,23 +414,18 @@
404414 static struct ctl_table ip6_frags_ns_ctl_table[] = {
405415 {
406416 .procname = "ip6frag_high_thresh",
407
- .data = &init_net.ipv6.frags.high_thresh,
408417 .maxlen = sizeof(unsigned long),
409418 .mode = 0644,
410419 .proc_handler = proc_doulongvec_minmax,
411
- .extra1 = &init_net.ipv6.frags.low_thresh
412420 },
413421 {
414422 .procname = "ip6frag_low_thresh",
415
- .data = &init_net.ipv6.frags.low_thresh,
416423 .maxlen = sizeof(unsigned long),
417424 .mode = 0644,
418425 .proc_handler = proc_doulongvec_minmax,
419
- .extra2 = &init_net.ipv6.frags.high_thresh
420426 },
421427 {
422428 .procname = "ip6frag_time",
423
- .data = &init_net.ipv6.frags.timeout,
424429 .maxlen = sizeof(int),
425430 .mode = 0644,
426431 .proc_handler = proc_dointvec_jiffies,
....@@ -452,13 +457,12 @@
452457 if (!table)
453458 goto err_alloc;
454459
455
- table[0].data = &net->ipv6.frags.high_thresh;
456
- table[0].extra1 = &net->ipv6.frags.low_thresh;
457
- table[0].extra2 = &init_net.ipv6.frags.high_thresh;
458
- table[1].data = &net->ipv6.frags.low_thresh;
459
- table[1].extra2 = &net->ipv6.frags.high_thresh;
460
- table[2].data = &net->ipv6.frags.timeout;
461460 }
461
+ table[0].data = &net->ipv6.fqdir->high_thresh;
462
+ table[0].extra1 = &net->ipv6.fqdir->low_thresh;
463
+ table[1].data = &net->ipv6.fqdir->low_thresh;
464
+ table[1].extra2 = &net->ipv6.fqdir->high_thresh;
465
+ table[2].data = &net->ipv6.fqdir->timeout;
462466
463467 hdr = register_net_sysctl(net, "net/ipv6", table);
464468 if (!hdr)
....@@ -521,30 +525,35 @@
521525 {
522526 int res;
523527
524
- net->ipv6.frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
525
- net->ipv6.frags.low_thresh = IPV6_FRAG_LOW_THRESH;
526
- net->ipv6.frags.timeout = IPV6_FRAG_TIMEOUT;
527
- net->ipv6.frags.f = &ip6_frags;
528
-
529
- res = inet_frags_init_net(&net->ipv6.frags);
528
+ res = fqdir_init(&net->ipv6.fqdir, &ip6_frags, net);
530529 if (res < 0)
531530 return res;
532531
532
+ net->ipv6.fqdir->high_thresh = IPV6_FRAG_HIGH_THRESH;
533
+ net->ipv6.fqdir->low_thresh = IPV6_FRAG_LOW_THRESH;
534
+ net->ipv6.fqdir->timeout = IPV6_FRAG_TIMEOUT;
535
+
533536 res = ip6_frags_ns_sysctl_register(net);
534537 if (res < 0)
535
- inet_frags_exit_net(&net->ipv6.frags);
538
+ fqdir_exit(net->ipv6.fqdir);
536539 return res;
540
+}
541
+
542
+static void __net_exit ipv6_frags_pre_exit_net(struct net *net)
543
+{
544
+ fqdir_pre_exit(net->ipv6.fqdir);
537545 }
538546
539547 static void __net_exit ipv6_frags_exit_net(struct net *net)
540548 {
541549 ip6_frags_ns_sysctl_unregister(net);
542
- inet_frags_exit_net(&net->ipv6.frags);
550
+ fqdir_exit(net->ipv6.fqdir);
543551 }
544552
545553 static struct pernet_operations ip6_frags_ops = {
546
- .init = ipv6_frags_init_net,
547
- .exit = ipv6_frags_exit_net,
554
+ .init = ipv6_frags_init_net,
555
+ .pre_exit = ipv6_frags_pre_exit_net,
556
+ .exit = ipv6_frags_exit_net,
548557 };
549558
550559 static const struct rhashtable_params ip6_rhash_params = {