XposedBridge icon indicating copy to clipboard operation
XposedBridge copied to clipboard

Preferences of a module cannot be read from different process on some devices running MM

Open C3C0 opened this issue 8 years ago • 25 comments

I have couple of reports from the users of my module that the preferences set in the settings part of a module don't stick. Unfortunately, I don't have any technical details about devices where that happens nor logs, but couple of users were the owners of Nexus 6P. I guess it has something to do with SeLinux or some other security restrictions. Could it be related to e.g. systemless rooting method? I run my module on couple of marshmallow nexus devices without any issues. My devices have modified kernel to allow classic SuperSU. I'm not using systemless root.

C3C0 avatar Dec 06 '15 10:12 C3C0

I can confirm that on a Nexus 5. I was no longer able to read or write module settings from e.g. SystemUI context when I switched to M. I ended up using a content provider instead. Am 06.12.2015 11:27 schrieb "C3C0" [email protected]:

I have couple of reports from the users of my module that the preferences set in the settings part of a module don't stick. Unfortunately, I don't have any technical details about devices where that happens nor logs, but couple of users were the owners of Nexus 6P. I guess it has something to do with SeLinux or some other security restrictions. Could it be related to e.g. systemless rooting method? I run my module on couple of marshmallow nexus devices without any issues. Those devices have modified kernel to allow classic SuperSU.

— Reply to this email directly or view it on GitHub https://github.com/rovo89/XposedBridge/issues/74.

theknut avatar Dec 06 '15 10:12 theknut

Then it would be interesting to know the difference between setup of my and your N5 since I don't have any problems reading preferences within SystemUI process on mine.

C3C0 avatar Dec 06 '15 10:12 C3C0

I'm not near my PC right now, but this sounds like the known issue I mentioned in the Marshmallow release announcement. It's an SELinux restriction that I didn't find any solution for yet.

rovo89 avatar Dec 06 '15 11:12 rovo89

I have some new information. Found out that devices which suffer from this are those with permissions of shared_prefs folder being drwx------ My N5X has permissions of this folder set as drwxrwx--x without me doing any manual changes. screenshot_20151209-103241_2 What could be causing this difference? One solution would be for my module to set proper permissions in boot completed receiver although it's too late. But at least it would prepare correct permissions for the next reboot cycle.

C3C0 avatar Dec 09 '15 13:12 C3C0

Why not setting the proper permission while closing the App (onpause or ondestroy)?

I have the same issue with my TW module on some LL FWs and i use this workaround.

wanam avatar Dec 09 '15 13:12 wanam

@wanam like setReadble(true, false) on the SharedPrefs XML file in onPause and onDestroy or by using some sort of shell command?

Additonal Info I found: I have two devices, one kitkat which my module works fine on, while the marshmallow one always fails to read. Seems for the shared prefs XML file the Kitkat device has 'rw-rw-r--' (0664) while the marshmallow device has 'rw-rw----'(0660). And when changing it to 664 in root explorer it works, but will change back on restart.

EDIT: I put new File("/data/data/PACKAGE_NAME/shared_prefs/PACKAGE_NAME_preferences.xml").setReadable(true, false); in all activities's onPause and onDestroy. When you attempt to read the preferences in initZygote(...) it says its doesn't exist, and is not world- or file- readable but can still get data from the XML file, which can be shown by prefs.getAll.size(). When handleLoadPackage(..) is executed, it will be completely readable. Note, I also refresh/reload the preferences in each hook (to update settings on runtime). A dodgy workaround but still works.

pbombnz avatar Jan 09 '16 06:01 pbombnz

@pbombnz Actually setReadble(true, false) is not enough on MM (at least on my case TW MM), as it just sets 660 permission, we need to set it to 664 to get a readable prefs on the module process.

The only way that seems to work properly for me is to set it through the PreferenceFragment:

getPreferenceManager().setSharedPreferencesMode(Context.MODE_WORLD_READABLE);
getPreferenceManager().setSharedPreferencesName(YourActivity.class.getSimpleName());
sharedPref = getActivity().getPreferences(Context.MODE_WORLD_READABLE);

I change the prefs file name to the activity's simple name because it's used on "getActivity().getPreferences" that seems the only method that still sets the required permission "664" for the flag "MODE_WORLD_READABLE".

wanam avatar Jan 19 '16 13:01 wanam

Having the same problem with my Xposed module on a Nexus 5 running MM. It seems like SELinux is kicking in as I found these AVCs: system:ui: type=1400 audit(0.0:49): avc: denied { search } for name="com.fifsource.android.resolveractivitytweaks" dev="mmcblk0p23" ino=603480 scontext=u:r:system_app:s0 tcontext=u:object_r:app_data_file:s0:c512,c768 tclass=dir permissive=0

Yep, the system UI cannot read data in packages. Are there any solutions?

F-i-f avatar Mar 01 '16 21:03 F-i-f

@F-i-f Normally, if the hooked method is in system process, it's in system process; and the hooked method in app process, it's in app process. So, don't read app's files in system process. The hooked app can get rid of the xposed if it's in app's process. (I do this in my xposed module Prevent Running.)

For Prevent Running (not just a xposed module), I never read the file from system process (This works in below 4.4, but doesn't work in 5.0+). I use other android component to read/write files, like content provider and receiver.

liudongmiao avatar Mar 02 '16 04:03 liudongmiao

@F-i-f Yep, that's exactly the issue we're talking about here. There's no solution to this yet.

rovo89 avatar Mar 02 '16 07:03 rovo89

@rovo89 but, why app can read /data/de.robv.android.xposed.installer/log/error.log?

liudongmiao avatar Mar 02 '16 12:03 liudongmiao

Which app? The issue is that system apps can't access data files from user apps. Xposed Installer can obviously read its own data files.

rovo89 avatar Mar 02 '16 13:03 rovo89

The error.log is logged by xposed module, and by system process too.

And, of course, prevent running (http://repo.xposed.info/module/me.piebridge.forcestopgb) read /data/de.robv.android.xposed.installer/log/error.log directly when it's not activated in xposed installer.

https://github.com/liudongmiao/ForceStopGB/blob/master/src/me/piebridge/prevent/ui/util/ReportUtils.java#L48 I always received the error.log.

liudongmiao avatar Mar 02 '16 14:03 liudongmiao

The error.log is logged by xposed module, and by system process too.

Not anymore. Since Lollipop, I changed XposedBridge.log() to write only to Logcat. An additional daemon starts logcat and write the output to a file. This daemon process runs with the same SELinux context as a user app.

I always received the error.log.

Yes, the SELinux rules permit accessing data files of the same user account (if you have a multi-user ROM) as long as the Unix permissions are WORLD_READABLE. System apps like the System UI are a separate category and cannot access any user app's files.

rovo89 avatar Mar 02 '16 16:03 rovo89

Got it. I didn't know why xposed can write file to xposed installer's app. I will look into the codes.

For my xposed module (As I said, not just a xposed module), I use content-provider to send log from system process to user app process.

liudongmiao avatar Mar 03 '16 02:03 liudongmiao

@rovo89

The issue is that system apps can't access data files from user apps.

Well I found out you can from the initZygoteHook, but once the framework is fully launched, selinux kicks in and it's over. It means that the user has to reboot to enact some changes which need to propagate to system ui, which is annoying, but not a deal-breaker.

How can I communicate from the system ui to my app for exchanging settings? I've read that the content provider route seems the easiest, but I don't have a context in system ui, therefore I don't seem to be able to query the provider.

F-i-f avatar Mar 04 '16 07:03 F-i-f

Ran in to this issue when working with com.android.Settings and ended up using a content provider to resolve. Found a great implementation on github that was pretty much everything I needed.

https://github.com/hamsterksu/MultiprocessPreferences

afxefx avatar May 18 '16 13:05 afxefx

On Wed, 2016-05-18 at 06:59 -0700, afxefx wrote:

Ran in to this issue when working with com.android.Settings and ended up using a content provider to resolve. Found a great implementation on github that was pretty much everything I needed.

Would you mind sharing that github repo? Thanks.

F-i-f avatar May 19 '16 15:05 F-i-f

I did lol at least it's showing for me but here you go:

https://github.com/hamsterksu/MultiprocessPreferences

and just in case the link doesn't show here's the link in text format:

https://github.com/hamsterksu/MultiprocessPreferences

afxefx avatar May 19 '16 15:05 afxefx

Shameless self promotion: I recently wrote a similar library, which is compatible with the SharedPreferences API: https://github.com/apsun/RemotePreferences

This one offers granular access control to preferences (so you can deny third party apps from reading/writing your preferences, which could be a security issue). Also, registerOnSharedPreferenceChangeListener works (yes, even across processes, so you can use it in your Xposed module).

apsun avatar May 25 '16 01:05 apsun

@rovo89 is there any chance the XposedBridge itself could use a content provider based solution for XSharedPreferences so modules that aren't rewritten for MM could start working? As a bonus that looks like it would potentially allow writing to prefs from the module side too.

davidgro avatar May 28 '16 20:05 davidgro

is there any chance the XposedBridge itself could use a content provider based solution for XSharedPreferences so modules that aren't rewritten for MM could start working?

Generally, that would be a possiblity, but several things like the requirement of a Context and security aspects have to be considered carefully.

As a bonus that looks like it would potentially allow writing to prefs from the module side too.

Yeah, but the UI also has to use SharedPreferences in the same way. The good thing about the standard preferences saved in XML files is that you can easily and out-of-the-box create complex preferences UIs - not sure if it's possible to make them write to the content provider instead.

rovo89 avatar May 29 '16 16:05 rovo89

Yeah, but the UI also has to use SharedPreferences in the same way. The good thing about the standard preferences saved in XML files is that you can easily and out-of-the-box create complex preferences UIs - not sure if it's possible to make them write to the content provider instead.

Not necessarily, you can just back your ContentProvider with SharedPreferences instead of a real database. Since the provider is running in the same context as the config app process, it can access the preferences directly. That way you can keep on using PreferenceFragment, etc.

Remote preference accesses (e.g. from an Xposed module running in a different process) go like this: App code -> ContentResolver -> ContentProvider -> SharedPreferences

Local preference accesses (e.g. configuration activity for the module) keep using the direct method: App code -> SharedPreferences

Not too sure on the Context requirement. For normal apps, it should be possible to just hook android.app.Application and get a Context object from that (I think).

apsun avatar May 30 '16 09:05 apsun

On Mon, 2016-05-30 at 02:21 -0700, Andrew Sun wrote:

    Yeah, but the UI also has to use SharedPreferences in the same
    way. The good thing about the standard preferences saved in
    XML files is that you can easily and out-of-the-box create
    complex preferences UIs - not sure if it's possible to make
    them write to the content provider instead.

8< snip >8

Not too sure on the Context requirement. For normal apps, it should be possible to just hook android.app.Application and get a Context object from that (I think).

That's the hard part. Most of the Xposed modules shared preferences breaking on MM is due to system-level apps being denied access to user-level app data by SELinux. User-installed-app-to-user-installed-app shared prefs is not a problem as the usual "chmod 666" trick is still effective (for how long we don't know). But any module that need to retrieve shared prefs from say the System UI gets an AVC denial. And it's hard to get a Context from the System UI (at least for me).

I was wondering if patching the SELinux policy to allow system-level apps to read user-level app data would be an acceptable middle ground. I think that if system-level apps are compromised, you're already hosed anyways. That choice could be left to the user, for example in the Xposed installer.

Phil.

F-i-f avatar May 30 '16 18:05 F-i-f

And it's hard to get a Context from the System UI (at least for me).

Really? I thought you could just use SystemUIApplication for hooks running in SystemUI (haven't tried myself though, I've always been able to get it out of the constructor somehow).

apsun avatar May 31 '16 08:05 apsun