diff options
author | kris <kris@FreeBSD.org> | 2001-02-26 03:41:13 +0000 |
---|---|---|
committer | kris <kris@FreeBSD.org> | 2001-02-26 03:41:13 +0000 |
commit | f13b6fe378f977bb101bdefab5288f0ba5ebf18b (patch) | |
tree | d316f4cc8646f50e64e2674752d10e9b69041c42 /sys/netinet6 | |
parent | a7a408f67ff21a3e24c002cf0007bde818da83fc (diff) | |
download | FreeBSD-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.c | 13 | ||||
-rw-r--r-- | sys/netinet6/ah_output.c | 8 | ||||
-rw-r--r-- | sys/netinet6/dest6.c | 28 | ||||
-rw-r--r-- | sys/netinet6/nd6.c | 13 |
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; } |