1

I have a python script that relies on the execution of an .exe file. It uses the subprocess module like this:

subprocess.run([
            "ffmpeg/ffmpeg.exe",
            url,
            path])

The python script works normally up until the above instruction is interpreted, then I get this exception:

PermissionError: [Errno 13] Permission denied: PosixPath('storage/emulated/legacy/scripts/ffmpeg/ffmpeg.exe')

The directories are ordered like this:

"/scripts/pyscript.py

/scripts/ffmpeg/ffmpeg.exe"

I'm running Termux on an android device not rooted. I have already tried changing file permissions with chmod but I get "Operation not permitted".

Do you have any workaround?

shin
  • 333
  • 3
  • 11
  • 2
    Note that UNIX executables usually don't have `.exe` extensions at all. – Charles Duffy Dec 27 '20 at 19:04
  • 1
    Beyond that -- it's good practice to mount paths that aren't supposed to have executables with the `noexec` flag, which makes everything under that path non-executable no matter what the filesystem permissions are. If the Android build you're using does that, with my security hat on, I approve. – Charles Duffy Dec 27 '20 at 19:05
  • @CharlesDuffy you're right! I'll try using ffmpeg for linux and I'll let you know. Thanks. – shin Dec 27 '20 at 19:07
  • 2
    I'd check the contents of `/proc/mounts` to see if the `noexec` flag is set for `/storage` before you try copying in a different executable -- and be sure you check whether that executable is statically or dynamically linked, and if the latter, whether the libraries it tries to link to exist. Android will generally have a much smaller set of native libraries than your typical Linux distro. – Charles Duffy Dec 27 '20 at 19:08
  • @CharlesDuffy where can I check the noexec flag? – shin Dec 27 '20 at 19:09
  • As I said before, read the content of the file `/proc/mounts`. Just `cat /proc/mounts` is the simplest way to do that. – Charles Duffy Dec 27 '20 at 19:10
  • @CharlesDuffy yes I can see noexec on storage/emulated/legacy/ – shin Dec 27 '20 at 19:23
  • 1
    BTW, in general, I'd try to get `ffmpeg` to where you can run it from a shell before bringing Python into play. And once you have a native Linux executable (note that it needs to be compiled for your phone's platform -- probably some ARM variant -- so an executable for Intel chips won't do), you can use `ldd` to list which libraries it needs. – Charles Duffy Dec 27 '20 at 19:23
  • 1
    Okay, if there's a `noexec` on `storage/emulated/legacy`, then you'll ned to find a different place to write the executable, somewhere that _doesn't_ have that flag... that, or invoke the dynamic linker manually -- for more on that, see [Subverting the execute flag on Linux systems: Why is this possible?](https://superuser.com/questions/456304/subverting-the-execute-flag-on-linux-systems-why-is-this-possible) -- though if the Android system in question is sufficiently hardened, that may not work. – Charles Duffy Dec 27 '20 at 19:24
  • 1
    Honestly, it's an intentional feature, not a bug, that non-interpreted code execution is restricted on an unrooted device -- the Google play store does a bunch of heuristics on code in the store to try to sniff out things that smell malicious; if it's easy to install software that hasn't gone through those tests by downloading it as a file into storage, that makes it easy to bypass those safety features. Thus, if you find an easy workaround, that's arguably indicative of either Google's security team or your phone vendor not doing their job well. – Charles Duffy Dec 27 '20 at 19:29
  • @CharlesDuffy the problem is that storage/emulated/legacy is as far back as I can go with these permissions, it's also the directory I see when I connect the android device to a computer and open "internal storage". I know it's meant to not allow me to do that, I was just wondering if there was an easy workaround. Thank you for you help! – shin Dec 27 '20 at 19:37
  • _nod_. The thing about this being the subject of ongoing cat-and-mouse games (wherein folks making malicious applications are trying to discover new holes and Google is trying to close them) is that it's all very in-flux; something that works today may not work after the next security update that comes out for your device, so it's next-to-impossible to say what will work on a device I haven't seen. – Charles Duffy Dec 27 '20 at 19:41
  • One suggestion: Consider trying to get ffmpeg working on a _rooted_ device first; once you have that going, you know you have a binary compiled for the correct architecture, depending on only available dynamic libraries, etc, such that the only issues outstanding are certain to be ones specific to needing to defeat the security model. – Charles Duffy Dec 27 '20 at 21:15
  • @CharlesDuffy thanks for the suggestion but I need the script to work on a non rooted device anyway. I'll try to see if there's another way to make it work on android. – shin Dec 27 '20 at 22:10
  • 1
    I realize that's what you need, but trying to get there all as one step means you're fighting two separate sets of issues at once, instead of first one set and then addressing the second set only after you know the first set of issues are solved. Taking smaller steps makes isolating individual issues easier. – Charles Duffy Dec 27 '20 at 22:43
  • If I had a rooted device I would have tried, even just out of curiosity. Thank you for your time. – shin Dec 28 '20 at 12:08

1 Answers1

-2

You have two option:

First you could change the permission of the file to Everyone or execute chmod 777 if your on linux.

or

you could run the script as admin.

For that you can use this as a reference.

Lukas Neumann
  • 656
  • 5
  • 18
  • I'm on android and I'm using Termux as a shell. Do you think the second solution might work? – shin Dec 27 '20 at 18:59
  • `chmod -x` is _removing_ execute permission, not adding it. And even as root/administrator, one still can't run files as executables when they're `a-x` without tricks like invoking the interpreter (`ld.so` for a dynamically-linked ELF binary) explicitly. – Charles Duffy Dec 27 '20 at 19:06
  • Ok, sorry about that, the second solution wont work too, but maybe its enough if you assign termux storage permissions with the command "termux-setup-storage" (https://wiki.termux.com/wiki/Termux-setup-storage) – Lukas Neumann Dec 27 '20 at 19:09
  • `chmod 777` should **never** be done, ever, under any circumstances at all. It lets even completely untrusted users like `nobody` (which is used for things like running first-line authentication code for inbound network connections) change a file that trusted users like `root` can then execute; that's a fast route to security disasters -- when I'm trying to take over a machine in a CTF and have taken over only a low-privileged account, one of the very first things I (or any other attacker) will do is look for files I can write to that other more-privileged users are executing. – Charles Duffy Dec 27 '20 at 19:11
  • ...just `chmod 755` is good enough to give both read and execute to the entire world; there's no reason to make the "other" bitmask `7`, and lots of good reasons not to. (The "group" bitmask sometimes there's a good reason, but usually it's just fine as `5` as well, unless you know what you're doing and have a specific reason). – Charles Duffy Dec 27 '20 at 19:16