diff options
author | Can Erkin Acar <canacar@cvs.openbsd.org> | 2006-08-28 10:50:14 +0000 |
---|---|---|
committer | Can Erkin Acar <canacar@cvs.openbsd.org> | 2006-08-28 10:50:14 +0000 |
commit | 49f43d9e859853c750edb2399c832c876ef58cb9 (patch) | |
tree | f9c363cf1a7055b30c00821ca834b4d01684a5a1 /sys | |
parent | 37bc495bb58a26309b2fa69ed1d0a21aa98cc76a (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.c | 61 |
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 |