From e2e3aa0539323b2fc048684d375641bc569a04b6 Mon Sep 17 00:00:00 2001 From: "Clay Kaiser (via linuxptp-devel Mailing List)" Date: Fri, 24 May 2024 16:05:06 -0400 Subject: [PATCH] sad: introduce sad_set_last_seqid() and sad_check_seqid() The standard specifies that the header sequence id should be checked to confirm the message has not been replayed. It specifies a seqid check for each message that has it's own sequence id pool but this is most relevant for sync/followup messages for which slaves do not confirm seqid currently. The standard also mentioned a seqid window. The seqid window specifies how far the seqid can advance from the last know seqid before it is considered a replay attack from before a seqid rollover. This patch introduces sad_check_seqid() in sad.c to check the seqid and sad_set_last_seqid() which is updates the last seqid upon successful sync in port_synchronize() and reset upon state transition in port_e2e_transition() and port_p2p_transition. Signed-off-by: Clay Kaiser Reviewed-by: Erez Geva Reviewed-by: Miroslav Lichvar --- port.c | 8 +++++++ sad.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sad.h | 9 ++++++++ 3 files changed, 89 insertions(+) diff --git a/port.c b/port.c index 5230b4bf..91702c29 100644 --- a/port.c +++ b/port.c @@ -1399,6 +1399,8 @@ static void port_synchronize(struct port *p, break; } + sad_set_last_seqid(clock_config(p->clock), p->spp, seqid); + last_state = clock_servo_state(p->clock); state = clock_synchronize(p->clock, t2, t1c); switch (state) { @@ -2824,6 +2826,7 @@ static void port_e2e_transition(struct port *p, enum port_state next) case PS_FAULTY: case PS_DISABLED: port_disable(p); + sad_set_last_seqid(clock_config(p->clock), p->spp, -1); break; case PS_LISTENING: port_set_announce_tmo(p); @@ -2837,6 +2840,7 @@ static void port_e2e_transition(struct port *p, enum port_state next) set_tmo_log(p->fda.fd[FD_MANNO_TIMER], 1, -10); /*~1ms*/ } port_set_sync_tx_tmo(p); + sad_set_last_seqid(clock_config(p->clock), p->spp, -1); break; case PS_PASSIVE: port_set_announce_tmo(p); @@ -2844,6 +2848,7 @@ static void port_e2e_transition(struct port *p, enum port_state next) case PS_UNCALIBRATED: flush_last_sync(p); flush_delay_req(p); + sad_set_last_seqid(clock_config(p->clock), p->spp, -1); /* fall through */ case PS_SLAVE: port_set_announce_tmo(p); @@ -2868,6 +2873,7 @@ static void port_p2p_transition(struct port *p, enum port_state next) case PS_FAULTY: case PS_DISABLED: port_disable(p); + sad_set_last_seqid(clock_config(p->clock), p->spp, -1); break; case PS_LISTENING: port_set_announce_tmo(p); @@ -2882,6 +2888,7 @@ static void port_p2p_transition(struct port *p, enum port_state next) set_tmo_log(p->fda.fd[FD_MANNO_TIMER], 1, -10); /*~1ms*/ } port_set_sync_tx_tmo(p); + sad_set_last_seqid(clock_config(p->clock), p->spp, -1); break; case PS_PASSIVE: port_set_announce_tmo(p); @@ -2889,6 +2896,7 @@ static void port_p2p_transition(struct port *p, enum port_state next) case PS_UNCALIBRATED: flush_last_sync(p); flush_peer_delay(p); + sad_set_last_seqid(clock_config(p->clock), p->spp, -1); /* fall through */ case PS_SLAVE: port_set_announce_tmo(p); diff --git a/sad.c b/sad.c index 0334b8f0..43ee92fc 100644 --- a/sad.c +++ b/sad.c @@ -67,6 +67,73 @@ static inline size_t sad_get_auth_tlv_len(struct security_association *sa, icv_len; /* size of icv (defined by key) */ } +/** + * update the last received seqid + */ +void sad_set_last_seqid(struct config *cfg, + int spp, Integer32 seqid) +{ + struct security_association* sa; + /* immediately return if security is not configured */ + if (spp < 0) { + return; + } + /* retrieve sa specified by spp */ + sa = sad_get_association(cfg, spp); + if (!sa) { + return; + } + + sa->last_seqid = (seqid == -1) ? seqid : (UInteger16) seqid; +} + +/** + * confirm seqid from inbound message header is with in seqid window. + */ +static int sad_check_seqid(struct ptp_message *msg, + Integer32 last_seqid, + UInteger16 seqid_window) +{ + UInteger16 new_seqid; + /* do not check seqid if seqid_window is zero */ + if (seqid_window < 1) { + return 0; + } + + /* (for now) only check seqid on sync/followup msgs */ + switch (msg_type(msg)) { + case SYNC: + case FOLLOW_UP: + new_seqid = msg->header.sequenceId; + /* last_seqid < 0 means unitialized */ + if (last_seqid < 0) { + return 0; + /* verify received seqid is greater than last */ + /* use mod(uint16) to handle wrap within window */ + } else if (new_seqid < (UInteger16)(last_seqid + 1) && + (UInteger16)(new_seqid + seqid_window) < + (UInteger16)(last_seqid + 1 + seqid_window)) { + pr_debug("replayed seqid: received seqid %u " + "smaller than last %u", + new_seqid, last_seqid); + return -EBADMSG; + /* verify received seqid is less than seqid window */ + /* use mod(uint16) to handle wrap within window */ + } else if (new_seqid > (UInteger16)(last_seqid + seqid_window) && + (UInteger16)(new_seqid + seqid_window) > + (UInteger16)(last_seqid + 2 * seqid_window)) { + pr_debug("replayed seqid: received seqid %u " + "beyond seqid_window %u + %d", + new_seqid, last_seqid, seqid_window); + return -EBADMSG; + } + break; + default: + break; + } + return 0; +} + static int sad_check_auth_tlv(struct security_association *sa, struct ptp_message *msg, struct ptp_message *raw) @@ -180,6 +247,11 @@ int sad_process_auth(struct config *cfg, int spp, if (!sa) { return -EPROTO; } + /* check seqid in header first (sync/followup only) */ + err = sad_check_seqid(msg, sa->last_seqid, sa->seqid_window); + if (err) { + return err; + } /* detect and process any auth tlvs */ err = sad_check_auth_tlv(sa, msg, raw); return err; diff --git a/sad.h b/sad.h index b55891da..4b797e81 100644 --- a/sad.h +++ b/sad.h @@ -25,6 +25,15 @@ struct security_association { Integer32 last_seqid; }; +/** + * Set the last received sequence id for SYNC/FOLLOW_UP + * @param cfg pointer to config that contains sad + * @param spp security parameters pointer for desired sa + * @param seqid sequence id to store in SA +*/ +void sad_set_last_seqid(struct config *cfg, + int spp, Integer32 seqid); + /** * inbound message authentication processing: * 1. check seqid (on sync/followup)