Android chroot VPN: de ce tunelul funcționează, iar aplicațiile îl ignoră
Chroot schimbă doar căutarea căilor, nu kernelul, spațiul de nume al rețelei sau înregistrarea VPN din Android. De aici rezultă două situații, și ambele surprind oamenii.
Pornești o distribuție Linux sub chroot pe telefon, instalezi un client VPN în ea, iar shell-ul anunță că tunelul e gata. Apoi treci la browser și traficul iese prin datele mobile ca și cum nimic nu s-ar fi întâmplat. Sau invers: fiecare aplicație de pe telefon pierde conectivitatea pentru că clientul a instalat o rută implicită în spațiul de nume pe care Android îl folosește de fapt. Ambele simptome vin din aceeași piesă lipsă, și niciunul nu este un defect al clientului VPN.
Shell-ul spune conectat, aplicațiile nu sunt de acord
Primul rezultat este cel obișnuit. Un tunel în spațiul utilizatorului deschis din chroot poate finaliza handshake-ul, poate afișa statisticile și poate transporta traficul generat de același shell, în timp ce aplicațiile Android continuă să folosească rețeaua implicită a telefonului. Nimic nu le interceptează, pentru că nimic nu i-a spus Androidului că există un VPN.
Al doilea rezultat este cel periculos. Dacă chroot partajează spațiul de nume al rețelei Android, ceea ce face implicit, un proces cu privilegii suficiente poate adăuga rute și o interfață TUN care afectează întregul telefon. Atunci tunelul funcționează pentru fiecare aplicație, inclusiv pentru cele pe care nu intenționai să le rutezi, iar conectivitatea telefonului depinde acum de un demon fără gestionare a ciclului de viață, fără indicator de conexiune și fără politică de pornire permanentă.
Care dintre cele două ți-a ieșit se poate stabili cu o singură comandă. Compară ip route din interiorul chroot cu aceeași comandă dintr-un shell Android de afară. Ieșire identică înseamnă că chroot este în spațiul de nume al gazdei: orice modificare de rețea pe care o face se aplică întregului telefon. Ieșire diferită înseamnă că lansatorul a creat un spațiu de nume pentru el, iar tunelul său este invizibil pentru Android prin construcție.
Ce a schimbat chroot și ce nu
| 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 |
Apelul de sistem chroot face un singur lucru: schimbă directorul folosit pentru rezolvarea numelor de cale. Pagina man spune explicit că nu este o graniță de securitate și nu spune nimic despre interfețe, rute sau starea VPN. Tot ce oamenii așteaptă de la un container Linux — un stack de rețea privat, un sistem de fișiere filtrat, limite de resurse — vine din alte mecanisme pe care lansatorul le poate sau nu le poate fi folosit.
De aceea afirmațiile că chroot izolează un VPN răspund de obicei la întrebarea greșită. Întrebarea relevantă este în ce spațiu de nume rulează procesul și cărei domenii SELinux îi este restricționat, iar ambele sunt proprietăți ale modului în care a fost pornit, nu ale cuvântului chroot.
TUN are nevoie de trei lucruri, iar un nod de dispozitiv este doar unul
Un tunel tradițional în spațiul utilizatorului are nevoie de un dispozitiv TUN pe care îl poate deschide, de suport din kernel pentru acel dispozitiv și de permisiunea de a configura interfața și rutele. Acestea sunt cerințe separate, iar crearea unui nume de cale sub /dev nu le îndeplinește singură pe niciuna:
ls -l /dev/net/tun
ip tuntap add dev tun0 mode tun
Pe Android kernelul are de obicei suport TUN compilat, pentru că serviciul VPN al platformei îl folosește, dar asta nu înseamnă că procesul tău îl poate folosi. Configurarea interfeței cere capacitatea de administrare a rețelei, iar SELinux decide dacă procesul poate ajunge deloc la nodul de dispozitiv. O refuzare arată ca o eroare de permisiune fără cauză evidentă, iar răspunsul este în jurnalul de audit:
dmesg | grep avc
logcat -d | grep "avc: denied"
Root nu rezolvă asta. SELinux restricționează procesele care rulează ca uid 0 exact ca pe celelalte, așa că un chroot pornit dintr-un shell root poate primi în continuare refuz pentru un dispozitiv pe care îl vede. Dezactivarea aplicării forțate pentru ca un instalator vechi să funcționeze este o decizie pentru întregul telefon, cu consecințe mult dincolo de tunel, și nu este o reparație pentru un binar învechit.
De ce aplicațiile Android ignoră tunelul tău
Modelul acceptat de Android este o aplicație VPN care se înregistrează prin serviciul VPN al platformei, cere o singură dată consimțământul utilizatorului și primește un descriptor de fișier pentru tunelul său. Platforma direcționează apoi traficul în acel descriptor și aplică sfera de aplicații aleasă de utilizator sau administrator, motiv pentru care același mecanism poate fi per aplicație, per profil și combinat cu setările de pornire permanentă și blocare fără VPN. Ghidul de dezvoltare VPN pentru Android descrie acel handshake, iar punctul cheie este că este o înregistrare, nu un truc de rutare.
Un demon din interiorul chroot nu se înregistrează niciodată. Nu există dialog de consimțământ, nu există pictogramă cu cheie în bara de stare, nu există listă de includere sau excludere per aplicație și nicio participare la politica de pornire permanentă. Prin urmare aplicațiile continuă să folosească rețeaua implicită, iar tunelul transportă doar ce trimite shell-ul însuși.
Nici mersul în direcția cealaltă nu ajută. Împingerea rutelor în spațiul de nume al gazdei capturează tot, inclusiv traficul pe care platforma se aștepta să rămână local, și face asta fără control per aplicație și fără ca utilizatorul să poată vedea sau revoca. Nu există o setare de mijloc în care un demon chroot să ruteze traficul pentru o singură aplicație.
Compatibilitatea binară este un zid separat
Chiar și când partea de rețea este interesantă, executabilul are cerințele sale: arhitectura CPU, loader-ul dinamic, biblioteca C și facilitățile de kernel pe care le așteaptă. Android folosește bionic, nu glibc, iar un binar vechi construit pentru o distribuție desktop poate avea nevoie de biblioteci care nu mai există pe dispozitiv.
Legarea simbolică a numelui unui fișier de bibliotecă la o versiune mai nouă nu creează compatibilitate ABI, iar o bibliotecă criptografică arhivată dintr-un pachet vechi de un deceniu nu este o componentă întreținută. Dacă planul depinde de asta, planul este să rulezi cod neîntreținut cu privilegii de rețea pe un telefon.
Demonstrează în contextul Android și curăță după
Testează ce te interesează cu adevărat, din partea care contează: deschide aplicația specifică, ajunge la destinația privată specifică, confirmă care resolver a răspuns, apoi deconectează tunelul și confirmă comportamentul documentat. Un rezultat dintr-un terminal din interiorul chroot este dovadă despre contextul de execuție al acelui terminal și nimic mai mult.
Dacă ai modificat rute ale gazdei în timpul experimentelor, pune-le la loc și notează ce ai schimbat. Apoi verifică dacă telefonul are configurat un VPN cu pornire permanentă, pentru că un experiment mai vechi care a lăsat o regulă poate părea o defecțiune a platformei luni mai târziu.
Pentru o nevoie reală de acces de la distanță, folosește clientul acceptat al serviciului sau un proiect de gateway aprobat. Întrebarea care merită pusă nu este dacă un instalator cu root poate fi făcut să ruleze, ci dacă o implementare acceptată duce aplicațiile de care ai nevoie dincolo de granița pe care ai intenționat-o, fără a lăsa pe dispozitiv modificări privilegiate fără proprietar.