DAC(Discretionary Access Control)

빌드에 추가된 파일 시스템 객체 및 서비스에는 Android ID(AID)라고 알려진 별도의 고유 ID가 필요할 때가 많습니다. 현재는 파일 및 서비스와 같은 다수의 리소스에 Android에서 정의한 핵심 AID가 불필요하게 사용되고 있으며 많은 경우 OEM에서 정의한 OEM AID를 대신 사용할 수 있습니다.

이전 버전의 Android(Android 7.x 이하)에서는 기기별 android_filesystem_config.h 파일을 사용해 AID 메커니즘을 확장하여 파일 시스템 기능 및 맞춤 OEM AID를 지정했습니다. 하지만 이 시스템은 OEM AID를 위한 적절한 이름 사용을 지원하지 않아 친숙한 이름을 숫자 AID에 연결하는 방법 없이 사용자 및 그룹 필드의 원시 숫자를 지정해야 했으므로 직관적이지 않았습니다.

새로운 Android 버전(Android 8.0 이상)은 파일 시스템 기능 확장을 위한 새로운 방식을 지원합니다. 이 새로운 방식에서 지원하는 내용은 다음과 같습니다.

  • 구성 파일을 위한 여러 소스 위치(확장 가능한 빌드 구성 지원)
  • OEM AID 값의 빌드 시간 상태 확인
  • 필요에 따라 소스 파일에 사용 가능한 맞춤 OEM AID 헤더 생성
  • 친숙한 이름을 실제 OEM AID 값에 연결. 사용자 및 그룹에 숫자가 아닌 문자열 인수(즉, '2901' 대신 'foo') 지원

추가 개선사항으로 system/core/libcutils/include/private/android_filesystem_config.h에서 android_ids[] 배열이 삭제되었습니다. 이제 이 배열은 getpwnam()getgrnam()을 통한 접근자가 있는, 완전히 비공개로 생성된 배열로 Bionic에 존재합니다. 이 경우 핵심 AID가 수정될 때 안정적인 바이너리를 생성하는 부작용이 있습니다. 도구 및 리드미 파일에 관한 자세한 내용은 build/make/tools/fs_config를 참고하세요.

Android ID(AID) 추가

Android 8.0에서는 Android 오픈소스 프로젝트(AOSP)에서 android_ids[] 배열을 삭제했습니다. 모든 AID 친화적인 이름은 Bionic android_ids[] 배열이 생성될 때 system/core/libcutils/include/private/android_filesystem_config.h 헤더 파일에서 대신 생성됩니다. AID_*와 일치하는 모든 define이 도구에서 선택되고 *가 소문자 이름이 됩니다.

예를 들어 private/android_filesystem_config.h에서

#define AID_SYSTEM 1000

위의 내용이 아래와 같이 변합니다.

  • 친숙한 이름: 시스템
  • uid: 1000
  • gid: 1000

새 AOSP 핵심 AID를 추가하려면 #defineandroid_filesystem_config.h 헤더 파일에 추가하기만 하면 됩니다. AID는 빌드 시에 생성되어 사용자 및 그룹 인수를 사용하는 인터페이스에 제공됩니다. 도구는 새 AID가 APP 또는 OEM 범위 내에 없는지 확인하고 이러한 범위에 대한 변경사항을 존중합니다. 또한 변경사항 또는 새로운 OEM 예약 범위에 대해 자동으로 재구성합니다.

AID 구성

새 AID 메커니즘을 사용 설정하려면 BoardConfig.mk 파일에서 TARGET_FS_CONFIG_GEN을 설정하세요. 이 변수에는 필요에 따라 파일을 추가할 수 있도록 구성 파일 목록이 보관됩니다.

규칙에 따르면 구성 파일은 이름 config.fs를 사용하지만 실제로는 어떤 이름이든 사용할 수 있습니다. config.fs 파일은 Python ConfigParser ini 형식을 취하며 파일 시스템 기능 구성을 위한 caps 섹션과 OEM AID 구성을 위한 AID 섹션을 포함합니다.

caps 섹션 구성

caps 섹션은 빌드 내의 파일 시스템 객체에 파일 시스템 기능 설정을 지원합니다. 파일 시스템 자체도 이 기능을 지원해야 합니다.

Android에서 안정적인 서비스를 루트로 실행하면 호환성 테스트 모음(CTS)에서 오류가 발생하게 되므로 프로세스 또는 서비스를 실행하면서 기능을 유지하기 위한 이전의 요구사항에는 기능을 설정한 후 실행할 올바른 AID에 setuid/setgid를 사용하는 것이 포함되었습니다. caps를 사용하면 이러한 요구사항을 건너뛰고 커널이 알아서 처리하게 만들 수 있습니다. 컨트롤이 main()에 전달되면 프로세스는 필요한 기능을 이미 보유하게 되므로 서비스에서 루트 외 사용자와 그룹을 사용할 수 있습니다(권한이 있는 서비스를 시작할 때 선호되는 방법).

caps 섹션에서는 다음과 같은 문법을 사용합니다.

섹션 정의
[path] 구성하려는 파일 시스템 경로입니다. /로 끝나는 경로는 dir로 간주되며 나머지는 파일입니다.

서로 다른 파일에서 동일한 [path]로 섹션을 여러 개 지정하면 오류가 발생합니다. Python 3.2 이하의 버전에서는 같은 파일에 이전 섹션을 재정의하는 섹션이 포함될 수 있으며 Python 3.2에서는 엄격한 모드로 설정됩니다.
mode 8진수 파일 모드 최소 3자리 숫자로 이루어진 유효한 8진수 파일 모드입니다. 3이 지정되면 0이 접두사로 사용되며, 나머지 경우에는 모드가 그대로 사용됩니다.
user AID_<user> 유효한 AID의 C define이거나 친숙한 이름입니다(예: AID_RADIOradio가 둘 다 허용됨). 맞춤 AID를 정의하려면 AID 섹션 구성을 참조하세요.
group AID_<group> 사용자와 동일합니다.
caps cap* 앞의 CAP_ 없이 bionic/libc/kernel/uapi/linux/capability.h에서 선언된 이름입니다. 대소문자 혼합이 허용됩니다. caps도 원시일 수 있습니다.
  • 2진수(0b0101)
  • 8진수(0455)
  • int(42)
  • 16진수(0xFF)
공백을 사용하여 여러 caps를 구분합니다.

사용 예는 파일 시스템 기능 사용을 참고하세요.

AID 섹션 구성

AID 섹션에는 OEM AID가 포함되며, 다음과 같은 문법이 사용됩니다.

섹션 정의
[AID_<name>] <name>은 설정된 대문자, 숫자 및 밑줄을 포함할 수 있습니다. 소문자 버전은 친숙한 이름으로 사용됩니다. 코드 포함을 위해 생성된 헤더 파일은 정확한 AID_<name>을 사용합니다.

동일한 AID_<name>으로 섹션을 여러 개 지정하면 오류가 발생합니다(대소문자를 구분하지 않으며 [path]와 제약 조건이 동일함).

<name>은 다른 소스와 충돌하지 않도록 파티션 이름으로 시작해야 합니다.
value <number> 유효한 C 형식 번호 문자열입니다(16진수, 8진수, 2진수 및 10진수).

같은 값 옵션으로 여러 섹션을 지정하면 오류가 발생합니다.

값 옵션은 <name>에 사용된 파티션에 상응하는 범위에서 지정되어야 합니다. 유효한 파티션 및 상응하는 범위 목록은 system/core/libcutils/include/private/android_filesystem_config.h에 정의되어 있습니다. 옵션은 다음과 같습니다.
  • 공급업체 파티션
    • AID_OEM_RESERVED_START(2900) - AID_OEM_RESERVED_END(2999)
    • AID_OEM_RESERVED_2_START(5000) - AID_OEM_RESERVED_2_END(5999)
  • 시스템 파티션
    • AID_SYSTEM_RESERVED_START(6000) - AID_SYSTEM_RESERVED_END(6499)
  • ODM 파티션
    • AID_ODM_RESERVED_START(6500) - AID_ODM_RESERVED_END(6999)
  • 제품 파티션
    • AID_PRODUCT_RESERVED_START(7000) - AID_PRODUCT_RESERVED_END(7499)
  • System_ext 파티션
    • AID_SYSTEM_EXT_RESERVED_START(7500) - AID_SYSTEM_EXT_RESERVED_END(7999)

사용 예는 OEM AID 이름 정의OEM AID 사용을 참고하세요.

사용 예

다음 예는 OEM AID를 정의 및 사용하고 파일 시스템 기능을 사용 설정하는 방법을 자세히 보여줍니다. OEM AID 이름([AID_name])은 'vendor_'와 같은 파티션 이름으로 시작해야 향후의 AOSP 이름 또는 다른 파티션과 충돌하지 않습니다.

OEM AID 이름 정의

OEM AID를 정의하려면 config.fs 파일을 생성하고 AID 값을 설정합니다. 예를 들어 device/x/y/config.fs에서 다음을 설정합니다.

[AID_VENDOR_FOO]
value: 2900

파일을 생성한 후에는 TARGET_FS_CONFIG_GEN 변수를 설정하고 BoardConfig.mk에서 변수를 가리킵니다. 예를 들어 device/x/y/BoardConfig.mk에서 다음을 설정합니다.

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

이제 새 빌드에 활성화된 시스템에서 맞춤 AID를 소비할 수 있습니다.

OEM AID 사용

OEM AID를 사용하려면 C 코드에서 연결된 Makefile에 oemaids_headers를 포함하고 #include "generated_oem_aid.h"를 추가한 다음 선언된 식별자를 사용하기 시작합니다. 예를 들어 my_file.c에서 다음을 추가합니다.

#include "generated_oem_aid.h"
…

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

연결된 Android.bp 파일에서 다음을 추가합니다.

header_libs: ["oemaids_headers"],

Android.mk 파일을 사용 중인 경우 다음을 추가합니다.

LOCAL_HEADER_LIBRARIES := oemaids_headers

친숙한 이름 사용

Android 9에서는 AID 이름을 지원하는 모든 인터페이스에 친숙한 이름을 사용할 수 있습니다. 예:

  • some/init.rcchown 명령어에서:
    chown vendor_foo /vendor/some/vendor_foo/file
    
  • some/init.rcservice에서:
    service vendor_foo /vendor/bin/foo_service
        user vendor_foo
        group vendor_foo
    

친숙한 이름에서 uid로의 내부 매핑은 /vendor/etc/passwd/vendor/etc/group에 의해 실행되므로 공급업체 파티션을 마운트해야 합니다.

친숙한 이름 연결

Android 9에서는 친숙한 이름을 실제 OEM AID 값과 연결할 수 있게 지원합니다. 사용자 및 그룹에 숫자가 아닌 문자열 인수를 사용할 수 있습니다(예: '2901' 대신 'vendor_foo').

AID에서 친숙한 이름으로 변환

OEM AID의 경우 Android 8.x에서는 getpwnam 및 유사 함수로 oem_####을 사용해야 했습니다. 또한 getpwnam(예: init 스크립트)을 통해 조회를 처리하는 곳에도 사용해야 했습니다. Android 9에서는 Bionic의 getpwnamgetgrnam 프렌드를 사용하여 Android ID(AID)를 친숙한 이름으로 변환하거나 그 반대로도 변환할 수 있습니다.

파일 시스템 기능 사용

파일 시스템 기능을 사용 설정하려면 config.fs 파일에 caps 섹션을 생성합니다. 예를 들어 device/x/y/config.fs에서 다음 섹션을 추가합니다.

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

파일을 생성한 후에는 TARGET_FS_CONFIG_GENBoardConfig.mk의 파일을 가리키도록 설정합니다. 예를 들어 device/x/y/BoardConfig.mk에서 다음을 설정합니다.

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

서비스 vendor_foo가 실행되면 setuidsetgid 호출 없이 기능 CAP_SYS_ADMINCAP_SYS_NICE로 시작됩니다. 또한 vendor_foo 서비스의 SELinux 정책에는 더 이상 기능 setuidsetgid가 필요하지 않으므로 정책을 삭제할 수 있습니다.

재정의 구성(Android 6.x-7.x)

Android 6.0에서는 fs_config 및 연결된 구조 정의(system/core/include/private/android_filesystem_config.h)를 system/core/libcutils/fs_config.c로 재배치하여 /system/etc/fs_config_dirs/system/etc/fs_config_files에 설치된 바이너리 파일로 업데이트 또는 재정의할 수 있었습니다. 추가적인 glob 표현식을 사용할 수 있는 디렉터리와 파일에 별도의 매칭 및 파싱 규칙을 사용하면 Android에서 서로 다른 두 개의 테이블로 디렉터리와 파일을 처리할 수 있습니다. system/core/libcutils/fs_config.c의 구조 정의는 디렉터리와 파일의 런타임 읽기를 허용할 뿐 아니라 호스트가 빌드 시간 중에 동일한 파일을 사용하여 파일 시스템 이미지를 ${OUT}/system/etc/fs_config_dirs${OUT}/system/etc/fs_config_files로 구성할 수 있었습니다.

파일 시스템 확장의 재정의 메서드가 Android 8.0에서 도입된 모듈식 구성 시스템으로 대체되었지만 원한다면 이전 메서드를 계속해서 사용할 수 있습니다. 다음 섹션에서는 재정의 파일을 생성 및 포함하고 파일 시스템을 구성하는 방법을 자세히 보여줍니다.

재정의 파일 생성

build/tools/fs_configfs_config_generate 도구를 사용하여 정렬된 바이너리 파일 /system/etc/fs_config_dirs/system/etc/fs_config_files를 생성할 수 있습니다. 이 도구는 libcutils 라이브러리 함수(fs_config_generate())를 사용하여 DAC 요구사항을 버퍼로 관리하며 포함 파일 규칙을 정의하여 DAC 규칙을 제도화합니다.

사용하려면 재정의 기능 역할을 하는 device/vendor/device/android_filesystem_config.h에서 포함 파일을 만듭니다. 파일은 디렉터리 및 파일 기호의 다음 구조 초기화와 함께 system/core/include/private/android_filesystem_config.h에 정의된 structure fs_path_config 형식을 사용해야 합니다.

  • 디렉터리의 경우 android_device_dirs[]를 사용합니다.
  • 파일의 경우 android_device_files[]를 사용합니다.

android_device_dirs[]android_device_files[]를 사용하지 않는다면 NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRSNO_ANDROID_FILESYSTEM_CONFIG_DEVICE_FILES를 정의하면 됩니다(아래 참고). 시행된 기본 이름 android_filesystem_config.h로 보드 구성의 TARGET_ANDROID_FILESYSTEM_CONFIG_H를 사용하여 재정의 파일을 지정할 수도 있습니다.

재정의 파일 포함

파일을 포함하려면 PRODUCT_PACKAGESfs_config_dirsfs_config_files가 포함되어 각각 /system/etc/fs_config_dirs/system/etc/fs_config_files에 설치될 수 있는지 확인합니다. 빌드 시스템은 BoardConfig.mk가 있는 $(TARGET_DEVICE_DIR)에서 맞춤 android_filesystem_config.h를 검색합니다. 이 파일이 다른 곳에 있다면 보드 구성 변수 TARGET_ANDROID_FILESYSTEM_CONFIG_H를 그 위치를 가리키도록 설정합니다.

파일 시스템 구성

Android 6.0 이상에서 파일 시스템을 구성하는 방법은 다음과 같습니다.

  1. $(TARGET_DEVICE_DIR)/android_filesystem_config.h 파일을 생성합니다.
  2. 보드 구성 파일의 PRODUCT_PACKAGES fs_config_dirsfs_config_files를 추가합니다(예: $(TARGET_DEVICE_DIR)/device.mk).

재정의 예

이 예에서는 system/bin/glgps 데몬을 재정의하여 device/vendor/device 디렉터리에 wake lock 지원을 추가하기 위한 패치를 보여줍니다. 다음 사항에 유의하세요.

  • 각 구조 항목은 모듈, uid, gid, 기능 및 이름입니다. system/core/include/private/android_filesystem_config.h는 자동으로 포함되어 매니페스트 #defines(AID_ROOT, AID_SHELL, CAP_BLOCK_SUSPEND)를 제공합니다.
  • android_device_files[] 섹션에는 지정되지 않은 경우 system/etc/fs_config_dirs 액세스를 억제하기 위한 작업이 포함됩니다. 이는 디렉터리 재정의를 위한 콘텐츠 부족 시의 추가적인 DAC 보호 조치로 기능합니다. 하지만 이러한 보호 조치는 미약해서 /system을 제어하는 사람이 있다면 이 사람은 일반적으로 원하는 모든 것을 할 수 있습니다.
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 filesystem
+** 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)

이전 버전에서 파일 시스템 이전

Android 5.x 이하의 파일 시스템을 이전할 때는 다음과 같은 Android 6.x의 특징에 유의해야 합니다.

  • 일부 포함, 구조 및 인라인 정의가 삭제됩니다.
  • system/core/include/private/android_filesystem_config.h에서 직접 실행하는 대신 libcutils 참조가 필요합니다. 파일이나 디렉터리 구조의 system/code/include/private_filesystem_config.h 또는 fs_config에 의존하는 기기 제조업체의 비공개 실행 파일은 libcutils 라이브러리 종속 항목을 추가해야 합니다.
  • 기존 타겟에 관한 추가 콘텐츠가 있는 system/core/include/private/android_filesystem_config.h의 기기 제조업체 비공개 분기 복사본을 device/vendor/device/android_filesystem_config.h로 이동해야 합니다.
  • SELinux MAC(Mandatory Access Controls)을 타겟 시스템의 구성 파일에 적용할 수 있는 권리를 보유합니다. fs_config()을 사용하여 맞춤 타겟 실행 파일을 포함하는 구현은 액세스를 보장해야 합니다.