0

EDITED to reflect progress.

If this question has been answered already, my apologies.

Currently writing an app where content (in a small zip file) is downloaded from an external location and stored inside /data/data/package_name_removed/files/, to be read later.

I currently have a zip file in that directory "Test.zip".

A try-catch loop containing:

//where filename is Test.zip


Log.d("Target file is", sourceContext.getFilesDir() +"/"+ fileName);
File file = new File(sourceContext.getFilesDir() +"/"+ fileName);
ZipFile loadedFile = new ZipFile(file);  

//where sourceContext is passed into this object from the base Activity class

Doesn't seem to work in Marshmallow:

D/Target file is: /data/user/0/package_name_removed/files/Test.zip
W/package_name_removed: type=1400 audit(0.0:11699): avc: denied { open } for name="Test.zip" dev="mmcblk0p29" ino=57426 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:app_data_file:s0 tclass=file permissive=0

This is a Log.d of the IOException getMessage; I think this one's generated from the new File() statement:

D/Log_title_omitted: /data/user/0/package_name_removed/files/Test.zip: open failed: EACCES (Permission denied)

I had this working in Lollipop; was debugging it for pre-lollipop too until I recently upgraded to Marshmallow. I don't think I can safely continue until I sort this out, because it means my app won't support 6.0.

I have managed to write a text file to this directory with no problems whatsoever with the same app, so I do not understand why attempting to open a zip file from that directory doesn't work.

Edit: I have also attempted to unzip the offending zip file to its own directory but to no avail:

//where file is now a json file "Test.json"
//located in .getFilesDir()/Test/
String loadedName = fileName.substring(0, fileName.length() - 5); //I need to reuse the string later.".json" is 5 char.
Log.d("Target is", sourceContext.getFilesDir() +"/"+ loadedName +"/" + fileName);
File file = new File(sourceContext.getFilesDir() + "/"+ loadedStoryName +"/" + fileName);

And got:

D/DOH: /data/user/0/package_name_removed/files/Test/Test.json: open failed: EACCES (Permission denied)
W/package_name_removed: type=1400 audit(0.0:22152): avc: denied { search } for name="Test" dev="mmcblk0p29" ino=57184 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:app_data_file:s0 tclass=dir permissive=0

I understand Marshmallow is really enforcing SELinux now, and I have to code for this eventuality - but I haven't been able to figure out how to get the proper permissions in code. Rightfully I should not need a READ_EXTERNAL anywhere as according to the documentation, there is no need to ask for permissions to the app's own files directory in internal storage.

Any help?

Note: package name omitted, not important.

Floern
  • 33,559
  • 24
  • 104
  • 119
  • "cannot use getFilesDir() here as we must extend Activity" -- no, `getFilesDir()` is implemented on `Context`. "this is part of a generic IO class that is NOT meant to be its own Activity" -- then pass in a `Context` to the method that is doing this work. Or, pass in the `Application` singleton to the constructor of this "generic IO class". Or, pass in `getFilesDir()` to the constructor of this class. Beyond your current problems, your existing code may not work for secondary user accounts on a device. – CommonsWare Dec 31 '15 at 14:37
  • Well ok, passing Context works. However I'm still getting avc: denied { open } on Test.zip. `File file = new File(sourceContext.getFilesDir()+"/"+userDir +"/"+ fileName);` – Larry Larry Dec 31 '15 at 15:38
  • getFilesDir itself currently returns `/data/user/0/package_name_removed/files/`, and this is now consistent with the directory I can write files to in the same app. However I still cannot pass SELinux muster when reading. This is even if I placed the downloaded or copied zip file in files/ and not in files/user1/. Does this mean the user directory is NOT readable unless SELINUX is permissive? That doesn't make sense and would break a lot of apps. – Larry Larry Jan 04 '16 at 02:48
  • "This is even if I placed the downloaded or copied zip file in files/" -- how exactly did you "place" those files? Are you referring to files that your app downloaded? – CommonsWare Jan 04 '16 at 12:15
  • My device is rooted, which is necessary to even see what's going on in data/data. Rooting does not disable SELinux. – Larry Larry Jan 04 '16 at 15:02
  • 1
    "My device is rooted, which is necessary to even see what's going on in data/data" -- no, it's not. Use `adb shell run-as`. "Rooting does not disable SELinux" -- no, but it does not mean that files that you create through a root shell somehow get the same permission bits/ACLs/etc. as do files you create through your application code. `adb shell run-as` *might* behave better in this fashion. Personally, I only ever read from internal storage like this; I only create things in internal storage through application code. – CommonsWare Jan 04 '16 at 15:05
  • Oh, command line-only debugging should be the norm, and the app must actually copy the data itself to its own directory before said data has the correct permission bits? ...makes sense; somewhat inconvenient, but then again I do have to get to the "download to app file directory" part eventually. Thanks, I'll have the app copy the file itself and report the results. – Larry Larry Jan 04 '16 at 15:20
  • Thanks! Having the app do the file copy itself did the trick. – Larry Larry Jan 05 '16 at 03:19
  • Try this it may be work http://stackoverflow.com/a/41221852/5488468 – Bipin Bharti Jan 03 '17 at 10:52

1 Answers1

0

From user CommonsWare:

"Rooting does not disable SELinux" -- no, but it does not mean that files that >you create through a root shell somehow get the same permission bits/ACLs/etc. as >do files you create through your application code. adb shell run-as might behave >better in this fashion.

Yep, it was indeed because I copied the file myself rather than have the app do it; having r permissions across the board is not enough to satisfy SELinux, the app must "own" the file by being the one that "creates" it.

I have yet to test this on the external write directory, but it is true for the internal app's own directory.