Skip to content

Commit 3cc07a0

Browse files
committed
Use atomic to avoid stale SRTP protection profile
`state` is acccessed without lock in the FSM. In some cases, that leads to stale values. For example, `srtpProtectionProfile` is set in flight handlers (differnt flight handlers in client and server). But, when it is accessed via the API `SelectedSRTPProtectionProfile`, it gets a stale value as it appears that the two goroutines are out-of-sync on that piece of shared memory. This is a larger concern for use of `state`. Ideally, either - `state` should have a lock internally and all fields are accessed through methods. - carefully split fields of `state` to ensure process access/sync. Doing the smaller change here to address one field that has seen stale value.
1 parent 5c0a7c1 commit 3cc07a0

6 files changed

Lines changed: 25 additions & 15 deletions

File tree

conn.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -374,14 +374,12 @@ func (c *Conn) ConnectionState() State {
374374

375375
// SelectedSRTPProtectionProfile returns the selected SRTPProtectionProfile
376376
func (c *Conn) SelectedSRTPProtectionProfile() (SRTPProtectionProfile, bool) {
377-
c.lock.RLock()
378-
defer c.lock.RUnlock()
379-
380-
if c.state.srtpProtectionProfile == 0 {
377+
profile := c.state.getSRTPProtectionProfile()
378+
if profile == 0 {
381379
return 0, false
382380
}
383381

384-
return c.state.srtpProtectionProfile, true
382+
return profile, true
385383
}
386384

387385
func (c *Conn) writePackets(ctx context.Context, pkts []*packet) error {

flight0handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func flight0Parse(_ context.Context, _ flightConn, state *State, cache *handshak
6060
if !ok {
6161
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errServerNoMatchingSRTPProfile
6262
}
63-
state.srtpProtectionProfile = profile
63+
state.setSRTPProtectionProfile(profile)
6464
case *extension.UseExtendedMasterSecret:
6565
if cfg.extendedMasterSecret != DisableExtendedMasterSecret {
6666
state.extendedMasterSecret = true

flight3handler.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func flight3Parse(ctx context.Context, c flightConn, state *State, cache *handsh
5656
if !found {
5757
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.IllegalParameter}, errClientNoMatchingSRTPProfile
5858
}
59-
state.srtpProtectionProfile = profile
59+
state.setSRTPProtectionProfile(profile)
6060
case *extension.UseExtendedMasterSecret:
6161
if cfg.extendedMasterSecret != DisableExtendedMasterSecret {
6262
state.extendedMasterSecret = true
@@ -71,7 +71,7 @@ func flight3Parse(ctx context.Context, c flightConn, state *State, cache *handsh
7171
if cfg.extendedMasterSecret == RequireExtendedMasterSecret && !state.extendedMasterSecret {
7272
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errClientRequiredButNoServerEMS
7373
}
74-
if len(cfg.localSRTPProtectionProfiles) > 0 && state.srtpProtectionProfile == 0 {
74+
if len(cfg.localSRTPProtectionProfiles) > 0 && state.getSRTPProtectionProfile() == 0 {
7575
return 0, &alert.Alert{Level: alert.Fatal, Description: alert.InsufficientSecurity}, errRequestedButNoSRTPExtension
7676
}
7777

flight4bhandler.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ func flight4bGenerate(_ flightConn, state *State, cache *handshakeCache, cfg *ha
5959
Supported: true,
6060
})
6161
}
62-
if state.srtpProtectionProfile != 0 {
62+
if state.getSRTPProtectionProfile() != 0 {
6363
extensions = append(extensions, &extension.UseSRTP{
64-
ProtectionProfiles: []SRTPProtectionProfile{state.srtpProtectionProfile},
64+
ProtectionProfiles: []SRTPProtectionProfile{state.getSRTPProtectionProfile()},
6565
})
6666
}
6767

flight4handler.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,9 @@ func flight4Generate(_ flightConn, state *State, _ *handshakeCache, cfg *handsha
228228
Supported: true,
229229
})
230230
}
231-
if state.srtpProtectionProfile != 0 {
231+
if state.getSRTPProtectionProfile() != 0 {
232232
extensions = append(extensions, &extension.UseSRTP{
233-
ProtectionProfiles: []SRTPProtectionProfile{state.srtpProtectionProfile},
233+
ProtectionProfiles: []SRTPProtectionProfile{state.getSRTPProtectionProfile()},
234234
})
235235
}
236236
if state.cipherSuite.AuthenticationType() == CipherSuiteAuthenticationTypeCertificate {

state.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ type State struct {
2222
masterSecret []byte
2323
cipherSuite CipherSuite // nil if a cipherSuite hasn't been chosen
2424

25-
srtpProtectionProfile SRTPProtectionProfile // Negotiated SRTPProtectionProfile
25+
srtpProtectionProfile atomic.Value // Negotiated SRTPProtectionProfile
2626
PeerCertificates [][]byte
2727
IdentityHint []byte
2828
SessionID []byte
@@ -87,7 +87,7 @@ func (s *State) serialize() *serializedState {
8787
SequenceNumber: atomic.LoadUint64(&s.localSequenceNumber[epoch]),
8888
LocalRandom: localRnd,
8989
RemoteRandom: remoteRnd,
90-
SRTPProtectionProfile: uint16(s.srtpProtectionProfile),
90+
SRTPProtectionProfile: uint16(s.getSRTPProtectionProfile()),
9191
PeerCertificates: s.PeerCertificates,
9292
IdentityHint: s.IdentityHint,
9393
SessionID: s.SessionID,
@@ -123,7 +123,7 @@ func (s *State) deserialize(serialized serializedState) {
123123
s.cipherSuite = cipherSuiteForID(CipherSuiteID(serialized.CipherSuiteID), nil)
124124

125125
atomic.StoreUint64(&s.localSequenceNumber[epoch], serialized.SequenceNumber)
126-
s.srtpProtectionProfile = SRTPProtectionProfile(serialized.SRTPProtectionProfile)
126+
s.setSRTPProtectionProfile(SRTPProtectionProfile(serialized.SRTPProtectionProfile))
127127

128128
// Set remote certificate
129129
s.PeerCertificates = serialized.PeerCertificates
@@ -214,3 +214,15 @@ func (s *State) getLocalEpoch() uint16 {
214214
}
215215
return 0
216216
}
217+
218+
func (s *State) setSRTPProtectionProfile(profile SRTPProtectionProfile) {
219+
s.srtpProtectionProfile.Store(profile)
220+
}
221+
222+
func (s *State) getSRTPProtectionProfile() SRTPProtectionProfile {
223+
if val, ok := s.srtpProtectionProfile.Load().(SRTPProtectionProfile); ok {
224+
return val
225+
}
226+
227+
return 0
228+
}

0 commit comments

Comments
 (0)