Add file-level locking to prevent race conditions in key persistence
Per-key ReentrantLock prevents concurrent writes to same key file
This commit is contained in:
+25
-1
@@ -7,9 +7,12 @@ import java.io.DataOutputStream
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.security.KeyPair
|
||||
import java.security.MessageDigest
|
||||
import java.security.cert.Certificate
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import org.matrix.TEESimulator.config.ConfigurationManager.CONFIG_PATH
|
||||
import org.matrix.TEESimulator.interception.keystore.KeyIdentifier
|
||||
import org.matrix.TEESimulator.logging.SystemLogger
|
||||
@@ -35,6 +38,13 @@ object GeneratedKeyPersistence {
|
||||
private const val FORMAT_VERSION = 1
|
||||
private val PERSISTENCE_DIR = File(CONFIG_PATH, "persistent_keys")
|
||||
|
||||
// Per-filename locks to prevent concurrent writes to the same key file
|
||||
private val fileLocks = ConcurrentHashMap<String, ReentrantLock>()
|
||||
|
||||
private fun getLockForKey(filename: String): ReentrantLock {
|
||||
return fileLocks.computeIfAbsent(filename) { ReentrantLock() }
|
||||
}
|
||||
|
||||
fun save(
|
||||
keyId: KeyIdentifier,
|
||||
keyPair: KeyPair,
|
||||
@@ -48,9 +58,14 @@ object GeneratedKeyPersistence {
|
||||
digests: List<Int>,
|
||||
isAttestationKey: Boolean,
|
||||
) {
|
||||
val filename = keyFileName(keyId.uid, keyId.alias)
|
||||
val lock = getLockForKey(filename)
|
||||
SystemLogger.debug("[Persistence] Acquiring lock for $filename")
|
||||
lock.lock()
|
||||
try {
|
||||
SystemLogger.debug("[Persistence] Lock acquired for $filename")
|
||||
runCatching {
|
||||
PERSISTENCE_DIR.mkdirs()
|
||||
val filename = keyFileName(keyId.uid, keyId.alias)
|
||||
val finalFile = File(PERSISTENCE_DIR, filename)
|
||||
val tmpFile = File(PERSISTENCE_DIR, "$filename.tmp")
|
||||
|
||||
@@ -94,10 +109,19 @@ object GeneratedKeyPersistence {
|
||||
throw IllegalStateException("Failed to atomically rename $tmpFile -> $finalFile")
|
||||
}
|
||||
|
||||
// Verify write succeeded - catches disk-full or filesystem errors
|
||||
if (!finalFile.exists() || finalFile.length() < 20) {
|
||||
throw IOException("File write verification failed - possible disk full")
|
||||
}
|
||||
|
||||
SystemLogger.debug("Persisted key: $keyId")
|
||||
}.onFailure { e ->
|
||||
SystemLogger.error("Failed to persist key $keyId", e)
|
||||
}
|
||||
} finally {
|
||||
lock.unlock()
|
||||
SystemLogger.debug("[Persistence] Lock released for $filename")
|
||||
}
|
||||
}
|
||||
|
||||
fun delete(keyId: KeyIdentifier) {
|
||||
|
||||
Reference in New Issue
Block a user