android-tools: make adbd fs_config opt-in via PACKAGECONFIG

On non-Android builds should_use_fs_config() in adbd's
file_sync_service.cpp unconditionally returns true, so every
`adb push` destination, including paths under /data, is routed through
Android's fs_config tables. Those tables have a catch-all directory entry
for "data" (mode 0771, AID_SYSTEM) but no equivalent file entry, so a
freshly pushed directory and the file inside it end up with inconsistent
owners, and non-root/system processes can't list the directory.

On non-Android builds should_use_fs_config() now returns false by
default: adbd then honours the mode sent by the host and leaves
ownership untouched.

Add a "fs-config" PACKAGECONFIG (disabled by default) which defines
ADBD_USE_FS_CONFIG and re-enables fs_config, scoped to /system, /vendor
and /oem, for BSPs that rely on it.

Behaviour change: fs_config is no longer applied on non-Android builds
unless PACKAGECONFIG contains "fs-config".

AI-Generated: Uses Claude Code (Claude Sonnet 5.5)

Signed-off-by: Etienne Cordonnier <ecordonnier@snap.com>
Signed-off-by: Khem Raj <khem.raj@oss.qualcomm.com>
This commit is contained in:
Etienne Cordonnier authored and Khem Raj committed 2026-10-09 10:01:42 -07:00
1 parent 46fad8b381
commit ec5c55a1b9
2 files changed
+66

No files matched your search

@@ -0,0 +1,60 @@
Subject: [PATCH] adbd: make fs_config opt-in on non-Android builds
should_use_fs_config() exists to restrict Android's fs_config-based
ownership/mode table to the partitions it actually describes
(/system, /vendor, /oem), with a compatibility carve-out that also
excludes /data on older on-device Android API levels. That carve-out
is guarded by `#if defined(__ANDROID__)`, so on a non-Android (Linux
host) build of adbd it never applies, and the function unconditionally
returns true instead.
As a result, every `adb push` destination -- including arbitrary
paths under /data -- gets routed through fs_config's android_dirs/
android_files tables. Those tables define a catch-all directory entry
for "data" (mode 0771, uid/gid AID_SYSTEM) but no equivalent catch-all
file entry, so a freshly pushed directory and the file inside it end
up with different, Android-partition-image-derived owners instead of
both simply being owned by whoever ran the push. Mode 0771 also means
a process that isn't root or system can traverse such a directory but
not list its contents, which breaks any non-privileged service trying
to iterate a pushed directory tree.
fs_config's table has nothing meaningful to say about a generic Linux
rootfs, so on non-Android builds disable it by default, which makes adbd
honour the mode sent by the host and leave ownership untouched. Builds
that do rely on fs_config can define ADBD_USE_FS_CONFIG, in which case
it is applied only to /system, /vendor and /oem.
Upstream-Status: Pending
Signed-off-by: Etienne Cordonnier <ecordonnier@snap.com>
---
packages/modules/adb/daemon/file_sync_service.cpp | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/packages/modules/adb/daemon/file_sync_service.cpp b/packages/modules/adb/daemon/file_sync_service.cpp
--- a/packages/modules/adb/daemon/file_sync_service.cpp
+++ b/packages/modules/adb/daemon/file_sync_service.cpp
@@ -81,8 +81,19 @@ static bool should_use_fs_config([[maybe_unused]] const std::string& path) {
if (android_get_device_api_level() < __ANDROID_API_V__) {
return !android::base::StartsWith(path, "/data/");
}
-#endif
return true;
+#elif defined(ADBD_USE_FS_CONFIG)
+ // Non-Android (Linux host) build with fs_config enabled: its tables only
+ // describe the system partitions, so keep it scoped to those rather than
+ // letting it apply to arbitrary pushed paths such as /data.
+ return android::base::StartsWith(path, "/system/") ||
+ android::base::StartsWith(path, "/vendor/") ||
+ android::base::StartsWith(path, "/oem/");
+#else
+ // Non-Android build, fs_config disabled: use the mode sent by the host and
+ // don't change ownership.
+ return false;
+#endif
}
static bool update_capabilities(const char* path, uint64_t capabilities) {
--
2.43.0
@@ -60,6 +60,7 @@ SRC_URI = "https://deb.debian.org/debian/pool/main/a/android-platform-tools/andr
file://0012-libbase-off64_t-extend-non-glibc-compat-typedef-to-musl.patch \
file://0013-adb-sysdeps-provide-pread64-pwrite64-lseek64-fallba.patch \
file://0014-daemon-auth-vendor-a-portable-b64_pton-for-non-glib.patch \
file://0015-adbd-make-fs-config-opt-in-on-non-android-builds.patch \
"
SRC_URI[orig.md5sum] = "352376965cdef7bd7505d8fefdd43d50"
@@ -98,6 +99,7 @@ CFLAGS:append:libc-musl = " -DANDROID_HOST_MUSL"
# path instead of the broken compile-time one.
CXXFLAGS:append = " -fPIC -std=gnu++20 -D_Nonnull= -D_Nullable= -I${STAGING_INCDIR}/boringssl -DFMT_CONSTEVAL="
CXXFLAGS:append:libc-musl = " -DANDROID_HOST_MUSL"
CXXFLAGS:append = "${@bb.utils.contains('PACKAGECONFIG', 'fs-config', ' -DADBD_USE_FS_CONFIG', '', d)}"
LDFLAGS:append = " -fPIC -L${STAGING_LIBDIR}/android"
@@ -259,4 +261,8 @@ FILES:${PN}-adbd = " \
BBCLASSEXTEND = "native"
PACKAGECONFIG ??= "${@bb.utils.filter('DISTRO_FEATURES', 'systemd', d)}"
# Apply Android's fs_config ownership/mode tables to files pushed by adbd to
# /system, /vendor and /oem. Off by default: the tables describe Android
# partition images and are meaningless on a generic Linux rootfs.
PACKAGECONFIG[fs-config] = ""
PACKAGECONFIG[systemd] = ",,systemd"