Android chroot VPN: ทำไมอุโมงค์ทำงานได้ แต่แอปไม่สนใจมัน
chroot เปลี่ยนเพียงการค้นหาพาธ ไม่ใช่เคอร์เนล เนมสเปซเครือข่าย หรือการลงทะเบียน VPN ของ Android ผลลัพธ์สองอย่างจึงตามมา และทั้งสองก็ทำให้คนประหลาดใจ
คุณเอาการติดตั้ง Linux ไปรันใต้ chroot บนโทรศัพท์ ติดตั้งไคลเอนต์ VPN ไว้ข้างใน แล้วเชลล์ก็ประกาศว่าอุโมงค์เสร็จแล้ว จากนั้นคุณสลับไปที่เบราว์เซอร์ และทราฟฟิกก็ออกไปทางข้อมูลมือถือราวกับไม่มีอะไรเกิดขึ้น หรือตรงกันข้าม: ทุกแอปบนโทรศัพท์สูญเสียการเชื่อมต่อ เพราะไคลเอนต์ใส่เส้นทางเริ่มต้นไว้ในเนมสเปซที่ Android ใช้งานจริง อาการทั้งสองมาจากชิ้นส่วนที่หายไปชิ้นเดียวกัน และไม่มีอันไหนเป็นบั๊กของไคลเอนต์ VPN
เชลล์บอกว่าเชื่อมต่อแล้ว แอปไม่เห็นด้วย
ผลลัพธ์แรกคืออันที่พบบ่อย อุโมงค์ในพื้นที่ผู้ใช้ที่เปิดจาก chroot สามารถจบแฮนด์เชก พิมพ์สถิติ และ ขนส่งทราฟฟิกที่เชลล์เดียวกันสร้างขึ้น ขณะที่แอปของ Android ยังคงใช้เครือข่ายเริ่มต้นของโทรศัพท์ ไม่มีอะไรดักจับพวกมัน เพราะไม่มีอะไรบอก Android ว่ามี VPN อยู่
ผลลัพธ์ที่สองคืออันที่อันตราย หาก chroot แชร์เนมสเปซเครือข่ายของ Android ซึ่งเป็นค่าเริ่มต้น กระบวนการที่มีสิทธิ์เพียงพอสามารถเพิ่มเส้นทางและอินเทอร์เฟซ TUN ที่ส่งผลต่อโทรศัพท์ทั้งเครื่องได้ จากนั้นอุโมงค์ก็ทำงานกับทุกแอป รวมถึงแอปที่คุณไม่ได้ตั้งใจจะส่งผ่าน และการเชื่อมต่อของโทรศัพท์ก็ขึ้นอยู่กับเดมอนที่ไม่มีการจัดการวงจรชีวิต ไม่มีตัวบ่งชี้การเชื่อมต่อ และไม่มีนโยบายเปิดตลอดเวลา
คุณได้แบบไหนสามารถตอบได้ด้วยคำสั่งเดียว เปรียบเทียบ ip route ภายใน chroot กับคำสั่งเดียวกันจากเชลล์ Android ภายนอก ถ้าเอาต์พุตเหมือนกัน แปลว่า chroot อยู่ในเนมสเปซของโฮสต์: การเปลี่ยนแปลงเครือข่ายใด ๆ ที่มันทำมีผลกับโทรศัพท์ทั้งเครื่อง ถ้าเอาต์พุตต่างกัน แปลว่าตัวเรียกใช้สร้างเนมสเปซให้มัน และอุโมงค์ของมันมองไม่เห็นจาก Android โดยโครงสร้าง
chroot เปลี่ยนอะไรและไม่เปลี่ยนอะไร
| 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 |
ระบบคอล chroot ทำสิ่งเดียว: เปลี่ยนไดเรกทอรีที่ใช้ในการแปลงชื่อพาธ หน้าคู่มือระบุชัดเจนว่ามันไม่ใช่ขอบเขตความปลอดภัย และไม่พูดถึงอินเทอร์เฟซ เส้นทาง หรือสถานะ VPN เลย ทุกสิ่งที่ผู้คนคาดหวังจากคอนเทนเนอร์ Linux — สแตกเครือข่ายส่วนตัว ระบบไฟล์ที่ถูกกรอง ขีดจำกัดทรัพยากร — มาจากกลไกอื่นที่ตัวเรียกใช้อาจใช้หรือไม่ใช้ก็ได้
นั่นคือเหตุผลที่ข้ออ้างว่า chroot แยก VPN มักตอบคำถามผิด คำถามที่เกี่ยวข้องคือกระบวนการรันในเนมสเปซใดและถูกจำกัดในโดเมน SELinux ใด และทั้งสองเป็นคุณสมบัติของการเริ่มต้น ไม่ใช่ของคุณสมบัติของคำว่า chroot
TUN ต้องการสามอย่าง และโหนดอุปกรณ์เป็นเพียงหนึ่ง
อุโมงค์ในพื้นที่ผู้ใช้แบบดั้งเดิมต้องการอุปกรณ์ TUN ที่เปิดได้ การสนับสนุนเคอร์เนลสำหรับอุปกรณ์นั้น และสิทธิ์ในการกำหนดค่าอินเทอร์เฟซและเส้นทาง สิ่งเหล่านี้เป็นข้อกำหนดแยกกัน และการสร้างชื่อพาธใต้ /dev ไม่ได้ตอบสนองข้อใดเลยด้วยตัวเอง:
ls -l /dev/net/tun
ip tuntap add dev tun0 mode tun
บน Android เคอร์เนลมักคอมไพล์การสนับสนุน TUN ไว้ เพราะบริการ VPN ของแพลตฟอร์มเองใช้มัน แต่นั่นไม่ได้หมายความว่ากระบวนการของคุณใช้ได้ การกำหนดค่าอินเทอร์เฟซต้องใช้ความสามารถในการบริหารเครือข่าย และ SELinux ตัดสินว่ากระบวนการเข้าถึงโหนดอุปกรณ์ได้หรือไม่ การปฏิเสธดูเหมือนข้อผิดพลาดด้านสิทธิ์ที่ไม่มีสาเหตุชัดเจน และคำตอบอยู่ในบันทึกการตรวจสอบ:
dmesg | grep avc
logcat -d | grep "avc: denied"
Root ไม่แก้ปัญหานี้ SELinux จำกัดกระบวนการที่รันเป็น uid 0 เช่นเดียวกับกระบวนการอื่น ดังนั้น chroot ที่เริ่มจากเชลล์ root ก็ยังอาจถูกปฏิเสธอุปกรณ์ที่มันมองเห็นได้ การปิดการบังคับใช้เพื่อให้ตัวติดตั้งเก่าทำงานเป็นการตัดสินใจทั้งเครื่องซึ่งมีผลไกลเกินกว่าอุโมงค์ และไม่ใช่การแก้ไขไบนารีที่ล้าสมัย
ทำไมแอป Android มองข้ามอุโมงค์ของคุณ
รูปแบบที่ Android สนับสนุนคือแอป VPN ที่ลงทะเบียนผ่านบริการ VPN ของแพลตฟอร์ม ขอความยินยอมจากผู้ใช้หนึ่งครั้ง และได้รับไฟล์ดีสคริปเตอร์สำหรับอุโมงค์ของตน จากนั้นแพลตฟอร์มกำหนดเส้นทางทราฟฟิกเข้าไปในดีสคริปเตอร์นั้นและบังคับขอบเขตแอปที่ผู้ใช้หรือผู้ดูแลเลือก นั่นคือเหตุผลที่กลไกเดียวกันทำเป็นรายแอป รายโปรไฟล์ และรวมกับการตั้งค่าเปิดตลอดเวลาและการบล็อกเมื่อไม่มี VPN ได้ คู่มือการพัฒนา VPN ของ Android อธิบายแฮนด์เชกนั้น และประเด็นสำคัญคือมันเป็นการลงทะเบียน ไม่ใช่กลอุบายการกำหนดเส้นทาง
เดมอนภายใน chroot ไม่เคยลงทะเบียน ไม่มีไดอะล็อกขอความยินยอม ไม่มีไอคอนกุญแจบนแถบสถานะ ไม่มีรายการรวมหรือยกเว้นรายแอป และไม่มีส่วนร่วมในนโยบายเปิดตลอดเวลา แอปจึงยังคงใช้เครือข่ายเริ่มต้น และอุโมงค์ขนส่งเพียงสิ่งที่เชลล์เองส่งออกไป
การไปทางอื่นก็ไม่ช่วย การดันเส้นทางเข้าเนมสเปซของโฮสต์จับทุกอย่าง รวมถึงทราฟฟิกที่แพลตฟอร์มคาดว่าจะคงไว้ในเครื่อง และทำโดยไม่มีการควบคุมรายแอปและไม่มีทางให้ผู้ใช้เห็นหรือเพิกถอน ไม่มีการตั้งค่าตรงกลางที่เดมอน chroot กำหนดเส้นทางให้แอปเดียวเท่านั้น
ความเข้ากันได้ของไบนารีเป็นกำแพงอีกด้าน
แม้ฝั่งเครือข่ายจะน่าสนใจ ไฟล์ปฏิบัติการก็มีข้อกำหนดของตัวเอง: สถาปัตยกรรม CPU ตัวโหลดแบบไดนามิก ไลบรารี C และความสามารถของเคอร์เนลที่มันคาดหวัง Android ใช้ bionic ไม่ใช่ glibc และไบนารีเก่าที่สร้างสำหรับดิสทริบิวชันเดสก์ท็อปอาจต้องใช้ไลบรารีที่ไม่มีอยู่ในอุปกรณ์แล้ว
การลิงก์ชื่อไฟล์ไลบรารีไปยังเวอร์ชันใหม่ไม่ได้สร้างความเข้ากันได้ของ ABI และไลบรารีการเข้ารหัสที่เก็บถาวรจากแพ็กเกจเมื่อสิบปีก่อนก็ไม่ใช่ส่วนประกอบที่ได้รับการดูแล หากแผนพึ่งพาสิ่งนั้น แผนก็คือการรันโค้ดที่ไม่ได้รับการดูแลด้วยสิทธิ์เครือข่ายบนโทรศัพท์
พิสูจน์ในบริบทของ Android แล้วทำความสะอาด
ทดสอบสิ่งที่คุณสนใจจริง ๆ จากด้านที่สำคัญ: เปิดแอปที่ระบุ ไปถึงปลายทางส่วนตัวที่ระบุ ยืนยันว่าตัวแปลงใดตอบ จากนั้นตัดการเชื่อมต่ออุโมงค์และยืนยันพฤติกรรมที่เอกสารระบุ ผลลัพธ์จากเทอร์มินัลภายใน chroot เป็นหลักฐานเกี่ยวกับบริบทการทำงานของเทอร์มินัลนั้นเท่านั้น ไม่มากกว่านั้น
หากคุณเปลี่ยนเส้นทางของโฮสต์ระหว่างทดลอง ให้คืนค่าและบันทึกว่าคุณเปลี่ยนอะไร จากนั้นตรวจสอบว่าโทรศัพท์มีการตั้งค่า VPN เปิดตลอดเวลาหรือไม่ เพราะการทดลองเก่าที่ทิ้งกฎไว้สามารถดูเหมือนความผิดพลาดของแพลตฟอร์มในอีกหลายเดือนต่อมา
สำหรับความต้องการเข้าถึงจากระยะไกลจริง ๆ ให้ใช้ไคลเอนต์ที่บริการสนับสนุนหรือการออกแบบเกตเวย์ที่ได้รับอนุมัติ คำถามที่ควรถามไม่ใช่ตัวติดตั้งที่รูทแล้วจะรันได้หรือไม่ แต่คือการใช้งานที่ได้รับการสนับสนุนพาแอปที่คุณต้องการข้ามพรมแดนที่คุณตั้งใจไว้หรือไม่ โดยไม่ทิ้งการเปลี่ยนแปลงที่มีสิทธิ์ซึ่งไม่มีเจ้าของไว้ในอุปกรณ์