From 44d1115ad6e7c01090d95480a27bd4484c91ffc5 Mon Sep 17 00:00:00 2001 From: Mobashshera Rasool Date: Fri, 3 Sep 2021 04:52:23 -0700 Subject: [PATCH 1/2] ospfd: ANVL Test case 25.22, 25.23 and 28.11 fixes ANVL Test case 28.11 If the database copy has LS age equal to MaxAge and LS sequence number equal to MaxSequenceNumber, simply discard the received LSA without acknowledging it. ANVL Test Case 25.22 When an attempt is made to increment the sequence number past the maximum value of N - 1 (0x7fffffff; also referred to as MaxSequenceNumber), the current instance of the LSA must first be flushed from the routing domain. ANVL Test Case 25.23 As soon as this flooding of a LSA with LS sequence number MaxSequenceNumber has been acknowledged by all adjacent neighbors, a new instance can be originated with sequence number of InitialSequenceNumber. RCA: When IXIA sent LS Seq num as MAX and LS Age as (MAX - 3), DUT dropped the packet instead of sending ACK. In function ospf_ls_upd, at Line 2106 the code is there to drop the LSA. Hence its failing. Fix: LSAs ACK must be sent when received LSA is having max sequence number but not max-aged. Considering /* CVE-2017-3224 */ issue, have corrected the existing code to prevent attacker from sending LSAs with max sequence number and higher checksum and blocking the flooding of the Max-sequence numbered LSAs. Signed-off-by: Mobashshera Rasool --- ospfd/ospf_lsa.h | 2 ++ ospfd/ospf_packet.c | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index d01dc720ba..f536c311f9 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -218,6 +218,8 @@ struct as_external_lsa { #define LS_AGE(x) (OSPF_LSA_MAXAGE < get_age(x) ? OSPF_LSA_MAXAGE : get_age(x)) #define IS_LSA_SELF(L) (CHECK_FLAG ((L)->flags, OSPF_LSA_SELF)) #define IS_LSA_MAXAGE(L) (LS_AGE ((L)) == OSPF_LSA_MAXAGE) +#define IS_LSA_MAX_SEQ(L) \ + ((L)->data->ls_seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER)) #define OSPF_LSA_UPDATE_DELAY 2 diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 9930b0bd49..8a76e265bc 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -2089,11 +2089,11 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, if (current == NULL || (ret = ospf_lsa_more_recent(current, lsa)) < 0) { /* CVE-2017-3224 */ - if (current && (lsa->data->ls_seqnum == - htonl(OSPF_MAX_SEQUENCE_NUMBER) - && !IS_LSA_MAXAGE(lsa))) { + if (current && (IS_LSA_MAX_SEQ(current)) + && (IS_LSA_MAX_SEQ(lsa)) + && !IS_LSA_MAXAGE(lsa)) { zlog_debug( - "Link State Update[%s]: has Max Seq but not MaxAge. Dropping it", + "Link State Update[%s]: has Max Seq and higher checksum but not MaxAge. Dropping it", dump_lsa_key(lsa)); DISCARD_LSA(lsa, 4); From 3cb62bb387d0630e8b2e3fe053de155563bac077 Mon Sep 17 00:00:00 2001 From: Mobashshera Rasool Date: Fri, 3 Sep 2021 05:10:26 -0700 Subject: [PATCH 2/2] ospfd: RFC conformance test case 25.23 issue fix Problem Statement : =================== LSA with InitialSequenceNumber is not originated after MaxSequenceNumber. ANVL Test case 25.33 states: ============================ As soon as this flooding of a LSA with LS sequence number MaxSequenceNumber has been acknowledged by all adjacent neighbors, a new instance can be originated with sequence number of InitialSequenceNumber. RCA : ===== DUT did not originated LSA with INITIAL_SEQUENCE number even after receiving ACK for max sequence LSA. Code is not present to handle this situation in the lsa ack flow. Fix : ===== Add code to originate LSA with initial sequence number in the LSA ack flow in case of wrap around sequence number. Signed-off-by: Mobashshera Rasool --- ospfd/ospf_lsa.c | 26 ++++++++++++++++++++++++++ ospfd/ospf_lsa.h | 2 ++ ospfd/ospf_packet.c | 7 ++++--- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index d209ae053c..cc1b2919c0 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2954,6 +2954,32 @@ static int ospf_maxage_lsa_remover(struct thread *thread) return 0; } +/* This function checks whether an LSA with initial sequence number should be + * originated after a wrap in sequence number + */ +void ospf_check_and_gen_init_seq_lsa(struct ospf_interface *oi, + struct ospf_lsa *recv_lsa) +{ + struct ospf_lsa *lsa = NULL; + struct ospf *ospf = oi->ospf; + + lsa = ospf_lsa_lookup_by_header(oi->area, recv_lsa->data); + + if ((lsa == NULL) || (!CHECK_FLAG(lsa->flags, OSPF_LSA_PREMATURE_AGE)) + || (lsa->retransmit_counter != 0)) { + if (IS_DEBUG_OSPF(lsa, LSA)) + zlog_debug( + "Do not generate LSA with initial seqence number."); + return; + } + + ospf_lsa_maxage_delete(ospf, lsa); + + lsa->data->ls_seqnum = lsa_seqnum_increment(lsa); + + ospf_lsa_refresh(ospf, lsa); +} + void ospf_lsa_maxage_delete(struct ospf *ospf, struct ospf_lsa *lsa) { struct route_node *rn; diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index f536c311f9..5dcd072774 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -349,6 +349,8 @@ extern struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf, extern struct ospf_lsa *ospf_translated_nssa_originate(struct ospf *ospf, struct ospf_lsa *type7, struct ospf_lsa *type5); +extern void ospf_check_and_gen_init_seq_lsa(struct ospf_interface *oi, + struct ospf_lsa *lsa); extern void ospf_flush_lsa_from_area(struct ospf *ospf, struct in_addr area_id, int type); #endif /* _ZEBRA_OSPF_LSA_H */ diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 8a76e265bc..000bbadc54 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -2090,8 +2090,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, || (ret = ospf_lsa_more_recent(current, lsa)) < 0) { /* CVE-2017-3224 */ if (current && (IS_LSA_MAX_SEQ(current)) - && (IS_LSA_MAX_SEQ(lsa)) - && !IS_LSA_MAXAGE(lsa)) { + && (IS_LSA_MAX_SEQ(lsa)) && !IS_LSA_MAXAGE(lsa)) { zlog_debug( "Link State Update[%s]: has Max Seq and higher checksum but not MaxAge. Dropping it", dump_lsa_key(lsa)); @@ -2271,8 +2270,10 @@ static void ospf_ls_ack(struct ip *iph, struct ospf_header *ospfh, lsr = ospf_ls_retransmit_lookup(nbr, lsa); - if (lsr != NULL && ospf_lsa_more_recent(lsr, lsa) == 0) + if (lsr != NULL && ospf_lsa_more_recent(lsr, lsa) == 0) { ospf_ls_retransmit_delete(nbr, lsr); + ospf_check_and_gen_init_seq_lsa(oi, lsa); + } lsa->data = NULL; ospf_lsa_discard(lsa);