Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: It is impossible to open termux's files in another apps. #7437

Closed
twaik opened this issue Aug 30, 2021 · 23 comments
Closed

[Bug]: It is impossible to open termux's files in another apps. #7437

twaik opened this issue Aug 30, 2021 · 23 comments
Labels
bug report Something is not working properly

Comments

@twaik
Copy link
Member

twaik commented Aug 30, 2021

Problem description

I tried a few ways of opening file in another apps but none of them worked.

What steps will reproduce the bug?

am start -a android.intent.action.VIEW -d file:///data/data/com.termux/files/home/fdroid.png -t "image/png" --grant-read-uri-permission
#This one opened image viewer, but file was unavailable.
termux-open-url file://`pwd`/fdroid.png
#answers Error: Activity not started, unable to resolve Intent { act=android.intent.action.VIEW dat=file:///data/data/com.termux/files/home/fdroid.png flg=0x10000000 }
am start -a android.intent.action.SEND -d file:///data/data/com.termux/files/home/fdroid.png -t "image/png" --grant-read-uri-permission
# A target program reported "Unsupported program"

What is the expected behavior?

Files inside Termux's file system should be openable in other apps.

System information

~ $ termux-info
Application version:
0.117
Packages CPU architecture:
aarch64
Subscribed repositories:
# sources.list
deb https://termux.librehat.com/apt/termux-main/ stable main
# game-repo (sources.list.d/game.list)
deb https://packages.termux.org/apt/termux-games games stable
# science-repo (sources.list.d/science.list)
deb https://packages.termux.org/apt/termux-science science stable
Updatable packages:
All packages up to date
Android version:
11
Kernel build information:
Linux localhost 4.19.87-20970822 #1 SMP PREEMPT Fri Aug 6 19:16:20 KST 2021 aarch64 Android
Device manufacturer:
samsung
Device model:
SM-G780F
@twaik twaik added the bug report Something is not working properly label Aug 30, 2021
@Grimler91
Copy link
Member

Have you tried termux-open ~/fdroid.png or termux-share ~/fdroid.png?

@twaik
Copy link
Member Author

twaik commented Aug 30, 2021

Sorry, looks like I am stupid, but I really did not see termux-open
Is there a way to send a file with Intent.FLAG_GRANT_READ_URI_PERMISSION|Intent.FLAG_GRANT_WRITE_URI_PERMISSION?
Or maybe there is a way to bind to Android service and write fd to parcel?

@agnostic-apollo
Copy link
Member

agnostic-apollo commented Aug 30, 2021

The ContentProvider for termux-app has the authority com.termux.files, so you need to use am start --user 0 -a android.intent.action.VIEW -d content://com.termux.files/data/data/com.termux/files/home/downloads/Deep.png -t "image/*" --grant-read-uri-permission com.fstop.photo. It also has android:grantUriPermissions="true" set, which is also required.

You can drop the package or package/activity from end if you want to show system chooser instead of sending to a specific component. Note that the activity in the target app should have the <data android:mimeType="image/*"/> or the relevent mime type in the intent-filter for the activity for this to work. You can use AppManager app for checking out app AndroidManifest.xml.

You can also pass --grant-persistable-uri-permission option in addition to --grant-read-uri-permission for it to get permanent access but target package must call takePersistableUriPermission() to retain access. The --grant-prefix-uri-permission option for FLAG_GRANT_PREFIX_URI_PERMISSION added via 846318a3 also looks interesting. I haven't tested these.

Edit:
Forgot to change test file name. Before y'all start judging Deep.png refers to this. ;)

@twaik
Copy link
Member Author

twaik commented Aug 31, 2021

I did not even think to judge :)
Is it possible to grant write uri permission?

@agnostic-apollo
Copy link
Member

Lolz ;)

Yeah, additionally pass --grant-write-uri-permission. It's mentioned in am --help.

@twaik
Copy link
Member Author

twaik commented Aug 31, 2021

Ok. But I need to know if it will let me do that.
I have seen that Termux grants read permissions (https://github.com/termux/termux-app/blob/9272a757affc0dae4aa044248800f3987e06c52b/app/src/main/AndroidManifest.xml#L175).

But did not see anything about write permissions.

@agnostic-apollo
Copy link
Member

The android:grantUriPermissions doesn't automatically grant it. It allows those flags to work if passed. It should work for both read and write.

@twaik
Copy link
Member Author

twaik commented Aug 31, 2021

Thank you. Looks like it will work in my case. I will check it a bit later.

@agnostic-apollo
Copy link
Member

You are welcome. Good luck!

@twaik
Copy link
Member Author

twaik commented Aug 31, 2021

Should I know anything else about sharing Unix socket?

@twaik
Copy link
Member Author

twaik commented Aug 31, 2021

so you need to use ...

In my case it was

#/data/data/com.termux/files/usr/bin/sh
am start --user 0 -a android.intent.action.VIEW -d content://com.termux.files/data/data/com.termux/files/home/fdroid.png -t "image/*" --grant-read-uri-permission com.sec.android.gallery3d

I think now I can try to share Unix socket. Thank you very much.

@Deligt4l
Copy link

Is this the reason why I can't find termux files on my phone with zarchiver

@twaik
Copy link
Member Author

twaik commented Sep 1, 2021

@Deligt4l No.

@ghost
Copy link

ghost commented Sep 1, 2021

@Deligt4l Termux stores files in private directory which normally can by accessed only either by Termux itself or root user. Other apps can access Termux files only via special Android APIs called "Storage Access Framework".

See https://wiki.termux.com/wiki/Internal_and_external_storage#Access_Termux_from_a_file_manager for examples on how to access Termux home directory in SAF-using applications.

@twaik
Copy link
Member Author

twaik commented Sep 5, 2021

Ok. I figured out how to deal with regular files. But when I am trying to pass there Unix socket there is a problem in a receiver app:

E/ViewReceiverActivity: got intent: Intent { act=android.intent.action.VIEW dat=content://com.termux.files/data/data/com.termux/files/usr/tmp/termux-9ecabe62 typ=termux/x11 flg=0x10000003 pkg=com.termux.x11 cmp=com.termux.x11/.ViewReceiverActivity }
...
I/LorieService: Got Uri: content://com.termux.files/data/data/com.termux/files/usr/tmp/termux-9ecabe62
W/System.err: java.io.FileNotFoundException: open failed: ENXIO (No such device or address)
W/System.err:     at android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:151)
W/System.err:     at android.content.ContentProviderProxy.openAssetFile(ContentProviderNative.java:704)
W/System.err:     at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1819)
W/System.err:     at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1717)
W/System.err:     at com.termux.x11.LorieService.onStartCommand(LorieService.java:197)
W/System.err:     at com.termux.x11.LorieService$IntentRunnable.run(LorieService.java:447)
W/System.err:     at android.os.Handler.handleCallback(Handler.java:938)
W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:99)
W/System.err:     at android.os.Looper.loop(Looper.java:246)
W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:8506)
W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
W/System.err:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)

If I get it right it opens file with a regular open call. That means there is no way to pass Unix socket via am utility.
Is there a way to connect to Java Service using AIDL? I can try to write a small program that opens Unix socket and sends it's fd to Java service. It is much easier than trying to solve it in C.

@twaik
Copy link
Member Author

twaik commented Sep 5, 2021

I think it is also possible to connect/bind sockets after modifying this function:
https://github.com/termux/termux-app/blob/f00738fe3a38e2d49be34fb9b7913d029e681ef0/app/src/main/java/com/termux/app/TermuxOpenReceiver.java#L182-L197
to handle Unix sockets. I mean it can connect to Unix socket if it is present (and accepts connections) or bind it if it is not. It is possible to sign operation as socket by modifying mode, like this
termux-provider.openFile(URI, "srw");
instead of
termux-provider.openFile(URI, "rw");
After getting unix socket fd we can pass it inside ParcelFileDescriptor using ParcelFileDescriptor.adoptFd(int fd).
Is it possible to patch the function this way?
@agnostic-apollo ?

@twaik
Copy link
Member Author

twaik commented Sep 6, 2021

@agnostic-apollo ?

@agnostic-apollo
Copy link
Member

agnostic-apollo commented Sep 8, 2021

The ParcelFileDescriptor.open() does not have any s mode. Check ParcelFileDescriptor.parseMode() for valid values. If you run termux-provider.openFile(URI, "srw"), it will throw a bad mode exception. Also previously only reading r was supported and no other mode, including writing, but latest changes to be released in next termux-app version will allow others if the app has com.termux.RUN_COMMAND permission and you won't need to play around with am command. You will have direct access with ContentProvider.open*().

I don't have much idea on how termux-x11 or Xwayland works. I see that termux-x11 creates a socket file in TMPDIR and listens on it. If that is the case, would it work if termux-app just creates an unbound Socket and returns the ParcelFileDescriptor for it. You can then bind to it in termux-x11. There is a ParcelFileDescriptor ParcelFileDescriptor.fromSocket(Socket socket) function that can be used for this. Note sure how you will handle the lock file.

Moreover, whatever design is finally decided, be it this or some other if you don't want to use sharedUserId will have to go through a security review before app is officially published, since sharing sockets with external apps could expose termux private files or allow arbitrary code execution. Although, I am probably not the right guy for it since most of this stuff is new to me and will take lot of research, which I currently don't have time for. You may wanna read the The Misuse of Android Unix Domain Sockets and Security Implications paper (I haven't fully read it), which exposes multiple app and system daemon vulnerabilities. For ShareIt app, check here. Abstract namespace sockets should not be used. There are also some other alternatives for IPC on this blog and its github. World accessible permissions for files/sockets are gone too if you targetSdkVersion >=28, check here and here.

p.s My responses can take time, often days and weeks, lot of things going on.

@agnostic-apollo
Copy link
Member

Closing since opening files is actually possible.

@twaik
Copy link
Member Author

twaik commented Sep 8, 2021

@agnostic-apollo I meant openFile can check if String mode if it contains s and bind/connect to a socket in this location. Also I think it is possible to check if there is + symbol and create a file for writing. After a check you can exclude those symbols from mode.

Anyway I think I found another solution.
I can use TermuxAm's code that sends intents to Android and start my Activity with Bundle containing IBinder token. It is possible to send ParcelFileDescriptor via this token. Also it is possible to read termux-app's preferences (like extra keys layout) and send them via this token. Or do something else, maybe more interesting. This solution worked when I used it inside Activities, I still did not check it inside with Termux.

But anyway thank you very much for help.

@agnostic-apollo
Copy link
Member

I meant openFile can check if String mode if it contains s

That should be doable.

it is possible to check if there is + symbol and create a file for writing.

You can already write if you pass wt and get the ParcelFileDescriptor.

ParcelFileDescriptor parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uri, "wt");
FileOutputStream fileOutputStream = new FileOutputStream(parcelFileDescriptor.getFileDescriptor());

Also it is possible to read termux-app's preferences (like extra keys layout) and send them via this token.

You can directly read the file with ContentProvider and save it in a file in your own app's private data and then load the SharedProperties with that custom path and then use getExtraKeysInfo().

It is possible to send ParcelFileDescriptor via this token.

That is probably not going to be possible across processes due to permission issues, check here.

But anyway thank you very much for help.

Welcome.

@twaik
Copy link
Member Author

twaik commented Sep 8, 2021

You can directly read the file with ContentProvider

Actually it is not possible. ContentProvider checks if path starts with TermuxConstants.TERMUX_FILES_DIR_PATH.

That is probably not going to be possible across processes due to permission issues, check here.

I'm already trying to use a solution described in this link.

@agnostic-apollo
Copy link
Member

Actually it is not possible. ContentProvider checks if path starts with TermuxConstants.TERMUX_FILES_DIR_PATH.

The termux-app only stores minimal and dangerous settings in SharedPreferences that you see in Termux Settings inside the app. All other user config is stored in /data/data/com.termux/files/home/.termux/termux.properties which is under TERMUX_FILES_DIR_PATH, including extra keys and loaded via SharedProperties. Write support is currently not there for later since .properties files also have comments and escapes, so in-place editing would be required to update values. Benefit of using SharedProperties instead of SharedPreferences is that all user config gets backed up during user backups and is accessible via shell as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug report Something is not working properly
Projects
None yet
Development

No branches or pull requests

4 participants