Android chroot VPN: vì sao đường hầm chạy được mà ứng dụng lại phớt lờ nó
Chroot chỉ đổi cách tra cứu đường dẫn, không đổi nhân, không gian tên mạng hay việc đăng ký VPN của Android. Từ đó có hai kết quả, và cả hai đều khiến người ta bất ngờ.
Bạn dựng một bản phân phối Linux chạy dưới chroot trên điện thoại, cài một ứng dụng khách VPN vào đó, và shell thông báo đường hầm đã xong. Rồi bạn chuyển sang trình duyệt và lưu lượng vẫn đi ra qua dữ liệu di động như chưa có gì xảy ra. Hoặc ngược lại: mọi ứng dụng trên máy mất kết nối vì ứng dụng khách đã đặt tuyến mặc định vào không gian tên mà Android thực sự dùng. Hai triệu chứng này đến từ cùng một mảnh thiếu, và không cái nào là lỗi của ứng dụng khách VPN.
Shell báo đã kết nối, ứng dụng không đồng ý
Kết quả thứ nhất là trường hợp phổ biến. Một đường hầm trong không gian người dùng mở từ chroot có thể hoàn tất bắt tay, in thống kê và chở lưu lượng do chính shell đó tạo ra, trong khi các ứng dụng Android vẫn dùng mạng mặc định của điện thoại. Không có gì chặn chúng, vì không có gì báo cho Android biết là có VPN.
Kết quả thứ hai là trường hợp nguy hiểm. Nếu chroot chia sẻ không gian tên mạng của Android, điều mặc định vẫn xảy ra, một tiến trình đủ quyền có thể thêm tuyến và giao diện TUN ảnh hưởng tới toàn bộ điện thoại. Khi đó đường hầm chạy cho mọi ứng dụng, kể cả những ứng dụng bạn không định đưa vào, và kết nối của máy giờ phụ thuộc vào một tiến trình nền không có quản lý vòng đời, không có chỉ báo kết nối và không có chính sách luôn bật.
Bạn rơi vào trường hợp nào có thể trả lời bằng một lệnh. So sánh ip route bên trong chroot với cùng lệnh đó từ một shell Android bên ngoài. Kết quả giống hệt nghĩa là chroot nằm trong không gian tên của máy chủ: mọi thay đổi mạng nó làm đều áp cho toàn bộ điện thoại. Kết quả khác nghĩa là trình khởi chạy đã tạo một không gian tên riêng cho nó, và đường hầm của nó vốn dĩ vô hình với Android.
Chroot đã đổi gì và không đổi gì
| 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 |
Lời gọi hệ thống chroot làm đúng một việc: đổi thư mục dùng để phân giải tên đường dẫn. Trang man nói rõ đó không phải ranh giới bảo mật, và không nói gì về giao diện, tuyến hay trạng thái VPN. Mọi thứ người ta mong đợi ở một container Linux — ngăn xếp mạng riêng, hệ thống tệp đã lọc, giới hạn tài nguyên — đều đến từ cơ chế khác mà trình khởi chạy có thể đã dùng hoặc không.
Vì thế những khẳng định rằng chroot cô lập một VPN thường trả lời sai câu hỏi. Câu hỏi đúng là tiến trình chạy trong không gian tên nào và bị giới hạn trong miền SELinux nào, và cả hai là thuộc tính của cách nó được khởi chạy, không phải của chữ chroot.
TUN cần ba thứ, và nút thiết bị chỉ là một
Một đường hầm không gian người dùng kiểu truyền thống cần một thiết bị TUN mở được, nhân hỗ trợ thiết bị đó, và quyền cấu hình giao diện cùng tuyến. Đó là những yêu cầu riêng rẽ, và việc tạo một tên đường dẫn dưới /dev tự nó không đáp ứng được yêu cầu nào:
ls -l /dev/net/tun
ip tuntap add dev tun0 mode tun
Trên Android nhân thường biên dịch sẵn hỗ trợ TUN, vì dịch vụ VPN của chính nền tảng dùng nó, nhưng điều đó không có nghĩa tiến trình của bạn được dùng. Cấu hình giao diện cần năng lực quản trị mạng, và SELinux quyết định tiến trình có chạm được nút thiết bị hay không. Một lần từ chối trông như lỗi quyền không rõ nguyên nhân, và câu trả lời nằm trong nhật ký kiểm toán:
dmesg | grep avc
logcat -d | grep "avc: denied"
Root không giải quyết được điều này. SELinux giới hạn tiến trình chạy với uid 0 y như các tiến trình khác, nên một chroot khởi chạy từ shell root vẫn có thể bị từ chối một thiết bị mà nó nhìn thấy. Tắt cưỡng chế để một trình cài đặt cũ chạy được là quyết định cho toàn bộ điện thoại với hậu quả vượt xa đường hầm, và đó không phải cách sửa một tệp nhị phân đã cũ.
Vì sao ứng dụng Android phớt lờ đường hầm của bạn
Mô hình được Android hỗ trợ là một ứng dụng VPN đăng ký qua dịch vụ VPN của nền tảng, xin người dùng đồng ý một lần và nhận một bộ mô tả tệp cho đường hầm của mình. Nền tảng sau đó đưa lưu lượng vào bộ mô tả đó và thực thi phạm vi ứng dụng mà người dùng hoặc quản trị viên đã chọn, nhờ vậy cùng một cơ chế có thể theo từng ứng dụng, từng hồ sơ và kết hợp với thiết lập luôn bật cùng chặn khi không có VPN. Hướng dẫn phát triển VPN của Android mô tả lần bắt tay đó, và điểm mấu chốt là đó là đăng ký, không phải mẹo định tuyến.
Một tiến trình nền bên trong chroot không bao giờ đăng ký. Không có hộp thoại đồng ý, không có biểu tượng chìa khóa trên thanh trạng thái, không có danh sách bao gồm hay loại trừ theo ứng dụng, và không tham gia chính sách luôn bật. Vì vậy ứng dụng vẫn dùng mạng mặc định, và đường hầm chỉ chở những gì chính shell gửi đi.
Đi theo hướng ngược lại cũng không giúp. Đẩy tuyến vào không gian tên của máy chủ sẽ bắt tất cả, kể cả lưu lượng mà nền tảng định giữ cục bộ, và làm vậy không có kiểm soát theo ứng dụng và không có cách để người dùng thấy hay thu hồi. Không có thiết lập trung gian nơi tiến trình nền chroot chỉ định tuyến cho một ứng dụng.
Tương thích nhị phân là bức tường riêng
Kể cả khi phía mạng thú vị, tệp thực thi có yêu cầu riêng: kiến trúc CPU, bộ nạp động, thư viện C, và các khả năng nhân mà nó mong đợi. Android dùng bionic chứ không phải glibc, và một tệp nhị phân cũ xây cho bản phân phối máy để bàn có thể cần những thư viện không còn trên thiết bị.
Liên kết tượng trưng tên tệp thư viện sang phiên bản mới hơn không tạo ra tương thích ABI, và một thư viện mật mã lưu trữ từ gói mười năm trước không phải thành phần được bảo trì. Nếu kế hoạch dựa vào đó, kế hoạch là chạy mã không được bảo trì với quyền mạng trên một chiếc điện thoại.
Chứng minh trong bối cảnh Android rồi dọn dẹp
Hãy thử đúng thứ bạn quan tâm, từ phía có ý nghĩa: mở ứng dụng cụ thể, đến đích riêng cụ thể, xác nhận bộ phân giải nào đã trả lời, rồi ngắt đường hầm và xác nhận hành vi đã được ghi trong tài liệu. Kết quả từ một terminal bên trong chroot chỉ là bằng chứng về bối cảnh thực thi của terminal đó và không hơn.
Nếu bạn đã đổi tuyến của máy chủ trong lúc thử nghiệm, hãy hoàn lại và ghi lại những gì đã đổi. Sau đó kiểm tra xem điện thoại có cấu hình VPN luôn bật hay không, vì một thử nghiệm cũ để lại một quy tắc có thể trông như lỗi nền tảng sau nhiều tháng.
Với nhu cầu truy cập từ xa thật, hãy dùng ứng dụng khách được dịch vụ hỗ trợ hoặc một thiết kế cổng được phê duyệt. Câu hỏi đáng đặt ra không phải là có chạy được một trình cài đặt đã root hay không, mà là một triển khai được hỗ trợ có đưa những ứng dụng bạn cần qua đúng ranh giới bạn định hay không, mà không để lại trên thiết bị những thay đổi đặc quyền vô chủ.