[Xposed General] rovo89:
Thanks, [MENTION=4322181]Tungstwenty[/MENTION]! One thing is for sure: Vendor-specific policies make it even harder.

In my research, I came to the conclusion that AOSP master doesn't have any file contexts which can be written by zygote, system_server and apps. That affects the logfile, so I will probably just send it to logcat for now and think of other ways later.

The safest way to ensure that the JAR file and native libraries are working is probably to put them next to similar files, i.e. to /system/framework and /system/lib.

For modules' config files (shared preferences), it would be enough to have read-only access to app_data_file. Unfortunately, AOSP master and the L preview don't allow this for zygote, and system_server can only read already opened files, but can't open any such files itself.

Zygote has access to some other contexts, like system_data_file, but normals apps don't have write access to it, so all the modules which want to provide settings would have to use su, couldn't use the standard preference screens and so on.

So here is my plan to work around these issues and hopefully keep modules working without any changes on their part. The Xposed API includes an XSharedPreferences class which modules should use to read their settings. If this class could abstract different ways to read a file, it would be transparent to the modules. I think three different ways would be necessary:

1. Direct access. This is the easiest one. Requires chmod o+r, which is the case without SELinux as well. Then it should work for any normal app:

sesearch -A sepolicy_l -c file -p read -s appdomain -t app_data_file
Found 2 semantic av rules:
allow untrusted_app app_data_file : file { ioctl read getattr lock execute execute_no_trans execmod open } ;
allow appdomain app_data_file : file { ioctl read write create getattr setattr lock append unlink link rename open } ;

2. Native binder call to a forked process. system_server has only read/write/getattr (but not open) access to app_data_file. So my idea is to fork a process early in zygote/app_process. In this process, I setcon("u:r:untrusted_app:s0"). Then I have a process running as root in the same domain as normal apps run, so it should be able to read any files written by normal apps. This process could host a binder service implemented in C++ which could receive a filename and return the content of the file. In case method 1 doesn't work (especially for the system_server), the app could make a binder call to that service. Both system_server and appdomain are allowed to do that:

sesearch -A sepolicy_l -c binder -p call -t appdomain
Found 15 semantic av rules:
allow unconfineddomain untrusted_app : binder { call set_context_mgr transfer } ;
allow unconfineddomain system_app : binder { call set_context_mgr transfer } ;
allow mediaserver appdomain : binder { call transfer } ;
allow unconfineddomain shell : binder { call set_context_mgr transfer } ;
allow unconfineddomain isolated_app : binder { call set_context_mgr transfer } ;
allow appdomain appdomain : binder { call transfer } ;
allow unconfineddomain nfc : binder { call set_context_mgr transfer } ;
allow unconfineddomain platform_app : binder { call set_context_mgr transfer } ;
allow drmserver appdomain : binder { call transfer } ;
allow dumpstate appdomain : binder { call transfer } ;
allow unconfineddomain bluetooth : binder { call set_context_mgr transfer } ;
allow system_server appdomain : binder { call transfer } ;
allow surfaceflinger appdomain : binder { call transfer } ;
allow unconfineddomain radio : binder { call set_context_mgr transfer } ;
allow surfaceflinger shell : binder { call transfer } ;

I have also verified in a PoC that the call from context system_server to untrusted_app works. It could theoretically also be used by normal apps of the file is not world readable. It could then make it world readable. But this has to be evaluated later, it depends on how well this service can be protected (system_server can be recognized by its UID, otherwise filename patterns would be an option).

3. Unfortunately, zygote is not allowed to make binder calls, and even if it was, the additional threads created for it can interfere with the startup procedure. So an alternative is needed. Fortunately, there is not much concurrency in zygote and only a few file reading attempts have to be expected. So I would use mmap with MAP_SHARED | MAP_ANONYMOUS to create an anonymous shared memory region that could be used by child processes as well. I believe that this can't be restricted, in contrast to named shared memory (ashmem). Again, I would fork a process and use setcon to let it access the files (actually, it should be possible to use one multi-threaded process for options 2 and 3). The communication between zygote and this child process would happen via the mmap'd area. Zygote would write the filename and some kind of operation code to it, then the child process would write the file content back. I'm using mutex and cond to ensure the proper control flow, which seems to be working fine.

XSharedPreferences would first try option 1, and fall back to either option 2 or 3 (zygote runs as UID 0, so that's probably an easy choice).

[MENTION=4322181]Tungstwenty[/MENTION], [MENTION=631273]Chainfire[/MENTION]: Any comments on these plans?