File DAC Configuration

Earlier versions of Android used a system configuration file that was not extensible, preventing device manufacturers from adding named binaries to specify Discretionary Access Controls (DAC) of ownership, access mode, or executable capabilities. This limitation occurred as a result of support for Linux kernels 3.14 and higher in which wake lock is enabled via the CAP_SUSPEND_BLOCK capability; partner-supplied GPS daemons were required to hold this wake lock (and thus have this capability set in the file system).

As of Android 6.0, fs_config and associated structure definitions (system/core/include/private/android_filesystem_config.h) are now located in system/core/libcutils/fs_config.c where they can be updated or overridden by binary files installed in /system/etc/fs_config_dirs and /system/etc/fs_config_files. For clarity, Android uses separate matching and parsing rules for directories and files (which can use additional glob expressions) and handles directories and files in two different tables. Structure definitions in system/core/libcutils/fs_config.c not only allow runtime reading of directories and files, but the host may use the same files during build time to construct filesystem images as ${OUT}/system/etc/fs_config_dirs and ${OUT}/system/etc/fs_config_files.

Generating override files

You can generate the aligned binary files /system/etc/fs_config_dirs and /system/etc/fs_config_files using the fs_config_generate tool in build/tools/fs_config. The tool uses a libcutils library function (fs_config_generate()) to manage DAC requirements into a buffer and defines rules for an include file to institutionalize the DAC rules.

To use, create an include file in device/vendor/device/android_filesystem_config.h that acts as the override. The file must use the structure fs_path_config format defined in system/core/include/private/android_filesystem_config.h with the following structure initializations for directory and file symbols:

  • For directories, use android_device_dirs[].
  • For files, use android_device_files[].

When not using android_device_dirs[] and android_device_files[], you can define NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS and NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_FILES (see the example below).

You can also specify the override file using TARGET_ANDROID_FILESYSTEM_CONFIG_H in the board configuration, with an enforced basename of android_filesystem_config.h.

Including files

PRODUCT_PACKAGES must include fs_config_dirs and/or fs_config_files to install them to /system/etc/fs_config_dirs and /system/etc/fs_config_files, respectively.

The build system searches for custom android_filesystem_config.h in $(TARGET_DEVICE_DIR), where BoardConfig.mk exists. If this file exists elsewhere, set board config variable TARGET_ANDROID_FILESYSTEM_CONFIG_H to point to that location.

Configuring

To configure the file system in Android 6.0 and higher:

  1. Create the $(TARGET_DEVICE_DIR)/android_filesystem_config.h file.
  2. Add the fs_config_dirs and/or fs_config_files to PRODUCT_PACKAGES in the board configuration file (e.g., $(TARGET_DEVICE_DIR)/device.mk).

Migration concerns

Migrating system configurations from Android 5.0 and earlier can be disruptive. When planning such a migration, keep in mind that Android 6.0:

  • Removes some includes, structures, and inline definitions.
  • Requires a reference to libcutils instead of running directly from system/core/include/private/android_filesystem_config.h. Device manufacturer private executables that depend on system/code/include/private_filesystem_config.h for the file or directory structures or fs_config must add libcutils library dependencies.
  • Requires device manufacturer private branch copies of the system/core/include/private/android_filesystem_config.h with extra content on existing targets to move to device/vendor/device/android_filesystem_config.h.
  • As Android reserves the right to apply SELinux Mandatory Access Controls (MAC) to configuration files on the target system, implementations that include custom target executables using fs_config() must ensure access.

Example

This example shows a patch for overriding the system/bin/glgps daemon to add wake lock support in the device/vendor/device directory. Keep the following in mind:

  • Each structure entry is the mode, uid, gid, capabilities, and the name. system/core/include/private/android_filesystem_config.h is included automatically to provide the manifest #defines (AID_ROOT, AID_SHELL, CAP_BLOCK_SUSPEND).
  • The android_device_files[] section includes an action to suppress access to system/etc/fs_config_dirs when unspecified, which serves as an additional DAC protection for lack of content for directory overrides. However, this is weak protection; if someone has control over /system, they can typically do anything they want.
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)