mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-26 12:25:22 +00:00
Fix P1: Add DoS protections to PeerID fragment handler
Critical security fix addressing Codex review feedback: The PeerID overload of handleFragment (which is actually called by CoreBluetooth) was missing key safety checks that existed in the String overload: 1. Added total <= 10000 check to prevent unbounded fragment counts 2. Added cumulative size check against FileTransferLimits before storing each fragment 3. Prevents memory exhaustion DoS attacks via malicious fragment streams This ensures the actually-used code path has proper bounds checking.
This commit is contained in:
@@ -3414,8 +3414,8 @@ extension BLEService {
|
|||||||
let originalType = packet.payload[12]
|
let originalType = packet.payload[12]
|
||||||
let fragmentData = packet.payload.suffix(from: 13)
|
let fragmentData = packet.payload.suffix(from: 13)
|
||||||
|
|
||||||
// Sanity checks
|
// Sanity checks - add reasonable upper bound on total to prevent DoS
|
||||||
guard total > 0 && index >= 0 && index < total else { return }
|
guard total > 0 && total <= 10000 && index >= 0 && index < total else { return }
|
||||||
|
|
||||||
// Store fragment
|
// Store fragment
|
||||||
let key = FragmentKey(sender: senderU64, id: fragU64)
|
let key = FragmentKey(sender: senderU64, id: fragU64)
|
||||||
@@ -3431,6 +3431,27 @@ extension BLEService {
|
|||||||
incomingFragments[key] = [:]
|
incomingFragments[key] = [:]
|
||||||
fragmentMetadata[key] = (originalType, total, Date())
|
fragmentMetadata[key] = (originalType, total, Date())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check cumulative size before storing this fragment
|
||||||
|
let currentSize = incomingFragments[key]?.values.reduce(0) { $0 + $1.count } ?? 0
|
||||||
|
let assemblyLimit: Int = {
|
||||||
|
if originalType == MessageType.fileTransfer.rawValue {
|
||||||
|
// Allow headroom for TLV metadata and binary framing overhead.
|
||||||
|
return FileTransferLimits.maxFramedFileBytes
|
||||||
|
}
|
||||||
|
return FileTransferLimits.maxPayloadBytes
|
||||||
|
}()
|
||||||
|
guard currentSize + fragmentData.count <= assemblyLimit else {
|
||||||
|
// Exceeds size limit - evict this assembly
|
||||||
|
SecureLogger.warning(
|
||||||
|
"🚫 Fragment assembly exceeds size limit (\(currentSize + fragmentData.count) bytes > \(assemblyLimit)), evicting",
|
||||||
|
category: .security
|
||||||
|
)
|
||||||
|
incomingFragments.removeValue(forKey: key)
|
||||||
|
fragmentMetadata.removeValue(forKey: key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
incomingFragments[key]?[index] = Data(fragmentData)
|
incomingFragments[key]?[index] = Data(fragmentData)
|
||||||
|
|
||||||
// Check if complete
|
// Check if complete
|
||||||
|
|||||||
Reference in New Issue
Block a user