Why root cannot access ".android_secure" directory on external SD card? I have an Android 9 tablet, rooted by way of Magisk. It has an external SD card mounted as sdfat on /mnt/media_rw/1234-5678 which is mounted on four other mount points, all as type sdcardfs, with some variation in owner and group.

From a terminal window I type ls -al /storage/1234-5678. Lots of files and directories are shown with one error message:

ls: permission denied: .android_secure


I try as root. I get the same result. Using /mnt/media_rw/1234-5678 and root, I can see the entry for .android_secure. I'm told that .android_secure itself is empty.


The external SD card is FAT32.  Anything on it has the same set of permissions.  How is .android_secure different from everything else on the card?
Even if .android_secure has different permissions from the other files in the directory, why is that stopping me from displaying the directory entry?
I become root and I still can't even display the directory entry for .android_secure. How can that be?


I tried stat. I tried lsattr. Still: permission denied.

I have read What does /mnt/asec directory contain? but it doesn't answer my questions:


If I have the permissions needed to list some directory entries, how am I being forbidden to list a specific entry in that directory?
How is it ever possible to deny root the ability to list a directory entry?  (And then change the protections on that entry.)


I can accept that the magic filesystem and/or SELinux makes it possible to have different protections on one file.  I just can't understand root being unable to even see what those different protections are.
A quick search reveals that there exist similar unanswered questions (this, this and this). Let me try to demystify it, starting with brief history.

WHAT IS .android_secure DIRECTORY?

In order to solve the problem of space shortage in internal storage, app2sd (Move to SD Card) was Android's native feature up to Lollipop. With this method .apk files (or whole /data/app/&lt;pkg&gt;/ directories) are moved as encrypted .asec files to .android_secure folder on external SD card or internal sdcard partition (mounted at /mnt/sdcard/ or /mnt/media_rw/sdcard[N]/). On every boot .android_secure is bind mounted to /mnt/secure/asec/ and the (ext4) filesystem containers (.asec) are decrypted (using dm-crypt) and mounted to individual directories (named after package names) in a temporary filesystem mounted at /mnt/asec/ by vold. Symlinks from /data/app/&lt;pkg&gt;/ and possibly /data/data/&lt;pkg&gt;/lib/ are pointing towards /mnt/asec/&lt;pkg&gt;/ and /mnt/asec/&lt;pkg&gt;/lib/.

WHY ACCESS TO .android_secure IS RESTRICTED?

From the early days of Android, access to android_secure folder (which later became .android_secure) was restricted. The commit states:


  In order to protect the /android_secure directory on VFAT removable media from being mucked with by 3rd party applications on the device, we hide the directory with a read-only, zero-sized tmpfs mounted on-top.


Later in Android 4.4 when FUSE was started being used for emulating SD cards from original mount point (/mnt/media_rw/sdcard1) to user accessible path (/storage/sdcard1/), the zero-sized tmpfs functionality (Ignore attempts to access security sensitive files) was shifted to sdcard daemon which was used to mount FUSE. In Android 6 the app2sd method was abandoned in favor of Adoptable Storage (also filesystem UUID was included in mount points).

In Android 7 sdcardfs support was added in parallel to FUSE and the "Always block security-sensitive files" functionality was added to sdcardfs in kernel. In Android 9 FUSE was completely removed (from sdcard daemon) but the sdcardfs still blocks creation/deletion of .android_secure directories in the root of emulated filesystem. However as you noticed, it's possible to access the path through original non-emulated mount point i.e. /mnt/media_rw/[UUID]/.android_secure.

For details on filesystem emulation, see What is /storage/emulated/0/?

WHY ROOT CAN'T ACCESS A DIRECTORY?


  How is it ever possible to deny root the ability to list a directory entry?


root is nothing but kernel's dear user. Kernel doesn't stop UID 0 from doing any harm or good. But there are things which are dearer to kernel than root. It includes SELinux 1, Linux capabilities 2 and obviously the filesystem restrictions like we see with FUSE 3 and sdcardfs 4. And like root cannot delete a file with immutable attribute 5. It's possible to remove any such restriction or add more by modifying kernel source.



1 See explanation and example.
2 A simple demonstration:

~# setpriv --bounding-set -sys_admin -- sh -c 'id; mount -o ro,remount /'
uid=0(root) gid=0(root) groups=0(root)
mount: permission denied (are you root?)


3 FUSE documentation:


  "No other user (including root) can access the contents of the mounted filesystem"


4 UID 0 is checked after filename (.android_secure) is checked.
5 Why can't I delete this file as root?



RELATED:


Android's Storage Journey
How to save files to external SD card?