From ab164971891c64126097eedca11d2f5586f1d8e7 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Tue, 29 Mar 2011 01:41:46 +0200 Subject: [PATCH] Fixes a nasty bug in OSPF. Sending malformed network prefixes in LSAs causes OSPF to crash just after the LSA is propagated to the other routers. --- nest/rt-table.c | 2 +- proto/ospf/ospf.h | 4 ++++ proto/ospf/packet.c | 7 ++++--- proto/ospf/rt.c | 49 +++++++++++++++++++++++++++++++++------------ 4 files changed, 45 insertions(+), 17 deletions(-) diff --git a/nest/rt-table.c b/nest/rt-table.c index 73b05d08..3013b0f7 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -374,7 +374,7 @@ rte_validate(rte *e) if ((n->n.pxlen > BITS_PER_IP_ADDRESS) || !ip_is_prefix(n->n.prefix,n->n.pxlen)) { - log(L_BUG "Ignoring bogus prefix %I/%d received via %s", + log(L_WARN "Ignoring bogus prefix %I/%d received via %s", n->n.prefix, n->n.pxlen, e->sender->name); return 0; } diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index 74a8e316..664bc48f 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -587,6 +587,10 @@ lsa_get_ipv6_prefix(u32 *buf, ip_addr *addr, int *pxlen, u8 *pxopts, u16 *rest) if (pxl > 96) _I3(*addr) = *buf++; + /* Clean up remaining bits */ + if (pxl < 128) + addr->addr[pxl / 32] &= u32_mkmask(pxl % 32); + return buf; } diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index ae9f862a..3cda3845 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -269,9 +269,10 @@ ospf_rx_hook(sock *sk, int size) struct proto_ospf *po = ifa->oa->po; // struct proto *p = &po->proto; - int src_local = ipa_in_net(sk->faddr, ifa->addr->prefix, ifa->addr->pxlen); - int dst_local = ipa_equal(sk->laddr, ifa->addr->ip); - int dst_mcast = ipa_equal(sk->laddr, AllSPFRouters) || ipa_equal(sk->laddr, AllDRouters); + int src_local, dst_local UNUSED, dst_mcast; + src_local = ipa_in_net(sk->faddr, ifa->addr->prefix, ifa->addr->pxlen); + dst_local = ipa_equal(sk->laddr, ifa->addr->ip); + dst_mcast = ipa_equal(sk->laddr, AllSPFRouters) || ipa_equal(sk->laddr, AllDRouters); #ifdef OSPFv2 /* First, we eliminate packets with strange address combinations. diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 2f9fe493..9e3f9d7a 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -245,6 +245,13 @@ add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_ .nhs = en->nhs }; + if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH) + { + log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)", + oa->po->proto.name, en->lsa.type, en->lsa.id, en->lsa.rt); + return; + } + if (en == oa->rt) { /* @@ -336,7 +343,8 @@ ospf_rt_spfa_rtlinks(struct ospf_area *oa, struct top_hash_entry *act, struct to { // struct proto *p = &oa->po->proto; struct proto_ospf *po = oa->po; - int i; + ip_addr prefix UNUSED; + int pxlen UNUSED, i; struct ospf_lsa_rt *rt = en->lsa_body; struct ospf_lsa_rt_link *rr = (struct ospf_lsa_rt_link *) (rt + 1); @@ -357,9 +365,9 @@ ospf_rt_spfa_rtlinks(struct ospf_area *oa, struct top_hash_entry *act, struct to * the same result by handing them here because add_network() * will keep the best (not the first) found route. */ - add_network(oa, ipa_from_u32(rtl->id), - ipa_mklen(ipa_from_u32(rtl->data)), - act->dist + rtl->metric, act, i); + prefix = ipa_from_u32(rtl->id & rtl->data); + pxlen = ipa_mklen(ipa_from_u32(rtl->data)); + add_network(oa, prefix, pxlen, act->dist + rtl->metric, act, i); break; #endif @@ -398,6 +406,8 @@ ospf_rt_spfa(struct ospf_area *oa) struct ospf_lsa_rt *rt; struct ospf_lsa_net *ln; struct top_hash_entry *act, *tmp; + ip_addr prefix UNUSED; + int pxlen UNUSED; u32 i, *rts; node *n; @@ -470,8 +480,9 @@ ospf_rt_spfa(struct ospf_area *oa) ln = act->lsa_body; #ifdef OSPFv2 - add_network(oa, ipa_and(ipa_from_u32(act->lsa.id), ln->netmask), - ipa_mklen(ln->netmask), act->dist, act, -1); + prefix = ipa_and(ipa_from_u32(act->lsa.id), ln->netmask); + pxlen = ipa_mklen(ln->netmask); + add_network(oa, prefix, pxlen, act->dist, act, -1); #endif rts = (u32 *) (ln + 1); @@ -618,8 +629,8 @@ ospf_rt_sum(struct ospf_area *oa) { #ifdef OSPFv2 struct ospf_lsa_sum *ls = en->lsa_body; - pxlen = ipa_mklen(ls->netmask); ip = ipa_and(ipa_from_u32(en->lsa.id), ls->netmask); + pxlen = ipa_mklen(ls->netmask); #else /* OSPFv3 */ u8 pxopts; u16 rest; @@ -630,6 +641,13 @@ ospf_rt_sum(struct ospf_area *oa) continue; #endif + if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH) + { + log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)", + p->name, en->lsa.type, en->lsa.id, en->lsa.rt); + continue; + } + metric = ls->metric & METRIC_MASK; options = 0; type = ORT_NET; @@ -695,7 +713,7 @@ ospf_rt_sum(struct ospf_area *oa) static void ospf_rt_sum_tr(struct ospf_area *oa) { - // struct proto *p = &oa->po->proto; + struct proto *p = &oa->po->proto; struct proto_ospf *po = oa->po; struct ospf_area *bb = po->backbone; ip_addr abrip; @@ -728,8 +746,8 @@ ospf_rt_sum_tr(struct ospf_area *oa) int pxlen; #ifdef OSPFv2 struct ospf_lsa_sum *ls = en->lsa_body; - pxlen = ipa_mklen(ls->netmask); ip = ipa_and(ipa_from_u32(en->lsa.id), ls->netmask); + pxlen = ipa_mklen(ls->netmask); #else /* OSPFv3 */ u8 pxopts; u16 rest; @@ -740,6 +758,13 @@ ospf_rt_sum_tr(struct ospf_area *oa) continue; #endif + if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH) + { + log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)", + p->name, en->lsa.type, en->lsa.id, en->lsa.rt); + continue; + } + metric = ls->metric & METRIC_MASK; re = fib_find(&po->rtf, &ip, pxlen); } @@ -1139,9 +1164,9 @@ ospf_ext_spf(struct proto_ospf *po) rt_tag = 0; #endif - if (pxlen < 0) + if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH) { - log(L_WARN "%s: Invalid mask in LSA (Type: %04x, Id: %R, Rt: %R)", + log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)", p->name, en->lsa.type, en->lsa.id, en->lsa.rt); continue; } @@ -1703,8 +1728,6 @@ again1: e->net = ne; e->pref = p->preference; - - DBG("Mod rte type %d - %I/%d via %I on iface %s, met %d\n", a0.source, nf->fn.prefix, nf->fn.pxlen, a0.gw, a0.iface ? a0.iface->name : "(none)", nf->n.metric1); rte_update(p->table, ne, p, p, e);