diff options
Diffstat (limited to 'usr.sbin/bgpd')
-rw-r--r-- | usr.sbin/bgpd/rde.c | 108 |
1 files changed, 56 insertions, 52 deletions
diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c index 682b616e209..a4f8e169345 100644 --- a/usr.sbin/bgpd/rde.c +++ b/usr.sbin/bgpd/rde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.216 2007/01/04 12:43:36 claudio Exp $ */ +/* $OpenBSD: rde.c,v 1.217 2007/01/24 13:24:51 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -676,7 +676,7 @@ rde_update_dispatch(struct imsg *imsg) struct rde_peer *peer; struct rde_aspath *asp = NULL, *fasp; u_char *p, *mpp = NULL; - int pos = 0; + int error = -1, pos = 0; u_int16_t afi, len, mplen; u_int16_t withdrawn_len; u_int16_t attrpath_len; @@ -720,10 +720,8 @@ rde_update_dispatch(struct imsg *imsg) asp = path_get(); while (len > 0) { if ((pos = rde_attr_parse(p, len, peer, asp, - &mpa)) < 0) { - path_put(asp); - return (-1); - } + &mpa)) < 0) + goto done; p += pos; len -= pos; } @@ -733,8 +731,7 @@ rde_update_dispatch(struct imsg *imsg) nlri_len))) { rde_update_err(peer, ERR_UPDATE, ERR_UPD_MISSNG_WK_ATTR, &subtype, sizeof(u_int8_t)); - path_put(asp); - return (-1); + goto done; } /* enforce remote AS if requested */ @@ -744,13 +741,12 @@ rde_update_dispatch(struct imsg *imsg) aspath_neighbor(asp->aspath)) { rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH, NULL, 0); - path_put(asp); - return (-1); + goto done; } if (rde_reflector(peer, asp) != 1) { - path_put(asp); - return (0); + error = 0; + goto done; } } @@ -768,17 +764,13 @@ rde_update_dispatch(struct imsg *imsg) log_peer_warnx(&peer->conf, "bad withdraw prefix"); rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK, NULL, 0); - if (attrpath_len != 0) - path_put(asp); - return (-1); + goto done; } if (prefixlen > 32) { log_peer_warnx(&peer->conf, "bad withdraw prefix"); rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK, NULL, 0); - if (attrpath_len != 0) - path_put(asp); - return (-1); + goto done; } p += pos; @@ -789,9 +781,7 @@ rde_update_dispatch(struct imsg *imsg) log_peer_warnx(&peer->conf, "bad AFI, IPv4 disabled"); rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR, NULL, 0); - if (attrpath_len != 0) - path_put(asp); - return (-1); + goto done; } rde_update_log("withdraw", peer, NULL, &prefix, prefixlen); @@ -819,8 +809,7 @@ rde_update_dispatch(struct imsg *imsg) "IPv6 disabled"); rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR, NULL, 0); - path_put(asp); - return (-1); + goto done; } while (mplen > 0) { if ((pos = rde_update_get_prefix6(mpp, mplen, @@ -830,8 +819,7 @@ rde_update_dispatch(struct imsg *imsg) rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR, mpa.unreach, mpa.unreach_len); - path_put(asp); - return (-1); + goto done; } if (prefixlen > 128) { log_peer_warnx(&peer->conf, @@ -839,8 +827,7 @@ rde_update_dispatch(struct imsg *imsg) rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR, mpa.unreach, mpa.unreach_len); - path_put(asp); - return (-1); + goto done; } mpp += pos; @@ -860,8 +847,8 @@ rde_update_dispatch(struct imsg *imsg) } if ((asp->flags & ~F_ATTR_MP_UNREACH) == 0) { - path_put(asp); - return (0); + error = 0; + goto done; } } @@ -870,8 +857,8 @@ rde_update_dispatch(struct imsg *imsg) /* aspath needs to be loop free nota bene this is not a hard error */ if (peer->conf.ebgp && !aspath_loopfree(asp->aspath, conf->as)) { - path_put(asp); - return (0); + error = 0; + goto done; } /* parse nlri prefix */ @@ -881,15 +868,13 @@ rde_update_dispatch(struct imsg *imsg) log_peer_warnx(&peer->conf, "bad nlri prefix"); rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK, NULL, 0); - path_put(asp); - return (-1); + goto done; } if (prefixlen > 32) { log_peer_warnx(&peer->conf, "bad nlri prefix"); rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK, NULL, 0); - path_put(asp); - return (-1); + goto done; } p += pos; @@ -900,8 +885,7 @@ rde_update_dispatch(struct imsg *imsg) log_peer_warnx(&peer->conf, "bad AFI, IPv4 disabled"); rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR, NULL, 0); - path_put(asp); - return (-1); + goto done; } /* add original path to the Adj-RIB-In */ @@ -921,9 +905,8 @@ rde_update_dispatch(struct imsg *imsg) log_peer_warnx(&peer->conf, "prefix limit reached"); rde_update_err(peer, ERR_CEASE, ERR_CEASE_MAX_PREFIX, NULL, 0); - path_put(asp); path_put(fasp); - return (-1); + goto done; } if (fasp == NULL) @@ -951,13 +934,18 @@ rde_update_dispatch(struct imsg *imsg) /* * this works because asp is not linked. + * But first unlock the previously locked nexthop. */ + if (asp->nexthop) { + asp->nexthop->refcnt--; + (void)nexthop_delete(asp->nexthop); + asp->nexthop = NULL; + } if ((pos = rde_get_mp_nexthop(mpp, mplen, afi, asp)) == -1) { log_peer_warnx(&peer->conf, "bad IPv6 nlri prefix"); rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR, mpa.reach, mpa.reach_len); - path_put(asp); - return (-1); + goto done; } mpp += pos; mplen -= pos; @@ -969,8 +957,7 @@ rde_update_dispatch(struct imsg *imsg) "IPv6 disabled"); rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR, NULL, 0); - path_put(asp); - return (-1); + goto done; } while (mplen > 0) { @@ -981,15 +968,13 @@ rde_update_dispatch(struct imsg *imsg) rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR, mpa.reach, mpa.reach_len); - path_put(asp); - return (-1); + goto done; } if (prefixlen > 128) { rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR, mpa.reach, mpa.reach_len); - path_put(asp); - return (-1); + goto done; } mpp += pos; @@ -1015,9 +1000,8 @@ rde_update_dispatch(struct imsg *imsg) "prefix limit reached"); rde_update_err(peer, ERR_CEASE, ERR_CEASE_MAX_PREFIX, NULL, 0); - path_put(asp); path_put(fasp); - return (-1); + goto done; } if (fasp == NULL) @@ -1040,10 +1024,18 @@ rde_update_dispatch(struct imsg *imsg) } } - /* need to free allocated attribute memory that is no longer used */ - path_put(asp); +done: + if (attrpath_len != 0) { + /* unlock the previously locked entry */ + if (asp->nexthop) { + asp->nexthop->refcnt--; + (void)nexthop_delete(asp->nexthop); + } + /* free allocated attribute memory that is no longer used */ + path_put(asp); + } - return (0); + return (error); } /* @@ -1161,6 +1153,12 @@ bad_flags: return (-1); } a->nexthop = nexthop_get(&nexthop); + /* + * lock the nexthop because it is not yet linked else + * withdraws may remove this nexthop which in turn would + * cause a use after free error. + */ + a->nexthop->refcnt++; break; case ATTR_MED: if (attr_len != 4) @@ -1329,6 +1327,12 @@ rde_get_mp_nexthop(u_char *data, u_int16_t len, u_int16_t afi, nexthop.af = AF_INET6; memcpy(&nexthop.v6.s6_addr, data, 16); asp->nexthop = nexthop_get(&nexthop); + /* + * lock the nexthop because it is not yet linked else + * withdraws may remove this nexthop which in turn would + * cause a use after free error. + */ + asp->nexthop->refcnt++; totlen += nhlen; data += nhlen; |