Skip to content
This repository has been archived by the owner on Aug 2, 2023. It is now read-only.

Caused by: java.io.IOException: error=13, Permission denied #23

Open
AmanArora1987 opened this issue Dec 27, 2020 · 2 comments
Open

Caused by: java.io.IOException: error=13, Permission denied #23

AmanArora1987 opened this issue Dec 27, 2020 · 2 comments

Comments

@AmanArora1987
Copy link

Hi,

I am getting below error on device Android 11 (OnePlus 8)

E/StunnelProcessManager: failure
    java.io.IOException: Cannot run program "/data/user/0/link.infra.sslsocks/files/stunnel" (in directory "/data/user/0/link.infra.sslsocks/files"): error=13, Permission denied
        at java.lang.ProcessBuilder.start(ProcessBuilder.java:1050)
        at java.lang.Runtime.exec(Runtime.java:699)
        at java.lang.Runtime.exec(Runtime.java:529)
        at link.infra.sslsocks.service.StunnelProcessManager.start(StunnelProcessManager.java:106)
        at link.infra.sslsocks.service.StunnelIntentService.handleStart(StunnelIntentService.java:81)
        at link.infra.sslsocks.service.StunnelIntentService.onHandleIntent(StunnelIntentService.java:69)
        at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:77)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:245)
        at android.os.HandlerThread.run(HandlerThread.java:67)
     Caused by: java.io.IOException: error=13, Permission denied
        at java.lang.UNIXProcess.forkAndExec(Native Method)
        at java.lang.UNIXProcess.<init>(UNIXProcess.java:133)
        at java.lang.ProcessImpl.start(ProcessImpl.java:141)
        at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
@lo1ol
Copy link

lo1ol commented Jun 16, 2021

Hi, it's new demand of Android Q: application can't run executable from application files dir: https://stackoverflow.com/questions/60370424/permission-is-denied-using-android-q-ffmpeg-error-13-permission-denied

Stunnel app has to be inside /data/app/${sslsocks}/lib/${arch} dir. I try to create a patch for this

@lo1ol
Copy link

lo1ol commented Jun 16, 2021

This patch works for me. Notice you have to put stunnel to app/src/main/jniLibs/${arch}/ dir and rename it to stunnel.so.

For example:
app/src/main/jniLibs/arm64-v8a/stunnel.so
or:
app/src/main/jniLibs/armeabi-v7a/stunnel.so

diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 5cdc764..b73ec30 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -15,6 +15,7 @@
         android:roundIcon="@mipmap/ic_launcher_round"
         android:supportsRtl="true"
         android:theme="@style/AppTheme"
+        android:extractNativeLibs = "true"
         tools:ignore="GoogleAppIndexingWarning">
         <activity
             android:name=".gui.AdvancedSettingsActivity"
diff --git a/app/src/main/java/link/infra/sslsocks/Constants.java b/app/src/main/java/link/infra/sslsocks/Constants.java
index 150decb..f8026dd 100644
--- a/app/src/main/java/link/infra/sslsocks/Constants.java
+++ b/app/src/main/java/link/infra/sslsocks/Constants.java
@@ -1,7 +1,7 @@
 package link.infra.sslsocks;
 
 public class Constants {
-	public static final String EXECUTABLE = "stunnel";
+	public static final String EXECUTABLE = "stunnel.so";
 	public static final String CONFIG = "config.conf";
 	public static final String PSKSECRETS = "psksecrets.txt";
 	public static final String PID = "pid";
diff --git a/app/src/main/java/link/infra/sslsocks/gui/main/MainActivity.java b/app/src/main/java/link/infra/sslsocks/gui/main/MainActivity.java
index f247412..5ac985a 100644
--- a/app/src/main/java/link/infra/sslsocks/gui/main/MainActivity.java
+++ b/app/src/main/java/link/infra/sslsocks/gui/main/MainActivity.java
@@ -85,7 +85,7 @@ public class MainActivity extends AppCompatActivity implements KeyFragment.OnLis
 		});
 
 		// attempt extraction in activity, to make service start faster
-		StunnelProcessManager.checkAndExtract(this);
+		StunnelProcessManager.checkStunnel(this);
 		StunnelProcessManager.setupConfig(this);
 
 		// Create the NotificationChannel, but only on API 26+ because
diff --git a/app/src/main/java/link/infra/sslsocks/service/StunnelProcessManager.java b/app/src/main/java/link/infra/sslsocks/service/StunnelProcessManager.java
index 75cf422..266a59e 100644
--- a/app/src/main/java/link/infra/sslsocks/service/StunnelProcessManager.java
+++ b/app/src/main/java/link/infra/sslsocks/service/StunnelProcessManager.java
@@ -2,11 +2,14 @@ package link.infra.sslsocks.service;
 
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
 import android.content.res.AssetManager;
 import android.util.Log;
 
 import androidx.preference.PreferenceManager;
 
+import android.content.pm.PackageManager;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.InterruptedIOException;
@@ -40,27 +43,25 @@ public class StunnelProcessManager {
 		return false;
 	}
 
-	public static void checkAndExtract(Context context) {
-		File execFile = new File(context.getFilesDir().getPath() + "/" + EXECUTABLE);
-		if (execFile.exists() && !hasBeenUpdated(context)) {
-			return; // already extracted
-		}
+	private static String getExecDir(Context context) {
+		String libraryDir = null;
+		try {
+			PackageManager p = context.getPackageManager();
+			libraryDir = p.getApplicationInfo("link.infra.sslsocks", 0).nativeLibraryDir;
+		} catch(PackageManager.NameNotFoundException e) {
 
-		//noinspection ResultOfMethodCallIgnored
-		execFile.getParentFile().mkdir();
+		}
 
-		// Extract stunnel exectuable
-		AssetManager am = context.getAssets();
-		try (BufferedSource in = Okio.buffer(Okio.source(am.open(EXECUTABLE)));
-		     BufferedSink out = Okio.buffer(Okio.sink(execFile))) {
-			out.writeAll(in);
+		return libraryDir;
+	}
 
-			//noinspection ResultOfMethodCallIgnored
-			execFile.setExecutable(true);
+	public static void checkStunnel(Context context) throws RuntimeException{
+		File execFile = new File(getExecDir(context) + "/" + EXECUTABLE);
 
-			Log.d(TAG, "Extracted stunnel binary successfully");
-		} catch (Exception e) {
-			Log.e(TAG, "Failed stunnel extraction: ", e);
+		if (execFile.exists() && !hasBeenUpdated(context)) {
+			return;
+		} else {
+			throw new RuntimeException("Stunnel app doesn't exists. Move it to app/src/main/jniLibs/${arch} as stunnel.so");
 		}
 	}
 
@@ -90,13 +91,14 @@ public class StunnelProcessManager {
 		if (stunnelProcess != null || pidFile.exists()) {
 			stop(context);
 		}
-		checkAndExtract(context);
+
+		checkStunnel(context);
 		setupConfig(context);
 		context.clearLog();
 		try {
 			String[] env = new String[0];
 			File workingDirectory = new File(context.getFilesDir().getPath());
-			stunnelProcess = Runtime.getRuntime().exec(context.getFilesDir().getPath() + "/" + EXECUTABLE + " " + CONFIG, env, workingDirectory);
+			stunnelProcess = Runtime.getRuntime().exec(getExecDir(context) + "/" + EXECUTABLE + " " + CONFIG, env, workingDirectory);
 			readInputStream(context, Okio.buffer(Okio.source(stunnelProcess.getErrorStream())));
 			readInputStream(context, Okio.buffer(Okio.source(stunnelProcess.getInputStream())));
 			stunnelProcess.waitFor();
@@ -162,12 +164,12 @@ public class StunnelProcessManager {
 		if (stunnelProcess != null || pidFile.exists()) {
 			stop(context);
 		}
-		checkAndExtract(context);
+		checkStunnel(context);
 		try {
 			String[] env = new String[0];
 			File workingDirectory = new File(context.getFilesDir().getPath());
 			// Make the process fail, so we can extract just the version from the error stream
-			stunnelProcess = Runtime.getRuntime().exec(context.getFilesDir().getPath() + "/" + EXECUTABLE + " THISFILESHOULDNOTEXIST", env, workingDirectory);
+			stunnelProcess = Runtime.getRuntime().exec(getExecDir(context) + "/" + EXECUTABLE + " THISFILESHOULDNOTEXIST", env, workingDirectory);
 			BufferedSource errors = Okio.buffer(Okio.source(stunnelProcess.getErrorStream()));
 
 			Pattern versionPattern = Pattern.compile("stunnel ([\\d.]+)");

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants