summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/inet/ip/ip.c33
-rw-r--r--usr/src/uts/common/inet/ip/ip6.c7
-rw-r--r--usr/src/uts/common/os/ip_cksum.c8
3 files changed, 35 insertions, 13 deletions
diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c
index 4a771a8256..0f6ac91ce6 100644
--- a/usr/src/uts/common/inet/ip/ip.c
+++ b/usr/src/uts/common/inet/ip/ip.c
@@ -24,8 +24,8 @@
* Copyright (c) 1990 Mentat Inc.
* Copyright (c) 2017 OmniTI Computer Consulting, Inc. All rights reserved.
* Copyright (c) 2016 by Delphix. All rights reserved.
- * Copyright (c) 2019 Joyent, Inc. All rights reserved.
* Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2021 Joyent, Inc.
*/
#include <sys/types.h>
@@ -2845,6 +2845,20 @@ icmp_pkt(mblk_t *mp, void *stuff, size_t len, ip_recv_attr_t *ira)
len_needed = IPH_HDR_LENGTH(ipha);
if (ipha->ipha_protocol == IPPROTO_ENCAP ||
ipha->ipha_protocol == IPPROTO_IPV6) {
+ /*
+ * NOTE: It is posssible that the inner packet is poorly
+ * formed (e.g. IP version is corrupt, or v6 extension headers
+ * got cut off). The receiver of the ICMP message should see
+ * what we saw. In the absence of a sane inner-packet (which
+ * protocol types IPPPROTO_ENCAP and IPPROTO_IPV6 indicate
+ * would be an IP header), we should send the size of what is
+ * normally expected to be there (either sizeof (ipha_t) or
+ * sizeof (ip6_t). It may be useful for diagnostic purposes.
+ *
+ * ALSO NOTE: "inner_ip6h" is the inner packet header, v4 or v6.
+ */
+ ip6_t *inner_ip6h = (ip6_t *)((uchar_t *)ipha + len_needed);
+
if (!pullupmsg(mp, -1)) {
BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsOutDiscards);
ip_drop_output("ipIfStatsOutDiscards", mp, NULL);
@@ -2854,13 +2868,20 @@ icmp_pkt(mblk_t *mp, void *stuff, size_t len, ip_recv_attr_t *ira)
ipha = (ipha_t *)mp->b_rptr;
if (ipha->ipha_protocol == IPPROTO_ENCAP) {
- len_needed += IPH_HDR_LENGTH(((uchar_t *)ipha +
- len_needed));
+ /*
+ * Check the inner IP version here to guard against
+ * bogons.
+ */
+ if (IPH_HDR_VERSION(inner_ip6h) == IPV4_VERSION) {
+ len_needed +=
+ IPH_HDR_LENGTH(((uchar_t *)inner_ip6h));
+ } else {
+ len_needed = sizeof (ipha_t);
+ }
} else {
- ip6_t *ip6h = (ip6_t *)((uchar_t *)ipha + len_needed);
-
ASSERT(ipha->ipha_protocol == IPPROTO_IPV6);
- len_needed += ip_hdr_length_v6(mp, ip6h);
+ /* function called next-line checks inner IP version */
+ len_needed += ip_hdr_length_v6(mp, inner_ip6h);
}
}
len_needed += ipst->ips_ip_icmp_return;
diff --git a/usr/src/uts/common/inet/ip/ip6.c b/usr/src/uts/common/inet/ip/ip6.c
index 26e7be2fe8..15ca8adbaa 100644
--- a/usr/src/uts/common/inet/ip/ip6.c
+++ b/usr/src/uts/common/inet/ip/ip6.c
@@ -22,7 +22,7 @@
* Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1990 Mentat Inc.
* Copyright 2017 OmniTI Computer Consulting, Inc. All rights reserved.
- * Copyright 2019 Joyent, Inc.
+ * Copyright 2021 Joyent, Inc.
*/
#include <sys/types.h>
@@ -2732,14 +2732,15 @@ done:
/*
* Return the length of the IPv6 related headers (including extension headers)
- * Returns a length even if the packet is malformed.
+ * If the packet is malformed, this returns the simple IPv6 header length.
*/
uint16_t
ip_hdr_length_v6(mblk_t *mp, ip6_t *ip6h)
{
uint16_t hdr_len;
- (void) ip_hdr_length_nexthdr_v6(mp, ip6h, &hdr_len, NULL);
+ if (!ip_hdr_length_nexthdr_v6(mp, ip6h, &hdr_len, NULL))
+ hdr_len = sizeof (*ip6h);
return (hdr_len);
}
diff --git a/usr/src/uts/common/os/ip_cksum.c b/usr/src/uts/common/os/ip_cksum.c
index 0a237e86ec..51a93dfa24 100644
--- a/usr/src/uts/common/os/ip_cksum.c
+++ b/usr/src/uts/common/os/ip_cksum.c
@@ -21,7 +21,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2019 Joyent, Inc.
+ * Copyright 2021 Joyent, Inc.
*/
/* Copyright (c) 1990 Mentat Inc. */
@@ -40,8 +40,7 @@
#include <sys/multidata.h>
#include <sys/multidata_impl.h>
-extern unsigned int ip_ocsum(ushort_t *address, int halfword_count,
- unsigned int sum);
+extern unsigned int ip_ocsum(ushort_t *, int, unsigned int);
/*
* Checksum routine for Internet Protocol family headers.
@@ -587,7 +586,8 @@ ip_hdr_length_nexthdr_v6(mblk_t *mp, ip6_t *ip6h, uint16_t *hdr_length_ptr,
ip6_rthdr_t *rthdr;
ip6_frag_t *fraghdr;
- ASSERT(IPH_HDR_VERSION(ip6h) == IPV6_VERSION);
+ if (IPH_HDR_VERSION(ip6h) != IPV6_VERSION)
+ return (B_FALSE);
length = IPV6_HDR_LEN;
whereptr = ((uint8_t *)&ip6h[1]); /* point to next hdr */
endptr = mp->b_wptr;