Inicjacja dostawcy

Proces inicjalizacji ma prawie nieograniczone uprawnienia i używa skryptów wejściowych z obu partycji (systemowej i dostawcy), aby zainicjować system podczas procesu uruchamiania. Ten dostęp powoduje ogromną lukę w podziale systemu Treble/dostawcy, ponieważ skrypty dostawcy mogą zlecać initowi dostęp do plików, właściwości itp., które nie są częścią stabilnego interfejsu binarnego aplikacji dostawcy systemu (ABI).

Inicjacja dostawcy ma na celu załatanie tej luki za pomocą osobnej domeny vendor_init z systemem SELinux (system zabezpieczeń wzmocnionych przez Linuxa) do wykonywania poleceń znajdujących się w /vendor z uprawnieniami dostępu określonymi przez dostawcę.

Mechanizm

Na początku procesu uruchamiania dostawca funkcja init tworzy proces podrzędny init w kontekście SELinux u:r:vendor_init:s0. Ten kontekst SELinux ma znacznie mniej uprawnień niż domyślny kontekst init, a jego dostęp jest ograniczony do plików, właściwości itp., które są specyficzne dla dostawcy lub są częścią stabilnego ABI dostawcy systemu.

Funkcja init sprawdza każdy wczytywany skrypt, aby sprawdzić, czy jego ścieżka zaczyna się od /vendor. Jeśli tak, oznacza go tagiem wskazującym, że jego polecenia muszą być wykonywane w kontekście init dostawcy. Każda wbudowana funkcja init jest opatrzona adnotacją typu boolean, która określa, czy polecenie musi być wykonywane w podprocesie init dostawcy:

  • Większość poleceń, które uzyskują dostęp do systemu plików, jest oznaczona jako polecenia do wykonania w podprocesie init dostawcy, dlatego podlegają polityce SEPolicy dostawcy.
  • Większość poleceń, które wpływają na stan wewnętrznego procesu inicjowania (np. uruchamianie i zatrzymywanie usług), jest wykonywana w ramach normalnego procesu inicjowania. Te polecenia są wykonywane, gdy skrypt dostawcy wywołuje je w celu obsługi uprawnień niebędących SELinux.

Główna pętla przetwarzania init zawiera sprawdzanie, czy polecenie jest oznaczone do uruchomienia w podprocesie dostawcy i pochodzi ze skryptu dostawcy. Jeśli tak, jest ono wysyłane za pomocą komunikacji między procesami (IPC) do podprocesu init dostawcy, który wykonuje polecenie i przesyła wynik z powrotem do init.

Używanie funkcji vendor init

Inicjacja dostawcy jest domyślnie włączona, a jej ograniczenia mają zastosowanie do wszystkich skryptów inicjujących znajdujących się w partycji /vendor. Inicjacja dostawcy powinna być przejrzysta dla dostawców, których skrypty nie mają dostępu do plików, właściwości itp. tylko dla systemu.

Jeśli jednak polecenia w danym skrypcie dostawcy naruszają ograniczenia inicjalizacji dostawcy, nie są one wykonywane. Polecenia, które nie działają, mają w logu jądra (widocznym za pomocą polecenia dmesg) wiersz z init, który wskazuje na błąd. Kontrola SELinux towarzyszy każdemu poleceniu, które nie zostało wykonane z powodu zasad SELinux. Przykład błędu obejmującego kontrolę SELinux:

type=1400 audit(1511821362.996:9): avc: denied { search } for pid=540 comm="init" name="nfc" dev="sda45" ino=1310721 scontext=u:r:vendor_init:s0 tcontext=u:object_r:nfc_data_file:s0 tclass=dir permissive=0
init: Command 'write /data/nfc/bad_file_access 1234' action=boot (/vendor/etc/init/hw/init.walleye.rc:422) took 2ms and failed: Unable to write to file '/data/nfc/bad_file_access': open() failed: Permission denied

Jeśli polecenie się nie powiedzie, masz 2 opcje:

  • Jeśli polecenie nie działa z powodu zamierzonego ograniczenia (np. gdy polecenie uzyskuje dostęp do pliku lub właściwości systemowej), należy je ponownie zaimplementować w sposób zgodny z Treble, korzystając tylko ze stabilnych interfejsów. Reguły Neverallow uniemożliwiają dodawanie uprawnień do plików systemowych, które nie są częścią stabilnego ABI dostawcy systemu.
  • Jeśli etykieta SELinux jest nowa i nie ma jeszcze przyznanych uprawnień w systemie vendor_init.te ani nie jest wykluczona w regułach neverallow, nowa etykieta może otrzymać uprawnienia w vendor_init.te.

W przypadku urządzeń uruchamianych przed Androidem 9 reguły neverallows można pominąć, dodając atrybut data_between_core_and_vendor_violators type do pliku vendor_init.te konkretnego urządzenia.

Lokalizacje kodu

Większość logiki dla IPC inicjalizacji dostawcy znajduje się w pliku system/core/init/subcontext.cpp.

Tabela poleceń znajduje się w klasie BuiltinFunctionMap w pliku system/core/init/builtins.cpp i zawiera adnotacje wskazujące, czy polecenie musi być wykonywane w podprocesie init dostawcy.

SEPolicy dla vendor_init jest podzielony na katalogi prywatne (system/sepolicy/private/vendor_init.te) i publiczne (system/sepolicy/public/vendor_init.te) w katalogu system/sepolicy.