Skip to content

Commit

Permalink
ospfd: Fix OSPF link-local opaque LSA crash and opaque memory corruption
Browse files Browse the repository at this point in the history
  1. When an OSPF interface is deleted, remove the references in link-local
     LSA. Delete the LSA from the LSDB so that the callback has accessibily
     to the interface prior to deletion.
  2. Fix a double free for the opaque function table data structure.
  3. Assure that the opaque per-type information and opaque function table
     structures are removed at the same time since they have back pointers
     to one another.
  4. Add a topotest variation for the link-local opaque LSA crash.

Signed-off-by: Acee <[email protected]>
  • Loading branch information
Acee committed Nov 26, 2023
1 parent d1e11d4 commit a437347
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 53 deletions.
22 changes: 2 additions & 20 deletions ospfd/ospf_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,8 @@ void ospf_if_free(struct ospf_interface *oi)

assert(oi->state == ISM_Down);

ospf_opaque_type9_lsa_if_cleanup(oi);

ospf_opaque_type9_lsa_term(oi);

QOBJ_UNREG(oi);
Expand Down Expand Up @@ -380,26 +382,6 @@ int ospf_if_is_up(struct ospf_interface *oi)
return if_is_up(oi->ifp);
}

struct ospf_interface *ospf_if_exists(struct ospf_interface *oic)
{
struct listnode *node;
struct ospf *ospf;
struct ospf_interface *oi;

if (!oic)
return NULL;

ospf = oic->ospf;
if (ospf == NULL)
return NULL;

for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi))
if (oi == oic)
return oi;

return NULL;
}

/* Lookup OSPF interface by router LSA posistion */
struct ospf_interface *ospf_if_lookup_by_lsa_pos(struct ospf_area *area,
int lsa_pos)
Expand Down
1 change: 0 additions & 1 deletion ospfd/ospf_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,6 @@ extern int ospf_if_up(struct ospf_interface *oi);
extern int ospf_if_down(struct ospf_interface *oi);

extern int ospf_if_is_up(struct ospf_interface *oi);
extern struct ospf_interface *ospf_if_exists(struct ospf_interface *oi);
extern struct ospf_interface *ospf_if_lookup_by_lsa_pos(struct ospf_area *area,
int lsa_pos);
extern struct ospf_interface *
Expand Down
2 changes: 1 addition & 1 deletion ospfd/ospf_nsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ static int ospf_db_summary_add(struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
case OSPF_OPAQUE_LINK_LSA:
/* Exclude type-9 LSAs that does not have the same "oi" with
* "nbr". */
if (ospf_if_exists(lsa->oi) != nbr->oi)
if (lsa->oi != nbr->oi)
return 0;
break;
case OSPF_OPAQUE_AREA_LSA:
Expand Down
62 changes: 59 additions & 3 deletions ospfd/ospf_opaque.c
Original file line number Diff line number Diff line change
Expand Up @@ -427,10 +427,12 @@ void ospf_delete_opaque_functab(uint8_t lsa_type, uint8_t opaque_type)
if (functab->oipt != NULL)
free_opaque_info_per_type(functab->oipt,
true);
/* Dequeue listnode entry from the list. */
/* Dequeue listnode entry from the function table
* list coreesponding to the opaque LSA type.
* Note that the list deletion callback frees
* the functab entry memory.
*/
listnode_delete(funclist, functab);

XFREE(MTYPE_OSPF_OPAQUE_FUNCTAB, functab);
break;
}
}
Expand Down Expand Up @@ -614,6 +616,17 @@ static void free_opaque_info_per_type(struct opaque_info_per_type *oipt,
}
listnode_delete(l, oipt);
}

/*
* Delete the function table corresponding to the LSA type and opaque type
* as well. The pointer to the opaque per-type information structure in
* the function table structure be set to NULL to avoid recursion during
* deletion.
*/
if (oipt->functab) {
oipt->functab->oipt = NULL;
ospf_delete_opaque_functab(oipt->lsa_type, oipt->opaque_type);
}
XFREE(MTYPE_OPAQUE_INFO_PER_TYPE, oipt);
return;
}
Expand Down Expand Up @@ -746,6 +759,49 @@ int ospf_opaque_is_owned(struct ospf_lsa *lsa)
return (oipt != NULL && lookup_opaque_info_by_id(oipt, lsa) != NULL);
}

/*
* Cleanup Link-Local LSAs assocaited with an interface that is being deleted.
* Since these LSAs are stored in the area link state database (LSDB) as opposed
* to a separate per-interface, they must be deleted from the area database.
* Since their flooding scope is solely the deleted OSPF interface, there is no
* need to attempt to flush them from the routing domain. For link local LSAs
* originated via the OSPF server API, LSA deletion before interface deletion
* is required so that the callback can access the OSPF interface address.
*/
void ospf_opaque_type9_lsa_if_cleanup(struct ospf_interface *oi)
{
struct route_table *table;
struct route_node *rn;
struct ospf_lsdb *lsdb;
struct ospf_lsa *lsa;

lsdb = oi->area->lsdb;
table = lsdb->type[OSPF_OPAQUE_LINK_LSA].db;
for (rn = route_top(table); rn; rn = route_next(rn))
if (rn->info != NULL) {
lsa = rn->info;
/*
* While the LSA shouldn't be referenced on any LSA
* lists since the flooding scoped is confined to the
* interface being deleted, clear the pointer to the
* deleted interface for safety's sake after it is
* is removed from the area LSDB.
*/
if (lsa->oi == oi) {
if (IS_DEBUG_OSPF_EVENT)
zlog_debug("Delete Type-9 Opaque-LSA on interface delete: [opaque-type=%u, opaque-id=%x]",
GET_OPAQUE_TYPE(ntohl(
lsa->data->id.s_addr)),
GET_OPAQUE_ID(ntohl(
lsa->data->id.s_addr)));
ospf_lsa_lock(lsa);
ospf_lsdb_delete(lsdb, lsa);
lsa->oi = NULL;
ospf_lsa_unlock(&lsa);
}
}
}

/*------------------------------------------------------------------------*
* Following are (vty) configuration functions for Opaque-LSAs handling.
*------------------------------------------------------------------------*/
Expand Down
1 change: 1 addition & 0 deletions ospfd/ospf_opaque.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ extern void ospf_opaque_term(void);
extern void ospf_opaque_finish(void);
extern int ospf_opaque_type9_lsa_init(struct ospf_interface *oi);
extern void ospf_opaque_type9_lsa_term(struct ospf_interface *oi);
extern void ospf_opaque_type9_lsa_if_cleanup(struct ospf_interface *oi);
extern int ospf_opaque_type10_lsa_init(struct ospf_area *area);
extern void ospf_opaque_type10_lsa_term(struct ospf_area *area);
extern int ospf_opaque_type11_lsa_init(struct ospf *ospf);
Expand Down
Loading

0 comments on commit a437347

Please sign in to comment.