Dyskretywna kontrola dostępu (DAC)

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

Wcześniejsze wersje Androida (Android 7.x i starsze) rozszerzyły mechanizm identyfikatorów AID za pomocą pliku android_filesystem_config.h przeznaczonego na konkretne urządzenie, aby określić możliwości systemu plików lub niestandardowe identyfikatory AID OEM. System ten był jednak nieintuicyjny, ponieważ nie obsługiwał przyjaznych nazw identyfikatorów AID OEM. Wymagało to podania surowych wartości liczbowych w polach użytkownika i grupy bez możliwości powiązania przyjaznej nazwy z liczbowym identyfikatorem AID.

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

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

Dodatkowe ulepszenia obejmują usunięcie tablicy android_ids[] z elementu system/core/libcutils/include/private/android_filesystem_config.h. Ta tablica jest teraz dostępna w Bionic jako całkowicie prywatna generowana tablica z metodami dostępu getpwnam()getgrnam(). (efektem ubocznym jest tworzenie stabilnych plików binarnych, gdy zmieniają się podstawowe identyfikatory AID). Więcej informacji o narzędziach i pliku README znajdziesz w artykule build/make/tools/fs_config.

Dodawanie identyfikatorów Androida (AID)

W Androidzie 8.0 usunięto macierz android_ids[] z projektu Android Open Source Project (AOSP). Wszystkie nazwy zgodne z AID są zamiast tego generowane z pliku nagłówka system/core/libcutils/include/private/android_filesystem_config.h podczas generowania tablicy Bionic android_ids[]. Dowolny element define pasujący do kolumny AID_* jest pobierany przez narzędzie, a znak * staje się małą nazwą.

Na przykład w private/android_filesystem_config.h:

#define AID_SYSTEM 1000

Zmiana:

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

Aby dodać nowy AID rdzenia AOSP, po prostu dodaj plik nagłówka #define do pliku nagłówka android_filesystem_config.h. AID jest generowany podczas kompilacji i staje się dostępny dla interfejsów, które używają argumentów użytkownika i grupy. Narzędzie sprawdza, czy nowy AID nie mieści się w zakresach APP ani OEM. Uwzględnia też zmiany w tych zakresach i powinno być automatycznie ponownie skonfigurowane po wprowadzeniu zmian lub nowych zakresach zarezerwowanych przez OEM.

Konfigurowanie identyfikatorów AID

Aby włączyć nowy mechanizm identyfikatorów AID, ustaw wartość TARGET_FS_CONFIG_GEN w pliku BoardConfig.mk. Ta zmienna zawiera listę plików konfiguracji, 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. config.fs pliki są w formacie ini ConfigParser Pythona i zawierają sekcję caps (do konfigurowania możliwości systemu plików) oraz sekcję AID (do konfigurowania identyfikatorów AID OEM).

Konfigurowanie sekcji dotyczącej limitów

Sekcja caps umożliwia konfigurowanie funkcji systemu plików w obiektach systemu plików w ramach kompilacji (system plików musi też obsługiwać tę funkcję).

Uruchomienie stabilnej usługi jako root na Androidzie powoduje niepowodzenie Compatibility Test Suite (CTS), więc poprzednie wymagania dotyczące zachowania możliwości podczas uruchamiania procesu lub usługi obejmowały konfigurowanie możliwości, a następnie używanie setuid/setgid do uruchamiania odpowiedniego AID. Dzięki temu możesz pominąć te wymagania i pozwolić jądro na wykonanie tej czynności za Ciebie. Gdy przekazanie kontroli do main(), proces ma już wymagane możliwości, aby usługa mogła używać użytkownika i grupy niebędącej użytkownikiem root (jest to preferowany sposób uruchamiania usług uprzywilejowanych).

Sekcja dotycząca wielkich liter ma taką składnię:

Sekcja Wartość Definicja
[path] Ścieżka do skonfigurowania w systemie plików. Ścieżka kończąca się na / jest uważana za katalog, w przeciwnym razie jest plikiem.

Podanie w różnych plikach kilku sekcji o tej samej nazwie [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 on ustawiony na tryb ścisły.
mode Tryb pliku octal Prawidłowy tryb pliku ósemkowego z co najmniej 3 cyframi. Jeśli podano wartość 3, przed nią dodawana jest litera 0, w przeciwnym razie tryb jest używany bez zmian.
user AID_<użytkownik> Litera C define dla prawidłowego identyfikatora AID lub przyjazna nazwa (np. zarówno AID_RADIO, jak i radio są dozwolone). Aby zdefiniować niestandardowy identyfikator AID, zapoznaj się z sekcją Konfigurowanie identyfikatora AID.
group AID_<group> Taki sam jak w przypadku użytkownika.
caps cap* Nazwa zadeklarowana w bionic/libc/kernel/uapi/linux/capability.h bez CAP_ na początku. Dozwolone są wielkie i małe litery. Caps może też być nieprzetworzony:
  • binarny (0b0101)
  • ośmiu (0455).
  • int (42)
  • szesnastkowo (0xFF)
Rozdziel wielkie litery odstępami.

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

Konfigurowanie sekcji AID

Sekcja AID zawiera identyfikatory AID OEM i korzysta z tej składni:

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

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

Nazwa <name> musi zaczynać się od nazwy partycji, aby nie powodować konfliktów z innymi źródłami.
value <number> Prawidłowy ciąg znaków liczby w stylu języka C (szesnastkowy, ósemkowy, binarny i dziesiętny).

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

Opcje wartości muszą być określone w zakresie odpowiadającym partycji używanej 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 artykułach 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łościowymi nazwami AOSP lub innymi partycjami.

Zdefiniuj nazwy AID OEM

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

[AID_VENDOR_FOO]
value: 2900

Po utworzeniu pliku ustaw zmienną TARGET_FS_CONFIG_GEN i od niej odwołuj się w sekcji BoardConfig.mk. Na przykład w 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 teraz być używany przez system w ramach nowej wersji.

Używanie identyfikatorów AID OEM

Aby użyć identyfikatora AID OEM, w kodzie C uwzględnij w powiązanym pliku Makefile zmienną oemaids_headers i dodaj #include "generated_oem_aid.h", a następnie zacznij używać zadeklarowanych identyfikatorów. Na przykład w elemencie my_file.c dodaj te informacje:

#include "generated_oem_aid.h"


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

W powiązanym pliku Android.bp dodaj:

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 dowolnym interfejsie, który obsługuje nazwy AID. Na przykład:

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

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

Powiąż przyjazne nazwy

Android 9 obsługuje łączenie nazwy przyjaznej z rzeczywistą wartością identyfikatora AID OEM. W przypadku użytkownika i grupy możesz używać niearytmetycznych ciągów znaków, np. „vendor_foo” zamiast „2901”.

Konwertowanie identyfikatorów AID na nazwy przyjazne

W Androidzie 8.x w przypadku identyfikatorów OEM wymagane było używanie funkcji oem_#### z funkcją getpwnam i podobnymi, a także w miejscach, które obsługują wyszukiwanie za pomocą funkcji getpwnam (np. skrypty init). W Androidzie 9 możesz używać znajomych z getpwnam i getgrnam w Bionic, aby zamienić identyfikatory Androida (AID) na przyjazne nazwy i odwrotnie.

Korzystanie z możliwości 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 TARGET_FS_CONFIG_GEN tak, by wskazywał ten plik w BoardConfig.mk. Na przykład w 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, uruchamia się z możliwościami CAP_SYS_ADMINCAP_SYS_NICE bez wywołań setuidsetgid. Dodatkowo zasada SELinux usługi vendor_foo nie wymaga już możliwości setuid ani setgid. Można ją usunąć.

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

W Androidzie 6.0 funkcja fs_config i powiązane z nią definicje struktury (system/core/include/private/android_filesystem_config.h) zostały przeniesione do pliku system/core/libcutils/fs_config.c, gdzie można je aktualizować lub zastępować za pomocą plików binarnych zainstalowanych w folderach /system/etc/fs_config_dirs/system/etc/fs_config_files. Korzystanie z osobnych reguł dopasowywania i analizowania 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 struktur w system/core/libcutils/fs_config.c zezwalały nie tylko na odczyt katalogów i plików w środowisku wykonawczym, ale podczas kompilacji host mógł używać tych samych plików do tworzenia obrazów systemu plików, takich jak ${OUT}/system/etc/fs_config_dirs i ${OUT}/system/etc/fs_config_files.

Metoda zastąpienia rozszerzenia systemu plików została zastąpiona przez modułowy system konfiguracji wprowadzony w Androidzie 8.0, ale w razie potrzeby nadal możesz używać starszej metody. W następnych sekcjach znajdziesz szczegółowe informacje o generowaniu i dołączaniu plików, zastępowaniu plików i konfigurowaniu systemu plików.

Generuj pliki zastąpień

Wyrównane pliki binarne /system/etc/fs_config_dirs/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 DAC w buforze, oraz definiuje reguły dla pliku include, aby ustanowić reguły DAC.

Aby użyć tej funkcji, utwórz plik include w folderze device/vendor/device/android_filesystem_config.h, który będzie działać jako zastąpienie. Plik musi być w formacie structure fs_path_config zdefiniowanym w pliku system/core/include/private/android_filesystem_config.h z tymi wstępnymi wartościami struktury dla symboli katalogu i pliku:

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

Jeśli nie używasz właściwości android_device_dirs[] i android_device_files[], możesz zdefiniować właściwości NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS i NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_FILES (patrz przykład poniżej). Plik zastąpienia możesz też określić za pomocą polecenia TARGET_ANDROID_FILESYSTEM_CONFIG_H w konfiguracji tablicy z wymuszoną nazwą bazową równą android_filesystem_config.h.

Uwzględnij pliki zastąpień

Aby dołączyć pliki, upewnij się, że PRODUCT_PACKAGES zawiera właściwość fs_config_dirs lub fs_config_files, aby umożliwić instalację odpowiednio w środowisku /system/etc/fs_config_dirs i /system/etc/fs_config_files. System kompilacji wyszukuje niestandardowe android_filesystem_config.h$(TARGET_DEVICE_DIR), gdzie istnieje BoardConfig.mk. Jeśli ten plik istnieje gdzie indziej, ustaw zmienną konfiguracji płyty TARGET_ANDROID_FILESYSTEM_CONFIG_H tak, aby wskazywała na tę lokalizację.

Konfigurowanie systemu plików

Aby skonfigurować system plików w Androidzie 6.0 lub nowszym:

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

Przykład zastąpienia

Ten przykład przedstawia poprawkę umożliwiającą zastąpienie demona system/bin/glgps dodającą obsługę blokady uśpienia w katalogu device/vendor/device. Pamiętaj o tych kwestiach:

  • Każdy wpis struktury to tryb, identyfikator użytkownika, identyfikator grupy, możliwości i nazwa. system/core/include/private/android_filesystem_config.h jest dołączany automatycznie, aby zapewnić definicje w pliku manifestu (#defines) (AID_ROOT, AID_SHELL, CAP_BLOCK_SUSPEND).
  • Sekcja android_device_files[] zawiera działanie blokujące dostęp do system/etc/fs_config_dirs, gdy nie jest określony. Dodatkowa ochrona DAC w przypadku braku treści zastąpień katalogu. Jest to jednak słaba ochrona. Jeśli ktoś ma kontrolę nad /system, 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

Przy migracji systemów plików z Androida 5.x i starszych pamiętaj, że Android 6.x

  • Usuwa niektóre elementy obejmujące, struktury i wbudowane definicje.
  • Wymaga odwołania do libcutils zamiast uruchamiania bezpośrednio 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 strukturze plików lub katalogów, lub fs_config, muszą dodać libcutils zależności biblioteki.
  • Wymaga kopii system/core/include/private/android_filesystem_config.h z dodatkowymi treściami dla istniejących celów, które należy przenieść do device/vendor/device/android_filesystem_config.h.
  • Zastrzega sobie prawo do stosowania mechanizmów Mandatory Access Controls (MAC) SELinux do plików konfiguracyjnych w systemie docelowym. Wdrożenia, które obejmują niestandardowe pliki wykonywalne docelowe korzystające z fs_config(), muszą zapewniać dostęp.