From: Srinivas Aji Date: Mon, 28 May 2007 18:22:43 +0000 (+0530) Subject: Improve and fix validation of received BPDUs. X-Git-Url: http://git.ipfire.org/?p=people%2Fms%2Frstp.git;a=commitdiff_plain;h=fcc6b809a2889306841e0abf54e67e99b1808a66 Improve and fix validation of received BPDUs. Validate ethernet and LLC headers: Check destination address, length, and SAP fields. Also fix length checks for Config and RST BPDUs. Signed-off-by: Srinivas Aji --- diff --git a/bridge_track.c b/bridge_track.c index 00e60e3..e4b512d 100644 --- a/bridge_track.c +++ b/bridge_track.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -565,10 +566,26 @@ int bridge_notify(int br_index, int if_index, int newlink, int up) return 0; } +struct llc_header +{ + uint8_t dest_addr[ETH_ALEN]; + uint8_t src_addr[ETH_ALEN]; + uint16_t len8023; + uint8_t d_sap; /* 0x42 */ + uint8_t s_sap; /* 0x42 */ + uint8_t llc_ui; /* 0x03 */ +} __attribute__((packed)); + +const unsigned char bridge_group_address[ETH_ALEN] = { + 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 +}; + +const unsigned char STP_SAP = 0x42; + void bridge_bpdu_rcv(int if_index, const unsigned char *data, int len) { struct ifdata *ifc = find_if(if_index); - BPDU_T *bpdu = (BPDU_T *) (data + sizeof(MAC_HEADER_T)); + BPDU_T *bpdu; LOG("ifindex %d, len %d", if_index, len); if (!ifc) @@ -576,17 +593,35 @@ void bridge_bpdu_rcv(int if_index, const unsigned char *data, int len) TST(ifc->up,); TST(ifc->master->stp_up,); - TST(len > sizeof(MAC_HEADER_T) + sizeof(ETH_HEADER_T) + sizeof(BPDU_HEADER_T),); - /* Do some validation */ + /* Validate Ethernet and LLC header */ + { + struct llc_header *h; + unsigned int l; + TST(len > sizeof(struct llc_header),); + h = (struct llc_header *)data; + TST(memcmp(h->dest_addr, bridge_group_address, ETH_ALEN) == 0, + ); + l = ntohs(h->len8023); + TST(l <= ETH_DATA_LEN && l <= len - ETH_HLEN && l >= 3,); + TST(h->d_sap == STP_SAP && h->s_sap == STP_SAP + && (h->llc_ui & 0x3) == 0x3 /* LLC UI */,); + /* BPDU_T includes ETH_HEADER_T, i.e. {d_sap, s_sap, llc_ui} */ + bpdu = (BPDU_T *)(data + sizeof(*h) - sizeof(ETH_HEADER_T)); + len = l + 2; /* ETH_HEADER_T includes the 2 bytes of len8023 */ + } + + TST(len > sizeof(ETH_HEADER_T) + sizeof(BPDU_HEADER_T),); + + /* Do some BPDU validation as per 9.3.4 of standard */ if (bpdu->hdr.protocol[0] || bpdu->hdr.protocol[1]) return; switch (bpdu->hdr.bpdu_type) { case BPDU_RSTP: - TST(len >= 36,); + TST(len >= sizeof(ETH_HEADER_T) + 36,); case BPDU_CONFIG_TYPE: - TST(len >= 35,); + TST(len >= sizeof(ETH_HEADER_T) + 35,); /* 802.1w doesn't ask for this */ // TST(ntohs(*(uint16_t*)bpdu.body.message_age) // < ntohs(*(uint16_t*)bpdu.body.max_age), );