Fixed a race conditon when adding a transport and then an endpoint.

To fix issue #3611966, KeyManagerImpl's handling of TransportAddedEvent
was made asynchronous. This made it possible for a thread to call
KeyManager.endpointAdded() before the KeyManager had asynchronously
handled the TransportAddedEvent from a previous call to
DatabaseComponent.addTransport().
This commit is contained in:
akwizgran
2013-05-14 20:54:23 +01:00
parent 673d7fa0c3
commit dddd15cd10
7 changed files with 22 additions and 20 deletions

View File

@@ -27,5 +27,5 @@ public interface KeyManager {
* Called whenever an endpoint has been added. The initial secret
* is erased before returning.
*/
void endpointAdded(Endpoint ep, byte[] initialSecret);
void endpointAdded(Endpoint ep, long maxLatency, byte[] initialSecret);
}

View File

@@ -288,19 +288,25 @@ abstract class Connector extends Thread {
db.setRemoteProperties(contactId, remoteProps);
// Create an endpoint for each transport shared with the contact
List<TransportId> ids = new ArrayList<TransportId>();
for(TransportId id : localProps.keySet())
if(remoteProps.containsKey(id)) ids.add(id);
Map<TransportId, Long> latencies = db.getTransportLatencies();
for(TransportId id : localProps.keySet()) {
if(latencies.containsKey(id) && remoteProps.containsKey(id))
ids.add(id);
}
// Assign indices to the transports deterministically and derive keys
Collections.sort(ids, TransportIdComparator.INSTANCE);
int size = ids.size();
for(int i = 0; i < size; i++) {
Endpoint ep = new Endpoint(contactId, ids.get(i), epoch, alice);
TransportId id = ids.get(i);
Endpoint ep = new Endpoint(contactId, id, epoch, alice);
long maxLatency = latencies.get(id);
try {
db.addEndpoint(ep);
} catch(NoSuchTransportException e) {
continue;
}
keyManager.endpointAdded(ep, crypto.deriveInitialSecret(secret, i));
byte[] initialSecret = crypto.deriveInitialSecret(secret, i);
keyManager.endpointAdded(ep, maxLatency, initialSecret);
}
}

View File

@@ -252,13 +252,9 @@ class KeyManagerImpl extends TimerTask implements KeyManager, DatabaseListener {
return new ConnectionContext(c, t, secret, connection, s.getAlice());
}
public synchronized void endpointAdded(Endpoint ep, byte[] initialSecret) {
Long maxLatency = maxLatencies.get(ep.getTransportId());
if(maxLatency == null) {
if(LOG.isLoggable(INFO))
LOG.info("No such transport, ignoring endpoint");
return;
}
public synchronized void endpointAdded(Endpoint ep, long maxLatency,
byte[] initialSecret) {
maxLatencies.put(ep.getTransportId(), maxLatency);
// Work out which rotation period we're in
long elapsed = clock.currentTimeMillis() - ep.getEpoch();
long rotation = maxLatency + MAX_CLOCK_DIFFERENCE;

View File

@@ -55,7 +55,7 @@
</javac>
</target>
<target name='test' depends='compile'>
<junit printsummary='on' fork='yes' forkmode='once'>
<junit showoutput='yes' printsummary='on' fork='yes' forkmode='once'>
<assertions>
<enable/>
</assertions>

View File

@@ -125,7 +125,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
db.addTransport(transportId, LATENCY);
Endpoint ep = new Endpoint(contactId, transportId, epoch, true);
db.addEndpoint(ep);
km.endpointAdded(ep, initialSecret.clone());
km.endpointAdded(ep, LATENCY, initialSecret.clone());
// Send Bob a message
String contentType = "text/plain";
byte[] body = "Hi Bob!".getBytes("UTF-8");
@@ -179,7 +179,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
db.addTransport(transportId, LATENCY);
Endpoint ep = new Endpoint(contactId, transportId, epoch, false);
db.addEndpoint(ep);
km.endpointAdded(ep, initialSecret.clone());
km.endpointAdded(ep, LATENCY, initialSecret.clone());
// Set up a database listener
MessageListener listener = new MessageListener();
db.addListener(listener);

View File

@@ -141,7 +141,7 @@ public class KeyManagerImplTest extends BriarTestCase {
}});
assertTrue(keyManager.start());
keyManager.endpointAdded(ep, initialSecret.clone());
keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone());
keyManager.stop();
context.assertIsSatisfied();
@@ -202,7 +202,7 @@ public class KeyManagerImplTest extends BriarTestCase {
}});
assertTrue(keyManager.start());
keyManager.endpointAdded(ep, initialSecret.clone());
keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone());
ConnectionContext ctx =
keyManager.getConnectionContext(contactId, transportId);
assertNotNull(ctx);

View File

@@ -239,7 +239,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
}});
assertTrue(keyManager.start());
keyManager.endpointAdded(ep, initialSecret.clone());
keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone());
keyManager.stop();
context.assertIsSatisfied();
@@ -377,7 +377,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
}});
assertTrue(keyManager.start());
keyManager.endpointAdded(ep, initialSecret.clone());
keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone());
ConnectionContext ctx =
keyManager.getConnectionContext(contactId, transportId);
assertNotNull(ctx);
@@ -533,7 +533,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
}});
assertTrue(keyManager.start());
keyManager.endpointAdded(ep, initialSecret.clone());
keyManager.endpointAdded(ep, MAX_LATENCY, initialSecret.clone());
// Recognise the tag for connection 0 in period 2
byte[] tag = new byte[TAG_LENGTH];
encodeTag(tag, key2, 0);