summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorCan Erkin Acar <canacar@cvs.openbsd.org>2006-08-28 10:50:14 +0000
committerCan Erkin Acar <canacar@cvs.openbsd.org>2006-08-28 10:50:14 +0000
commit49f43d9e859853c750edb2399c832c876ef58cb9 (patch)
treef9c363cf1a7055b30c00821ca834b4d01684a5a1 /sys
parent37bc495bb58a26309b2fa69ed1d0a21aa98cc76a (diff)
Check for illegal option lengths when parsing LCP packets
and drop such bad packets. Also remove some redundant mallocs. This fixes possible heap overflows when forming replys to such bad packets as discovered by Martin Husemann and Pavel Cahyna. reported by NetBSD, initial diff from markus@, additional comments by claudio@, ok markus@
Diffstat (limited to 'sys')
-rw-r--r--sys/net/if_spppsubr.c61
1 files changed, 30 insertions, 31 deletions
diff --git a/sys/net/if_spppsubr.c b/sys/net/if_spppsubr.c
index 0a4687090a3..b104842f138 100644
--- a/sys/net/if_spppsubr.c
+++ b/sys/net/if_spppsubr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_spppsubr.c,v 1.42 2006/07/11 21:36:51 canacar Exp $ */
+/* $OpenBSD: if_spppsubr.c,v 1.43 2006/08/28 10:50:13 canacar Exp $ */
/*
* Synchronous PPP/Cisco link level subroutines.
* Keepalive protocol implemented in both Cisco and PPP modes.
@@ -1317,6 +1317,9 @@ sppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m)
return;
}
rv = (cp->RCR)(sp, h, len);
+ /* silently drop illegal packets */
+ if (rv == -1)
+ return;
switch (sp->state[cp->protoidx]) {
case STATE_OPENED:
sppp_cp_change_state(cp, sp, rv?
@@ -2045,7 +2048,11 @@ sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
/* pass 1: check for things that need to be rejected */
p = (void*) (h+1);
- for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
+ for (rlen = 0; len > 1; len -= p[1], p += p[1]) {
+ if (p[1] < 2 || p[1] > len) {
+ free(buf, M_TEMP);
+ return (-1);
+ }
if (debug)
addlog("%s ", sppp_lcp_opt_name(*p));
switch (*p) {
@@ -2232,19 +2239,18 @@ HIDE void
sppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
{
STDDCL;
- u_char *buf, *p;
+ u_char *p;
len -= 4;
- buf = malloc (len, M_TEMP, M_NOWAIT);
- if (!buf)
- return;
if (debug)
log(LOG_DEBUG, SPP_FMT "lcp rej opts: ",
SPP_ARGS(ifp));
p = (void*) (h+1);
- for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
+ for (; len > 1; len -= p[1], p += p[1]) {
+ if (p[1] < 2 || p[1] > len)
+ return;
if (debug)
addlog("%s ", sppp_lcp_opt_name(*p));
switch (*p) {
@@ -2283,8 +2289,6 @@ sppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
}
if (debug)
addlog("\n");
- free (buf, M_TEMP);
- return;
}
/*
@@ -2295,20 +2299,19 @@ HIDE void
sppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
{
STDDCL;
- u_char *buf, *p;
+ u_char *p;
u_long magic;
len -= 4;
- buf = malloc (len, M_TEMP, M_NOWAIT);
- if (!buf)
- return;
if (debug)
log(LOG_DEBUG, SPP_FMT "lcp nak opts: ",
SPP_ARGS(ifp));
p = (void*) (h+1);
- for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
+ for (; len > 1; len -= p[1], p += p[1]) {
+ if (p[1] < 2 || p[1] > len)
+ return;
if (debug)
addlog("%s ", sppp_lcp_opt_name(*p));
switch (*p) {
@@ -2363,8 +2366,6 @@ sppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
}
if (debug)
addlog("\n");
- free (buf, M_TEMP);
- return;
}
HIDE void
@@ -2657,7 +2658,11 @@ sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
log(LOG_DEBUG, SPP_FMT "ipcp parse opts: ",
SPP_ARGS(ifp));
p = (void*) (h+1);
- for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
+ for (rlen = 0; len > 1; len -= p[1], p += p[1]) {
+ if (p[1] < 2 || p[1] > len) {
+ free(buf, M_TEMP);
+ return (-1);
+ }
if (debug)
addlog("%s ", sppp_ipcp_opt_name(*p));
switch (*p) {
@@ -2804,21 +2809,20 @@ sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
HIDE void
sppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
{
- u_char *buf, *p;
+ u_char *p;
struct ifnet *ifp = &sp->pp_if;
int debug = ifp->if_flags & IFF_DEBUG;
len -= 4;
- buf = malloc (len, M_TEMP, M_NOWAIT);
- if (!buf)
- return;
if (debug)
log(LOG_DEBUG, SPP_FMT "ipcp rej opts: ",
SPP_ARGS(ifp));
p = (void*) (h+1);
- for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
+ for (; len > 1; len -= p[1], p += p[1]) {
+ if (p[1] < 2 || p[1] > len)
+ return;
if (debug)
addlog("%s ", sppp_ipcp_opt_name(*p));
switch (*p) {
@@ -2838,8 +2842,6 @@ sppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
}
if (debug)
addlog("\n");
- free (buf, M_TEMP);
- return;
}
/*
@@ -2849,22 +2851,21 @@ sppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len)
HIDE void
sppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
{
- u_char *buf, *p;
+ u_char *p;
struct ifnet *ifp = &sp->pp_if;
int debug = ifp->if_flags & IFF_DEBUG;
u_long wantaddr;
len -= 4;
- buf = malloc (len, M_TEMP, M_NOWAIT);
- if (!buf)
- return;
if (debug)
log(LOG_DEBUG, SPP_FMT "ipcp nak opts: ",
SPP_ARGS(ifp));
p = (void*) (h+1);
- for (; len > 1 && p[1]; len -= p[1], p += p[1]) {
+ for (; len > 1; len -= p[1], p += p[1]) {
+ if (p[1] < 2 || p[1] > len)
+ return;
if (debug)
addlog("%s ", sppp_ipcp_opt_name(*p));
switch (*p) {
@@ -2905,8 +2906,6 @@ sppp_ipcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len)
}
if (debug)
addlog("\n");
- free (buf, M_TEMP);
- return;
}
HIDE void