summaryrefslogtreecommitdiffstats
path: root/sys/netinet6
diff options
context:
space:
mode:
authorkris <kris@FreeBSD.org>2001-02-26 03:41:13 +0000
committerkris <kris@FreeBSD.org>2001-02-26 03:41:13 +0000
commitf13b6fe378f977bb101bdefab5288f0ba5ebf18b (patch)
treed316f4cc8646f50e64e2674752d10e9b69041c42 /sys/netinet6
parenta7a408f67ff21a3e24c002cf0007bde818da83fc (diff)
downloadFreeBSD-src-f13b6fe378f977bb101bdefab5288f0ba5ebf18b.zip
FreeBSD-src-f13b6fe378f977bb101bdefab5288f0ba5ebf18b.tar.gz
More IP option length validation.
Includes the following revisions from KAME (two of these were actually committed previously but the CVS revisions weren't documented): 1.40 kame/kame/sys/netinet6/ah_core.c (committed in previous rev) 1.41 kame/kame/sys/netinet6/ah_core.c 1.28 kame/kame/sys/netinet6/ah_output.c (committed in previous rev) 1.29 kame/kame/sys/netinet6/ah_output.c 1.30 kame/kame/sys/netinet6/ah_output.c 1.129 kame/kame/sys/netinet6/nd6.c 1.130 kame/kame/sys/netinet6/nd6.c 1.24 kame/kame/sys/netinet6/dest6.c 1.25 kame/kame/sys/netinet6/dest6.c Obtained from: KAME
Diffstat (limited to 'sys/netinet6')
-rw-r--r--sys/netinet6/ah_core.c13
-rw-r--r--sys/netinet6/ah_output.c8
-rw-r--r--sys/netinet6/dest6.c28
-rw-r--r--sys/netinet6/nd6.c13
4 files changed, 41 insertions, 21 deletions
diff --git a/sys/netinet6/ah_core.c b/sys/netinet6/ah_core.c
index 92481db..477de51 100644
--- a/sys/netinet6/ah_core.c
+++ b/sys/netinet6/ah_core.c
@@ -788,6 +788,8 @@ again:
i = sizeof(struct ip);
while (i < hlen) {
if (i + IPOPT_OPTVAL >= hlen) {
+ ipseclog((LOG_ERR, "ah4_calccksum: "
+ "invalid IP option\n"));
error = EINVAL;
goto fail;
}
@@ -796,6 +798,10 @@ again:
i + IPOPT_OLEN < hlen)
;
else {
+ ipseclog((LOG_ERR,
+ "ah4_calccksum: invalid IP option "
+ "(type=%02x)\n",
+ p[i + IPOPT_OPTVAL]));
error = EINVAL;
goto fail;
}
@@ -813,14 +819,19 @@ again:
case 0x94: /* Router alert */
case 0x95: /* RFC1770 */
l = p[i + IPOPT_OLEN];
+ if (l < 2)
+ goto invalopt;
skip = 0;
break;
default:
l = p[i + IPOPT_OLEN];
+ if (l < 2)
+ goto invalopt;
skip = 1;
break;
}
- if (l <= 0 || hlen - i < l) {
+ if (l < 1 || hlen - i < l) {
+ invalopt:
ipseclog((LOG_ERR,
"ah4_calccksum: invalid IP option "
"(type=%02x len=%02x)\n",
diff --git a/sys/netinet6/ah_output.c b/sys/netinet6/ah_output.c
index df9f4d5..59263cd 100644
--- a/sys/netinet6/ah_output.c
+++ b/sys/netinet6/ah_output.c
@@ -539,8 +539,8 @@ ah4_finaldst(m)
break;
case IPOPT_LSRR:
case IPOPT_SSRR:
- if (q[i + IPOPT_OLEN] <= 0
- || optlen - i < q[i + IPOPT_OLEN]) {
+ if (q[i + IPOPT_OLEN] < 2 + sizeof(struct in_addr) ||
+ optlen - i < q[i + IPOPT_OLEN]) {
ipseclog((LOG_ERR,
"ip_finaldst: invalid IP option "
"(code=%02x len=%02x)\n",
@@ -550,8 +550,8 @@ ah4_finaldst(m)
i += q[i + IPOPT_OLEN] - sizeof(struct in_addr);
return (struct in_addr *)(q + i);
default:
- if (q[i + IPOPT_OLEN] <= 0
- || optlen - i < q[i + IPOPT_OLEN]) {
+ if (q[i + IPOPT_OLEN] < 2 ||
+ optlen - i < q[i + IPOPT_OLEN]) {
ipseclog((LOG_ERR,
"ip_finaldst: invalid IP option "
"(code=%02x len=%02x)\n",
diff --git a/sys/netinet6/dest6.c b/sys/netinet6/dest6.c
index 268d8c9..8d3987c 100644
--- a/sys/netinet6/dest6.c
+++ b/sys/netinet6/dest6.c
@@ -89,22 +89,20 @@ dest6_input(mp, offp, proto)
/* search header for all options. */
for (optlen = 0; dstoptlen > 0; dstoptlen -= optlen, opt += optlen) {
- switch(*opt) {
- case IP6OPT_PAD1:
- optlen = 1;
- break;
- case IP6OPT_PADN:
- if (dstoptlen < IP6OPT_MINLEN) {
- ip6stat.ip6s_toosmall++;
- goto bad;
- }
- optlen = *(opt + 1) + 2;
- break;
+ if (*opt != IP6OPT_PAD1 &&
+ (dstoptlen < IP6OPT_MINLEN || *(opt + 1) + 2 > dstoptlen)) {
+ ip6stat.ip6s_toosmall++;
+ goto bad;
+ }
+
+ switch (*opt) {
+ case IP6OPT_PAD1:
+ optlen = 1;
+ break;
+ case IP6OPT_PADN:
+ optlen = *(opt + 1) + 2;
+ break;
default: /* unknown option */
- if (dstoptlen < IP6OPT_MINLEN) {
- ip6stat.ip6s_toosmall++;
- goto bad;
- }
if ((optlen = ip6_unknown_opt(opt, m,
opt-mtod(m, u_int8_t *))) == -1)
return(IPPROTO_DONE);
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index 4298ce2..a4ddfa1 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -274,6 +274,12 @@ nd6_option(ndopts)
nd_opt = ndopts->nd_opts_search;
+ /* make sure nd_opt_len is inside the buffer */
+ if ((caddr_t)&nd_opt->nd_opt_len >= (caddr_t)ndopts->nd_opts_last) {
+ bzero(ndopts, sizeof(*ndopts));
+ return NULL;
+ }
+
olen = nd_opt->nd_opt_len << 3;
if (olen == 0) {
/*
@@ -285,7 +291,12 @@ nd6_option(ndopts)
}
ndopts->nd_opts_search = (struct nd_opt_hdr *)((caddr_t)nd_opt + olen);
- if (!(ndopts->nd_opts_search < ndopts->nd_opts_last)) {
+ if (ndopts->nd_opts_search > ndopts->nd_opts_last) {
+ /* option overruns the end of buffer, invalid */
+ bzero(ndopts, sizeof(*ndopts));
+ return NULL;
+ } else if (ndopts->nd_opts_search == ndopts->nd_opts_last) {
+ /* reached the end of options chain */
ndopts->nd_opts_done = 1;
ndopts->nd_opts_search = NULL;
}
OpenPOWER on IntegriCloud