Vydáno ve v1.36.0, 8. 10. 2026  Oprava chyby v KDE Connect pro Android v upstreamu

KDE Connect: neomezený buffer pro pakety přes Bluetooth na Androidu

Náš skener upozornil, že Bluetooth backend aplikace KDE Connect pro Android, která propojuje telefon s počítačem kvůli sdílení notifikací, souborů a schránky, ukládal příchozí pakety do bufferu bez jakéhokoli limitu velikosti. Poslali jsme merge request s opravou a unit testem. Autor a správce KDE Connect Albert Vaca Cintora ho týž den začlenil.

Co bylo špatně

Pakety KDE Connect jsou řádky JSON zakončené \n. Přijímací vlákno v BluetoothLink.kt přidávalo vše přečtené do StringBuilder, dokud nepřišel konec řádku, a to bez horní meze. Připojené zařízení, které posílalo data bez ukončení řádku, tak nutilo aplikaci držet všechno v paměti, dokud jí paměť nedošla. Protože se po každém čtení 512 znaků prohledával na \n celý buffer, byla smyčka navíc kvadratická vůči velikosti paketu.

Backend pro LAN (Wi-Fi) už ochranu měl: LanLink čte pakety přes readLineBounded() s limitem 32 MB. Bluetooth backend ne.

Dosah je omezený. Podpora Bluetooth je ve výchozím stavu vypnutá (nastavení se jmenuje „Enable bluetooth (beta)“) a protistrana musí být Bluetooth zařízení už spárované s telefonem. Nejhorší důsledek je vyčerpání paměti aplikace, ne spuštění kódu.

Jak to bylo opraveno

Oprava čte pakety přes Bluetooth stejným pomocníkem readLineBounded() se stejným limitem 32 MB jako LanLink. Paket nad limit se bere jako jakákoli jiná chyba čtení, takže se spojení ukončí. Vstup je obalen do BufferedInputStream jako v LanLink, aby čtení po bajtech nebralo zámek kanálu multiplexeru pro každý bajt.

-            val sb = StringBuilder()
             try {
-                val reader: Reader = InputStreamReader(input, UTF_8)
-                val buf = CharArray(512)
+                val stream = BufferedInputStream(input)
                 while (continueAccepting) {
-                    while (sb.indexOf("\n") == -1 && continueAccepting) {
-                        ...
-                            sb.append(buf, 0, charsRead)
-                        ...
-                    }
+                    val message = readLineBounded(stream, MAX_PACKET_SIZE)

Nový unit test BluetoothLinkTest pošle spojení 64 MB bez konce řádku a čeká, že se odpojí. Před změnou vypršel časový limit, po ní projde celá sada testů. Testovali jsme jen unit testem, ne se skutečným Bluetooth zařízením. Albert Vaca Cintora (albertvaka) v merge requestu odpověděl:

„Thanks for catching this!“

Časová osa

Jak to číst

Triáž skeneru popsala útočníka jako „unauthenticated or remote“. Čtení kódu to zúžilo na volitelný backend a už spárované zařízení a do upstreamu šel tento užší popis. Samotná oprava znovu používá ochranu, kterou projekt už měl pro spojení přes LAN. Nálezy jsou podněty pro lidi, ne rozsudky.

Zdroje

← Zpět na příběhy úspěchu