VPN i chroot på Android: hvorfor tunnelen virker, og hvorfor apps ignorerer den
chroot ændrer stiopløsning, ikke kernen, netværksnavnerummet eller Androids VPN-registrering. Der følger to udfald, og begge overrasker folk.
Du får en Linux-distribution til at køre under chroot på telefonen, installerer en VPN-klient i den, og shellen meddeler, at tunnelen er etableret. Så skifter du til en browser, og trafikken går ud over mobildata, som om intet var sket. Eller det modsatte: alle apps på telefonen mister forbindelsen, fordi klienten har lagt en standardrute i det navnerum, Android faktisk bruger. De to symptomer kommer fra samme manglende brik, og ingen af dem er en fejl i VPN-klienten.
Shellen siger forbundet, appene er uenige
Det første udfald er det almindelige. En brugertunntunnel åbnet fra en chroot kan fuldføre sit handshake, printe sin statistik og bære trafik, som den samme shell genererer, mens Androids apps fortsat bruger telefonens standardnetværk. Intet opfanger dem, fordi intet har fortalt Android, at der findes en VPN.
Det andet udfald er det farlige. Hvis chrooten deler Androids netværksnavnerum, hvilket den gør som standard, kan en proces med tilstrækkelige rettigheder tilføje ruter og et TUN-interface, der påvirker hele telefonen. Så virker tunnelen for alle apps, også dem du ikke ville route, og telefonens forbindelse afhænger nu af en daemon uden livscyklusstyring, uden forbindelsesindikator og uden politik for altid-til.
Hvilket af de to udfald du fik, kan besvares med én kommando. Sammenlign ip route inde i chrooten med samme kommando fra en Android-shell udenfor. Identisk output betyder, at chrooten er i værtens navnerum: enhver netværksændring, den laver, gælder hele telefonen. Forskelligt output betyder, at launcheren har oprettet et navnerum til den, og dens tunnel er ved sin opbygning usynlig for Android.
Hvad chrooten ændrede, og hvad den ikke gjorde
| Object | Effect of a chroot |
|---|---|
| Pathname resolution | Changed: lookups start at the new root |
| Kernel and drivers | Unchanged: the phone's kernel, its TUN driver, its limits |
| Network namespace | Unchanged unless the launcher creates one |
| Android VPN registration | Unchanged: no app consented, no VPN is selected |
Systemkaldet chroot gør én ting: det ændrer den mappe, der bruges til stipoløsning. Man-siden siger udtrykkeligt, at det ikke er en sikkerhedsgrænse, og den siger intet om interfaces, ruter eller VPN-tilstand. Alt, hvad folk forventer af en Linux-container — en privat netværksstak, et filtreret filsystem, ressourcegrænser — kommer fra andre mekanismer, som launcheren måske eller måske ikke har brugt.
Derfor besvarer påstande om, at en chroot isolerer en VPN, normalt det forkerte spørgsmål. Det relevante spørgsmål er, hvilket navnerum processen kører i, og hvilket SELinux-domæne den er begrænset til, og begge er egenskaber ved, hvordan den blev startet, ikke ved ordet chroot.
TUN kræver tre ting, og en enhedsknude er kun én
En traditionel brugertunntunnel kræver en TUN-enhed, den kan åbne, kernestøtte til enheden og tilladelse til at konfigurere interfacet og ruterne. Det er separate krav, og oprettelsen af et stinavn under /dev opfylder ikke noget af dem i sig selv:
ls -l /dev/net/tun
ip tuntap add dev tun0 mode tun
På Android er TUN-støtte normalt kompileret ind i kernen, fordi platformens egen VPN-tjeneste bruger den, men det betyder ikke, at din proces må bruge den. Interfacekonfiguration kræver netværksadministrationskompetencen, og SELinux afgør, om processen overhovedet må nå enhedsknuden. En afvisning ligner en tilladelsesfejl uden oplagt årsag, og svaret findes i revisionssporet:
dmesg | grep avc
logcat -d | grep "avc: denied"
Root løser ikke dette. SELinux begrænser processer, der kører som uid 0, præcis som den begrænser andre, så en chroot startet fra en root-shell kan stadig blive nægtet en enhed, den kan se. At slå håndhævelsen fra for at få en gammel installer til at virke er en beslutning for hele telefonen med konsekvenser langt ud over tunnelen, og det er ikke en rettelse af en forældet binær.
Hvorfor Androids apps ignorerer din tunnel
Androids understøttede model er en VPN-app, der registrerer sig via platformens VPN-tjeneste, beder brugeren om samtykke én gang og modtager en fildeskriptor til sin tunnel. Platformen sender derefter trafik ind i den deskriptor og håndhæver det app-område, brugeren eller administratoren valgte, og derfor kan samme mekanisme være pr. app, pr. profil og kombineret med altid-til og blokering uden VPN. Androids udviklervejledning til VPN beskriver det handshake, og det centrale er, at det er en registrering, ikke et routingtrick.
En daemon inde i en chroot registrerer sig aldrig. Der er ingen samtykkedialog, intet nøgleikon i statuslinjen, ingen medtag- eller udelad-liste pr. app og ingen deltagelse i altid-til-politikken. Apps bruger derfor fortsat standardnetværket, og tunnelen bærer kun det, shellen selv sender.
Den anden vej hjælper heller ikke. At skubbe ruter ind i værtens navnerum opfanger alt, også trafik som platformen forventede at holde lokalt, og det gør det uden styring pr. app og uden at brugeren kan se eller tilbagekalde det. Der findes ingen melleminstilling, hvor en chroot-daemon router trafik for kun én app.
Binær kompatibilitet er en separat mur
Selv når netværkssiden er interessant, har den kørende fil sine egne krav: CPU-arkitektur, den dynamiske loader, C-biblioteket og de kernemuligheder, den forventer. Android bruger bionic frem for glibc, og en gammel binær bygget til en desktopdistribution kan kræve biblioteker, der ikke findes på enheden længere.
At linke et biblioteksfilnavn til en nyere version skaber ikke ABI-kompatibilitet, og et arkiveret kryptografibibliotek fra en ti år gammel pakke er ikke en vedligeholdt komponent. Hvis planen afhænger af det, er planen at køre uvedligeholdt kode med netværksrettigheder på en telefon.
Bevis det i Android-konteksten, og ryd op bagefter
Test det, du reelt har brug for, fra den side, der betyder noget: åbn den konkrete app, nå den konkrete private destination, bekræft hvilken resolver der svarede, afbryd derefter tunnelen og bekræft den dokumenterede adfærd. Et resultat fra en terminal inde i chrooten er bevis om den terminals kørselskontekst og intet mere.
Hvis du ændrede værtsruter under eksperimentet, så gendan dem og noter, hvad du ændrede. Tjek derefter, om telefonen har en altid-til VPN konfigureret, fordi et ældre eksperiment, der efterlod en regel, kan se ud som en platformfejl måneder senere.
Til et reelt fjernadgangsbehov brug tjenestens understøttede klient eller et godkendt gatewaydesign. Spørgsmålet værd at stille er ikke, om en root-installer kan bringes til at køre, men om en understøttet implementering bærer de apps, du har brug for, over den grænse, du tilsigtede, uden at efterlade ejerløse privilegerede ændringer på enheden.