mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-10-25 07:40:36 +00:00
fix(sync): reject out-of-range GCS parameters instead of decoding garbage
decodeToSortedSet takes p and m straight off the wire - REQUEST_SYNC carries P as a uint8, so 0..255 all arrive - and decodes with them regardless. Kotlin's shift operators use the low 6 bits of the count, so p >= 64 wraps and the decoder emits values that were never in the filter; p = 0 turns every remainder into a zero-width read and manufactures a value per bit. On today's 20-id filter, p = 0 decodes 105 values. Those values are read as "the peer already has this packet", so the responder withholds packets the peer actually lacks - the failure direction that loses messages. Guard the parameters as iOS does in GCSFilter.decodeToSortedSet: p in 1..32 and m > 1, otherwise decode to nothing, which callers read as "peer has nothing" and answer by sending the data.
This commit is contained in:
parent
b028270cc4
commit
56c7e6d0be
@ -18,6 +18,14 @@ import kotlin.math.ln
|
||||
* - Bitstream is packed MSB-first in each byte.
|
||||
*/
|
||||
object GCSFilter {
|
||||
/**
|
||||
* Highest Golomb-Rice parameter accepted from the wire. P maps to an FPR of
|
||||
* ~1/2^P; beyond 32 the remainder width exceeds any practical filter, and
|
||||
* the shifts in decode silently wrap (Kotlin shifts use the low 6 bits of
|
||||
* the count) into garbage values.
|
||||
*/
|
||||
const val MAX_P = 32
|
||||
|
||||
data class Params(
|
||||
val p: Int, // Golomb-Rice parameter (>= 1)
|
||||
val m: Long, // Range M = N * 2^P
|
||||
@ -70,6 +78,11 @@ object GCSFilter {
|
||||
}
|
||||
|
||||
fun decodeToSortedSet(p: Int, m: Long, data: ByteArray): LongArray {
|
||||
// p and m arrive off the wire. Reject out-of-range parameters rather
|
||||
// than decoding garbage: callers read the result as "peer has nothing"
|
||||
// and fall back to sending the data, which is the safe direction.
|
||||
// Matches the iOS guard in GCSFilter.decodeToSortedSet.
|
||||
if (p < 1 || p > MAX_P || m <= 1L) return LongArray(0)
|
||||
val values = ArrayList<Long>()
|
||||
val reader = BitReader(data)
|
||||
var acc = 0L
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user