Skip to main content
added 2805 characters in body
Source Link
Irfan Latif
  • 21.2k
  • 3
  • 74
  • 225

WHY IS ADB DENIED ACCESS TO MULTI-USER STORAGE?

The whole story is about Android's filesystem emulation in order to have a permission-less directory (/sdcard) which allowsmakes file sharing among multiple UNIX users (apps) possible. It's achieved through mount namespaces and different VIEWs of /data/media mounted in /mnt/runtime/. Apps belonging to secondary as well as primary user have isolated mount namespaces. For details please see What is the “u#_everybody” UID? and What is /storage/emulated/0/?.

HOW TO ACCESS MULTIPLE-USERS FILES FROM ADB?

HOW TOWITH ROOT ACCESS MULTIPLE-USERS FILES FROM ADB?:

With root access you You can mount the emulated filesystem without default_normal option:

After reboot you should be able to read files in /storage/emulated/10 from adb shell.

WITHOUT ROOT ACCESS:

On Android 9+ filesystem level access to secondary users/profiles is not possible from adb on user builds of ROMs (i.e. without root). Only interaction through adb commands which support --user option (am, pm, content etc.) is possible. Documented in What’s in Android 9 for enterprise apps:

"To help keep work data in the work profile, the Android Debug Bridge (adb) tool can’t access directories and files in the work profile."

If the files owned by secondary users are accessible to primary user (through adb or any other means, except through Device/Work Policy Controller app), it breaks the intended isolation between users/profiles which is controlled through Android APIs. See more details in How to share files between regular account and work account?

It should be noted that Android Debugging Bridge (adb) is meant to be used by developers for debugging, not by end users. That's why a fully-managed device owner can completely disable adb.

There's a suggested workaround to transfer data with secondary users/profiles as explained in Testing Multiple Users:

"adb (or more accurately the adbd daemon) always runs as the system user (user ID = 0) regardless of which user is current. Therefore device paths that are user dependent (such as /sdcard/) always resolve as the system user."
...
"Access to /sdcard paths of secondary users is denied starting in Android 9."
...
"Because adb runs as the system user and data is sandboxed in Android 9 and higher, you must use content providers to push or pull any test data from a nonsystem user."

For instance to transfer test.jpg file to /storage/emulated/10/Pictures/ run the following commands from adb shell:

~$ content insert --user 10 --uri content://media/external/images/media/ --bind _display_name:s:test.jpg
~$ ID=$(content query --user 10 --projection _id --uri content://media/external/images/media/ --where _display_name=\'test.jpg\' | grep -o '_id=[0-9]*' | cut -d= -f2)
~$ content write --user 10 --uri content://media/external/images/media/$ID < test.jpg

However it's not a practical approach for bulk data transfers on a regular basis.

The whole story is about Android's filesystem emulation in order to have a permission-less directory (/sdcard) which allows file sharing among multiple UNIX users (apps). It's achieved through mount namespaces and different VIEWs of /data/media mounted in /mnt/runtime/. Apps belonging to secondary as well as primary user have isolated mount namespaces. For details please see What is the “u#_everybody” UID? and What is /storage/emulated/0/?.

HOW TO ACCESS MULTIPLE-USERS FILES FROM ADB?

With root access you can mount the emulated filesystem without default_normal option:

After reboot you should be able to read files in /storage/emulated/10 from adb shell.

WHY IS ADB DENIED ACCESS TO MULTI-USER STORAGE?

The whole story is about Android's filesystem emulation in order to have a permission-less directory (/sdcard) which makes file sharing among multiple UNIX users (apps) possible. It's achieved through mount namespaces and different VIEWs of /data/media mounted in /mnt/runtime/. Apps belonging to secondary as well as primary user have isolated mount namespaces. For details please see What is the “u#_everybody” UID? and What is /storage/emulated/0/?.

HOW TO ACCESS MULTIPLE-USERS FILES FROM ADB?

WITH ROOT ACCESS:

You can mount the emulated filesystem without default_normal option:

After reboot you should be able to read files in /storage/emulated/10 from adb shell.

WITHOUT ROOT ACCESS:

On Android 9+ filesystem level access to secondary users/profiles is not possible from adb on user builds of ROMs (i.e. without root). Only interaction through adb commands which support --user option (am, pm, content etc.) is possible. Documented in What’s in Android 9 for enterprise apps:

"To help keep work data in the work profile, the Android Debug Bridge (adb) tool can’t access directories and files in the work profile."

If the files owned by secondary users are accessible to primary user (through adb or any other means, except through Device/Work Policy Controller app), it breaks the intended isolation between users/profiles which is controlled through Android APIs. See more details in How to share files between regular account and work account?

It should be noted that Android Debugging Bridge (adb) is meant to be used by developers for debugging, not by end users. That's why a fully-managed device owner can completely disable adb.

There's a suggested workaround to transfer data with secondary users/profiles as explained in Testing Multiple Users:

"adb (or more accurately the adbd daemon) always runs as the system user (user ID = 0) regardless of which user is current. Therefore device paths that are user dependent (such as /sdcard/) always resolve as the system user."
...
"Access to /sdcard paths of secondary users is denied starting in Android 9."
...
"Because adb runs as the system user and data is sandboxed in Android 9 and higher, you must use content providers to push or pull any test data from a nonsystem user."

For instance to transfer test.jpg file to /storage/emulated/10/Pictures/ run the following commands from adb shell:

~$ content insert --user 10 --uri content://media/external/images/media/ --bind _display_name:s:test.jpg
~$ ID=$(content query --user 10 --projection _id --uri content://media/external/images/media/ --where _display_name=\'test.jpg\' | grep -o '_id=[0-9]*' | cut -d= -f2)
~$ content write --user 10 --uri content://media/external/images/media/$ID < test.jpg

However it's not a practical approach for bulk data transfers on a regular basis.

Source Link
Irfan Latif
  • 21.2k
  • 3
  • 74
  • 225

Access to /storage/emulated/10 is denied from adb shell due to this change in Android 9:

Add "default_normal" support to vold.
This new flag isolates each user on a multi-user device for security reasons.

What the mount option default_normal does in sdcardfs is explained here:

The default_normal option causes mounts with the gid set to AID_SDCARD_RW to have user specific gids, as in the normal case.

The whole story is about Android's filesystem emulation in order to have a permission-less directory (/sdcard) which allows file sharing among multiple UNIX users (apps). It's achieved through mount namespaces and different VIEWs of /data/media mounted in /mnt/runtime/. Apps belonging to secondary as well as primary user have isolated mount namespaces. For details please see What is the “u#_everybody” UID? and What is /storage/emulated/0/?.

Btw, my /sdcard/ always points to the first user's space /storage/emulated/0 at adb shell regardless what my current user is at mobile UI.

For all native processes running in root mount namespace (including adbd), /sdcard is a symlink to /storage/emulated/0 and /storage/emulated is bind mounted from /mnt/runtime/default. The device owner's (User_ID: 0) files in /storage/emulated/0 have ownership root:sdcard_rw (0:1015) and permission mode 0771, while secondary profile/user's (say with User_ID: 10) files in /storage/emulated/10 have ownership 0:1001015.

It means that non-root processes can read the directories only if they are members of supplementary groups: 0001015, 1001015, 11001015 and so on, "others" can only traverse the directories. Since adbd is member of only 1015 GID, it can read only device owner's files, not of secondary users.

However up to Android 8 there was an exception to the above rule: to all the processes running in root mount namespace (non-app processes), sdcardfs always returned the directories /storage/emulated/[N] owned by GID 1015. So adb was able to read these directories. However the exception has been removed in Android 9 using mount option default_normal.


HOW TO ACCESS MULTIPLE-USERS FILES FROM ADB?

With root access you can mount the emulated filesystem without default_normal option:

~# umount /mnt/runtime/*/emulated
~# /system/bin/sdcard -u 1023 -g 1023 -m -w -G /data/media emulated

Or to make changes permanent, replace sdcard binary with a shell script:

~# cd /system/bin/; mv sdcard sdcard.bin; touch sdcard
~# chown 0.2000 sdcard*; chmod 0755 sdcard*
~# chcon u:object_r:system_file:s0 sdcard
~# chcon u:object_r:sdcardd_exec:s0 sdcard.bin

/system/bin/sdcard (remove -i argument passed by vold):

#!/system/bin/sh

set -- $(echo "$*" | sed 's/-i //')
/system/bin/sdcard.bin $*

After reboot you should be able to read files in /storage/emulated/10 from adb shell.