Dyskrecjonalna kontrola dostępu (DAC)

Obiekty i usługi systemu plików dodane do kompilacji często wymagają oddzielnych, unikalnych identyfikatorów, zwanych identyfikatorami Androida (AID). Obecnie wiele zasobów, takich jak pliki i usługi, niepotrzebnie korzysta z identyfikatorów AID zdefiniowanych przez Androida. W wielu przypadkach można zamiast nich używać identyfikatorów AID zdefiniowanych przez producenta OEM.

Starsze wersje Androida (7.x i starsze) rozszerzały mechanizm identyfikatorów AID za pomocą pliku android_filesystem_config.h specyficznego dla urządzenia, aby określać możliwości systemu plików lub niestandardowe identyfikatory AID OEM. Ten system był jednak nieintuicyjny, ponieważ nie obsługiwał używania przyjaznych nazw w przypadku identyfikatorów AID OEM, co wymagało podawania surowych wartości liczbowych w polach użytkownika i grupy bez możliwości powiązania przyjaznej nazwy z identyfikatorem AID.

Nowsze wersje Androida (8.0 i nowsze) obsługują nową metodę rozszerzania możliwości systemu plików. Ta nowa metoda obsługuje:

  • Wiele lokalizacji źródłowych plików konfiguracji (umożliwia rozszerzalne konfiguracje kompilacji).
  • Sprawdzanie poprawności wartości OEM AID w czasie kompilacji.
  • Generowanie niestandardowego nagłówka OEM AID, którego można w razie potrzeby używać w plikach źródłowych.
  • Powiązanie nazwy przyjaznej z rzeczywistą wartością AID OEM. Obsługuje argumenty w postaci ciągów znaków nienumerycznych dla użytkowników i grup, np. „foo” zamiast „2901”.

Dodatkowe ulepszenia obejmują usunięcie tablicy android_ids[] z system/core/libcutils/include/private/android_filesystem_config.h. Ta tablica jest teraz w Bionic w pełni prywatną tablicą wygenerowaną z akcesorami z getpwnam()getgrnam(). (Skutkiem ubocznym jest tworzenie stabilnych plików binarnych, ponieważ modyfikowane są podstawowe identyfikatory AID). Narzędzia i plik README z dodatkowymi informacjami znajdziesz w build/make/tools/fs_config.

Dodawanie identyfikatorów Androida (AID)

W Androidzie 8.0 usunięto tablicę android_ids[] z projektu Android Open Source (AOSP). Wszystkie nazwy przyjazne dla AID są generowane z pliku nagłówkowego system/core/libcutils/include/private/android_filesystem_config.h podczas generowania tablicy Bionic android_ids[]. Każde definedopasowanieAID_* jest wykrywane przez narzędzie, a * staje się nazwą zapisaną małymi literami.

Na przykład w przypadku private/android_filesystem_config.h:

#define AID_SYSTEM 1000

Zmienia się w:

  • Przyjazna nazwa: system
  • uid: 1000
  • gid: 1000

Aby dodać nowy podstawowy identyfikator AID AOSP, po prostu dodaj #define do pliku nagłówkowego android_filesystem_config.h. Identyfikator AID jest generowany podczas kompilacji i udostępniany interfejsom, które używają argumentów użytkownika i grupy. Narzędzie sprawdza, czy nowy identyfikator AID nie mieści się w zakresach APP ani OEM. Uwzględnia też zmiany w tych zakresach i powinno automatycznie zmieniać konfigurację w przypadku zmian lub nowych zakresów zarezerwowanych przez producenta OEM.

Konfigurowanie identyfikatorów aplikacji

Aby włączyć nowy mechanizm identyfikatorów reklamowych, w pliku BoardConfig.mk ustaw wartość TARGET_FS_CONFIG_GEN. Ta zmienna zawiera listę plików konfiguracyjnych, dzięki czemu możesz w razie potrzeby dołączać pliki.

Zgodnie z konwencją pliki konfiguracji mają nazwę config.fs, ale w praktyce możesz użyć dowolnej nazwy. Pliki config.fs są w formacie ini ConfigParser języka Python i zawierają sekcję caps (do konfigurowania możliwości systemu plików) oraz sekcję AIDs (do konfigurowania identyfikatorów AID OEM).

Konfigurowanie sekcji limitów

Sekcja caps umożliwia ustawianie uprawnień systemu plików dla obiektów systemu plików w kompilacji (sam system plików musi też obsługiwać tę funkcję).

Uruchamianie stabilnej usługi jako użytkownik root w Androidzie powoduje błąd Compatibility Test Suite (CTS), dlatego poprzednie wymagania dotyczące zachowania możliwości podczas uruchamiania procesu lub usługi obejmowały skonfigurowanie możliwości, a następnie użycie setuid/setgid do uruchomienia odpowiedniego identyfikatora AID. Dzięki limitom możesz pominąć te wymagania i zlecić to jądru. Gdy kontrola zostanie przekazana do main(), Twój proces będzie już miał potrzebne uprawnienia, dzięki czemu usługa będzie mogła korzystać z użytkownika i grupy bez uprawnień roota (jest to preferowany sposób uruchamiania usług z uprawnieniami).

Sekcja limitów wykorzystuje tę składnię:

Sekcja Wartość Definicja
[path] Ścieżka systemu plików do skonfigurowania. Ścieżka kończąca się znakiem / jest traktowana jako katalog, w przeciwnym razie jest traktowana jako plik.

Określenie w różnych plikach wielu sekcji o tej samej wartości [path] jest błędem. W wersjach Pythona <= 3.2 ten sam plik może zawierać sekcje, które zastępują poprzednią sekcję. W Pythonie 3.2 jest ustawiony tryb ścisły.
mode Ósemkowy tryb pliku Prawidłowy tryb pliku w systemie ósemkowym składający się z co najmniej 3 cyfr. Jeśli podano wartość 3, jest ona poprzedzona zerem. W przeciwnym razie tryb jest używany w niezmienionej postaci.
user AID_<user> C define w przypadku prawidłowego identyfikatora AID lub nazwa przyjazna (np. akceptowane są zarówno AID_RADIO, jak i radio). Aby zdefiniować niestandardowy identyfikator aplikacji, zapoznaj się z sekcją Konfigurowanie identyfikatora aplikacji.
group AID_<group> Taki sam jak użytkownik.
caps cap* Nazwa zadeklarowana w bionic/libc/kernel/uapi/linux/capability.h bez początkowego znaku CAP_. Dozwolone są wielkie i małe litery. Limity mogą też być wartościami:
  • binarny (0b0101)
  • ósemkowy (0455)
  • int (42)
  • szesnastkowy (0xFF)
Poszczególne limity oddzielaj spacjami.

Przykład użycia znajdziesz w sekcji Korzystanie z funkcji systemu plików.

Konfigurowanie sekcji AID

Sekcja AID zawiera identyfikatory AID OEM i ma taką składnię:

Sekcja Wartość Definicja
[AID_<name>] <name> może zawierać znaki z tego zbioru: wielkie litery, cyfry i podkreślenia. Wersja pisana małymi literami jest używana jako nazwa przyjazna. Wygenerowany plik nagłówkowy do włączenia kodu używa dokładnego AID_<name>.

Błędem jest określenie wielu sekcji o tej samej wartości atrybutu AID_<name> (bez rozróżniania wielkości liter, z tymi samymi ograniczeniami co [path]).

<name> musi zaczynać się od nazwy partycji, aby nie powodować konfliktu z różnymi źródłami.
value <numer> Prawidłowy ciąg znaków liczbowych w stylu C (szesnastkowy, ósemkowy, binarny i dziesiętny).

Określenie wielu sekcji z tą samą opcją wartości jest błędem.

Opcje wartości muszą być określone w zakresie odpowiadającym partycji użytej w <name>. Lista prawidłowych partycji i odpowiadających im zakresów jest zdefiniowana w system/core/libcutils/include/private/android_filesystem_config.h. Dostępne opcje:
  • Partycja dostawcy
    • AID_OEM_RESERVED_START(2900) - AID_OEM_RESERVED_END(2999)
    • AID_OEM_RESERVED_2_START(5000) - AID_OEM_RESERVED_2_END(5999)
  • Partycja systemowa
    • AID_SYSTEM_RESERVED_START(6000) - AID_SYSTEM_RESERVED_END(6499)
  • Partycja ODM
    • AID_ODM_RESERVED_START(6500) - AID_ODM_RESERVED_END(6999)
  • Podział produktu
    • AID_PRODUCT_RESERVED_START(7000) - AID_PRODUCT_RESERVED_END(7499)
  • Partycja system_ext
    • AID_SYSTEM_EXT_RESERVED_START(7500) - AID_SYSTEM_EXT_RESERVED_END(7999)

Przykłady użycia znajdziesz w sekcjach Definiowanie nazw identyfikatorów AID OEMUżywanie identyfikatorów AID OEM.

Przykłady użycia

Poniższe przykłady pokazują, jak zdefiniować i używać identyfikatora AID OEM oraz jak włączyć funkcje systemu plików. Nazwy identyfikatorów AID OEM ([AID_name]) muszą zaczynać się od nazwy partycji, np. „vendor_”, aby nie powodować konfliktów z przyszłymi nazwami AOSP ani innymi partycjami.

Określanie nazw identyfikatorów AID OEM

Aby zdefiniować identyfikator AID OEM, utwórz plik config.fs i ustaw wartość identyfikatora AID. Na przykład w device/x/y/config.fs ustaw te wartości:

[AID_VENDOR_FOO]
value: 2900

Po utworzeniu pliku ustaw zmienną TARGET_FS_CONFIG_GEN i wskaż ją w BoardConfig.mk. Na przykład w przypadku device/x/y/BoardConfig.mk ustaw te wartości:

TARGET_FS_CONFIG_GEN += device/x/y/config.fs

Twój niestandardowy identyfikator AID może być teraz używany przez system w nowej kompilacji.

Korzystanie z urządzeń AID OEM

Aby użyć interfejsu AID OEM, w kodzie C umieść oemaids_headers w powiązanym pliku Makefile i dodaj #include "generated_oem_aid.h", a potem zacznij używać zadeklarowanych identyfikatorów. Na przykład w my_file.c dodaj ten kod:

#include "generated_oem_aid.h"


If (ipc->uid == AID_VENDOR_FOO) {
  // Do something
...

W powiązanym pliku Android.bp dodaj te informacje:

header_libs: ["oemaids_headers"],

Jeśli używasz pliku Android.mk, dodaj te informacje:

LOCAL_HEADER_LIBRARIES := oemaids_headers

Używanie przyjaznych nazw

W Androidzie 9 możesz używać przyjaznej nazwy w przypadku każdego interfejsu, który obsługuje nazwy AID. Na przykład:

  • W poleceniu chown w some/init.rc:
    chown vendor_foo /vendor/some/vendor_foo/file
    
  • servicesome/init.rc:
    service vendor_foo /vendor/bin/foo_service
        user vendor_foo
        group vendor_foo
    

Ponieważ wewnętrzne mapowanie nazwy przyjaznej na identyfikator UID jest wykonywane przez /vendor/etc/passwd/vendor/etc/group, partycja dostawcy musi być zamontowana.

Powiązywanie przyjaznych nazw

Android 9 obsługuje przypisywanie przyjaznej nazwy do rzeczywistej wartości AID OEM. W przypadku argumentów user i group możesz używać ciągów znaków nienumerycznych, czyli np. „vendor_foo” zamiast „2901”.

Konwertowanie identyfikatorów AID na przyjazne nazwy

W przypadku identyfikatorów AID OEM Android 8.x wymagał użycia oem_####getpwnam i podobnymi funkcjami, a także w miejscach, w których wyszukiwania są obsługiwane za pomocą getpwnam (np. w skryptach init). W Androidzie 9 możesz używać funkcji getpwnamgetgrnam w Bionic do konwertowania identyfikatorów Androida (AID) na przyjazne nazwy i odwrotnie.

Korzystanie z funkcji systemu plików

Aby włączyć funkcje systemu plików, utwórz sekcję caps w pliku config.fs. Na przykład w device/x/y/config.fs dodaj tę sekcję:

[system/bin/foo_service]
mode: 0555
user: AID_VENDOR_FOO
group: AID_SYSTEM
caps: SYS_ADMIN | SYS_NICE

Po utworzeniu pliku ustaw zmienną TARGET_FS_CONFIG_GEN tak, aby wskazywała ten plik w BoardConfig.mk. Na przykład w przypadku device/x/y/BoardConfig.mk ustaw te wartości:

TARGET_FS_CONFIG_GEN += device/x/y/config.fs

Gdy usługa vendor_foo jest wykonywana, zaczyna się od funkcji CAP_SYS_ADMINCAP_SYS_NICE bez wywołań setuidsetgid. Dodatkowo usługa vendor_foo nie potrzebuje już uprawnień setuidsetgid w zasadach SELinux i można je usunąć.

Konfigurowanie zastąpień (Android 6.x–7.x)

Android 6.0 przeniósł fs_config i powiązane definicje struktury (system/core/include/private/android_filesystem_config.h) do system/core/libcutils/fs_config.c, gdzie można je było aktualizować lub zastępować plikami binarnymi zainstalowanymi w /system/etc/fs_config_dirs/system/etc/fs_config_files. Używanie osobnych reguł dopasowywania i parsowania dla katalogów i plików (które mogą używać dodatkowych wyrażeń glob) umożliwiło Androidowi obsługę katalogów i plików w 2 różnych tabelach. Definicje struktury w system/core/libcutils/fs_config.c umożliwiały nie tylko odczytywanie katalogów i plików w czasie działania, ale też host mógł używać tych samych plików w czasie kompilacji do tworzenia obrazów systemu plików jako ${OUT}/system/etc/fs_config_dirs${OUT}/system/etc/fs_config_files.

Metoda zastępowania rozszerzania systemu plików została zastąpiona modułowym systemem konfiguracji wprowadzonym w Androidzie 8.0, ale w razie potrzeby możesz nadal używać starej metody. W kolejnych sekcjach znajdziesz szczegółowe informacje o tym, jak generować i dołączać pliki zastępujące oraz konfigurować system plików.

Generowanie plików zastępujących

Wyrównane pliki binarne /system/etc/fs_config_dirs i /system/etc/fs_config_files możesz wygenerować za pomocą narzędzia fs_config_generatebuild/tools/fs_config. Narzędzie korzysta z funkcji biblioteki libcutils (fs_config_generate()), aby zarządzać wymaganiami dotyczącymi DAC w buforze, i określa reguły dla pliku dołączanego, aby ujednolicić reguły DAC.

Aby go użyć, utwórz plik dołączany w device/vendor/device/android_filesystem_config.h, który będzie działać jako zastąpienie. Plik musi mieć format structure fs_path_config zdefiniowany w system/core/include/private/android_filesystem_config.h z następującymi inicjalizacjami struktury dla symboli katalogów i plików:

  • W przypadku katalogów użyj elementu android_device_dirs[].
  • W przypadku plików użyj android_device_files[].

Jeśli nie używasz elementów android_device_dirs[]android_device_files[], możesz zdefiniować elementy NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRSNO_ANDROID_FILESYSTEM_CONFIG_DEVICE_FILES (patrz przykład poniżej). Możesz też określić plik zastępujący, używając TARGET_ANDROID_FILESYSTEM_CONFIG_H w konfiguracji płyty z wymuszonym basename android_filesystem_config.h.

Uwzględnij pliki zastępujące

Aby uwzględnić pliki, upewnij się, że PRODUCT_PACKAGES zawiera fs_config_dirs lub fs_config_files, aby można było zainstalować je odpowiednio w lokalizacjach /system/etc/fs_config_dirs/system/etc/fs_config_files. System kompilacji wyszukuje niestandardowe android_filesystem_config.h$(TARGET_DEVICE_DIR), gdzie znajduje się BoardConfig.mk. Jeśli ten plik znajduje się w innym miejscu, ustaw zmienną konfiguracji płyty TARGET_ANDROID_FILESYSTEM_CONFIG_H, aby wskazywała tę lokalizację.

Konfigurowanie systemu plików

Aby skonfigurować system plików na urządzeniu z Androidem 6.0 lub nowszym:

  1. Utwórz plik $(TARGET_DEVICE_DIR)/android_filesystem_config.h.
  2. Dodaj fs_config_dirs lub fs_config_files do PRODUCT_PACKAGES w pliku konfiguracji tablicy (np. $(TARGET_DEVICE_DIR)/device.mk).

Przykład zastąpienia

Ten przykład pokazuje poprawkę zastępującą demona system/bin/glgps w celu dodania obsługi blokady wybudzania w katalogu device/vendor/device. Pamiętaj o tych kwestiach:

  • Każdy wpis struktury to tryb, uid, gid, możliwości i nazwa. system/core/include/private/android_filesystem_config.h jest automatycznie uwzględniany, aby udostępniać definicje #define w pliku manifestu (AID_ROOT, AID_SHELL, CAP_BLOCK_SUSPEND).
  • Sekcja android_device_files[] zawiera działanie, które w przypadku braku określenia powoduje zablokowanie dostępu do system/etc/fs_config_dirs. Stanowi to dodatkową ochronę DAC w przypadku braku treści dla zastąpień katalogu. Jest to jednak słaba ochrona. Jeśli ktoś ma kontrolę nad /system, zwykle może zrobić wszystko, co zechce.
diff --git a/android_filesystem_config.h b/android_filesystem_config.h
new file mode 100644
index 0000000..874195f
--- /dev/null
+++ b/android_filesystem_config.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+/* This file is used to define the properties of the file system
+** images generated by build tools (eg: mkbootfs) and
+** by the device side of adb.
+*/
+
+#define NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS
+/* static const struct fs_path_config android_device_dirs[] = { }; */
+
+/* Rules for files.
+** These rules are applied based on "first match", so they
+** should start with the most specific path and work their
+** way up to the root. Prefixes ending in * denotes wildcard
+** and will allow partial matches.
+*/
+static const struct fs_path_config android_device_files[] = {
+  { 00755, AID_ROOT, AID_SHELL, (1ULL << CAP_BLOCK_SUSPEND),
"system/bin/glgps" },
+#ifdef NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS
+  { 00000, AID_ROOT, AID_ROOT, 0, "system/etc/fs_config_dirs" },
+#endif
+};


diff --git a/device.mk b/device.mk
index 0c71d21..235c1a7 100644
--- a/device.mk
+++ b/device.mk
@@ -18,7 +18,8 @@ PRODUCT_PACKAGES := \
     libwpa_client \
     hostapd \
     wpa_supplicant \
-    wpa_supplicant.conf
+    wpa_supplicant.conf \
+    fs_config_files

 ifeq ($(TARGET_PREBUILT_KERNEL),)
 ifeq ($(USE_SVELTE_KERNEL), true)

Migracja systemów plików z wcześniejszych wersji

Podczas przenoszenia systemów plików z Androida 5.x i starszych wersji pamiętaj, że Android 6.x

  • Usuwa niektóre instrukcje include, struktury i definicje wbudowane.
  • Wymaga odwołania do libcutils zamiast bezpośredniego uruchamiania z system/core/include/private/android_filesystem_config.h. Prywatne pliki wykonywalne producenta urządzenia, które zależą od system/code/include/private_filesystem_config.h w przypadku struktur plików lub katalogów albo fs_config, muszą dodać zależności biblioteki libcutils.
  • Wymaga kopii prywatnych gałęzi producenta urządzenia system/core/include/private/android_filesystem_config.h z dodatkową zawartością w przypadku istniejących miejsc docelowych, aby przejść na device/vendor/device/android_filesystem_config.h.
  • Zastrzega sobie prawo do stosowania obowiązkowych kontroli dostępu (MAC) SELinux do plików konfiguracyjnych w systemie docelowym. Implementacje, które zawierają niestandardowe pliki wykonywalne w systemie docelowym, korzystające z funkcji fs_config(), muszą zapewniać dostęp.