aboutsummaryrefslogtreecommitdiffstats
path: root/include/net
diff options
context:
space:
mode:
authorTom Herbert <tom@quantonium.net>2017-10-30 17:16:00 -0400
committerDavid S. Miller <davem@davemloft.net>2017-11-02 20:50:22 -0400
commit47d3d7ac656a1ffb9d0f0d3c845663ed6fd7e78d (patch)
treeadb397853601ba03f23c3735b3addb496319706d /include/net
parent2d2faaf0568b4946d9abeb4e541227b4ca259840 (diff)
ipv6: Implement limits on Hop-by-Hop and Destination options
RFC 8200 (IPv6) defines Hop-by-Hop options and Destination options extension headers. Both of these carry a list of TLVs which is only limited by the maximum length of the extension header (2048 bytes). By the spec a host must process all the TLVs in these options, however these could be used as a fairly obvious denial of service attack. I think this could in fact be a significant DOS vector on the Internet, one mitigating factor might be that many FWs drop all packets with EH (and obviously this is only IPv6) so an Internet wide attack might not be so effective (yet!). By my calculation, the worse case packet with TLVs in a standard 1500 byte MTU packet that would be processed by the stack contains 1282 invidual TLVs (including pad TLVS) or 724 two byte TLVs. I wrote a quick test program that floods a whole bunch of these packets to a host and sure enough there is substantial time spent in ip6_parse_tlv. These packets contain nothing but unknown TLVS (that are ignored), TLV padding, and bogus UDP header with zero payload length. 25.38% [kernel] [k] __fib6_clean_all 21.63% [kernel] [k] ip6_parse_tlv 4.21% [kernel] [k] __local_bh_enable_ip 2.18% [kernel] [k] ip6_pol_route.isra.39 1.98% [kernel] [k] fib6_walk_continue 1.88% [kernel] [k] _raw_write_lock_bh 1.65% [kernel] [k] dst_release This patch adds configurable limits to Destination and Hop-by-Hop options. There are three limits that may be set: - Limit the number of options in a Hop-by-Hop or Destination options extension header. - Limit the byte length of a Hop-by-Hop or Destination options extension header. - Disallow unrecognized options in a Hop-by-Hop or Destination options extension header. The limits are set in corresponding sysctls: ipv6.sysctl.max_dst_opts_cnt ipv6.sysctl.max_hbh_opts_cnt ipv6.sysctl.max_dst_opts_len ipv6.sysctl.max_hbh_opts_len If a max_*_opts_cnt is less than zero then unknown TLVs are disallowed. The number of known TLVs that are allowed is the absolute value of this number. If a limit is exceeded when processing an extension header the packet is dropped. Default values are set to 8 for options counts, and set to INT_MAX for maximum length. Note the choice to limit options to 8 is an arbitrary guess (roughly based on the fact that the stack supports three HBH options and just one destination option). These limits have being proposed in draft-ietf-6man-rfc6434-bis. Tested (by Martin Lau) I tested out 1 thread (i.e. one raw_udp process). I changed the net.ipv6.max_dst_(opts|hbh)_number between 8 to 2048. With sysctls setting to 2048, the softirq% is packed to 100%. With 8, the softirq% is almost unnoticable from mpstat. v2; - Code and documention cleanup. - Change references of RFC2460 to be RFC8200. - Add reference to RFC6434-bis where the limits will be in standard. Signed-off-by: Tom Herbert <tom@quantonium.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/net')
-rw-r--r--include/net/ipv6.h40
-rw-r--r--include/net/netns/ipv6.h4
2 files changed, 44 insertions, 0 deletions
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 3cda3b521c36..fb6d67012de6 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -51,6 +51,46 @@
51#define IPV6_DEFAULT_HOPLIMIT 64 51#define IPV6_DEFAULT_HOPLIMIT 64
52#define IPV6_DEFAULT_MCASTHOPS 1 52#define IPV6_DEFAULT_MCASTHOPS 1
53 53
54/* Limits on Hop-by-Hop and Destination options.
55 *
56 * Per RFC8200 there is no limit on the maximum number or lengths of options in
57 * Hop-by-Hop or Destination options other then the packet must fit in an MTU.
58 * We allow configurable limits in order to mitigate potential denial of
59 * service attacks.
60 *
61 * There are three limits that may be set:
62 * - Limit the number of options in a Hop-by-Hop or Destination options
63 * extension header
64 * - Limit the byte length of a Hop-by-Hop or Destination options extension
65 * header
66 * - Disallow unknown options
67 *
68 * The limits are expressed in corresponding sysctls:
69 *
70 * ipv6.sysctl.max_dst_opts_cnt
71 * ipv6.sysctl.max_hbh_opts_cnt
72 * ipv6.sysctl.max_dst_opts_len
73 * ipv6.sysctl.max_hbh_opts_len
74 *
75 * max_*_opts_cnt is the number of TLVs that are allowed for Destination
76 * options or Hop-by-Hop options. If the number is less than zero then unknown
77 * TLVs are disallowed and the number of known options that are allowed is the
78 * absolute value. Setting the value to INT_MAX indicates no limit.
79 *
80 * max_*_opts_len is the length limit in bytes of a Destination or
81 * Hop-by-Hop options extension header. Setting the value to INT_MAX
82 * indicates no length limit.
83 *
84 * If a limit is exceeded when processing an extension header the packet is
85 * silently discarded.
86 */
87
88/* Default limits for Hop-by-Hop and Destination options */
89#define IP6_DEFAULT_MAX_DST_OPTS_CNT 8
90#define IP6_DEFAULT_MAX_HBH_OPTS_CNT 8
91#define IP6_DEFAULT_MAX_DST_OPTS_LEN INT_MAX /* No limit */
92#define IP6_DEFAULT_MAX_HBH_OPTS_LEN INT_MAX /* No limit */
93
54/* 94/*
55 * Addr type 95 * Addr type
56 * 96 *
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index 2ea1ed341ef8..600ba1c1befc 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -37,6 +37,10 @@ struct netns_sysctl_ipv6 {
37 int idgen_delay; 37 int idgen_delay;
38 int flowlabel_state_ranges; 38 int flowlabel_state_ranges;
39 int flowlabel_reflect; 39 int flowlabel_reflect;
40 int max_dst_opts_cnt;
41 int max_hbh_opts_cnt;
42 int max_dst_opts_len;
43 int max_hbh_opts_len;
40}; 44};
41 45
42struct netns_ipv6 { 46struct netns_ipv6 {