From b4b9edba8629406b9fe618a02731f36d926a66db Mon Sep 17 00:00:00 2001 From: Davinder Singh Date: Mon, 24 Jun 2019 10:43:39 +0100 Subject: [PATCH 1/2] use native lib dir instead of assets to pack rclone executables on android q, calling exec() on writable application files is a W^X (https://en.wikipedia.org/wiki/W%5EX) violation and represents an unsafe application practice. this commit, makes executable code to load from (read-only) native library directory also used for jni. --- app/build.gradle | 5 +++ .../arm64-v8a/librclone.so} | Bin .../armeabi-v7a/librclone.so} | Bin .../rclone-x86_32 => lib/x86/librclone.so} | Bin .../java/ca/pkay/rcloneexplorer/Rclone.java | 40 ++---------------- 5 files changed, 8 insertions(+), 37 deletions(-) rename app/{src/main/assets/rclone-arm64 => lib/arm64-v8a/librclone.so} (100%) rename app/{src/main/assets/rclone-arm32 => lib/armeabi-v7a/librclone.so} (100%) rename app/{src/main/assets/rclone-x86_32 => lib/x86/librclone.so} (100%) diff --git a/app/build.gradle b/app/build.gradle index 5586255..45eb942 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,6 +17,11 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + sourceSets { + main { + jniLibs.srcDirs = ["lib"] + } + } } repositories { diff --git a/app/src/main/assets/rclone-arm64 b/app/lib/arm64-v8a/librclone.so similarity index 100% rename from app/src/main/assets/rclone-arm64 rename to app/lib/arm64-v8a/librclone.so diff --git a/app/src/main/assets/rclone-arm32 b/app/lib/armeabi-v7a/librclone.so similarity index 100% rename from app/src/main/assets/rclone-arm32 rename to app/lib/armeabi-v7a/librclone.so diff --git a/app/src/main/assets/rclone-x86_32 b/app/lib/x86/librclone.so similarity index 100% rename from app/src/main/assets/rclone-x86_32 rename to app/lib/x86/librclone.so diff --git a/app/src/main/java/ca/pkay/rcloneexplorer/Rclone.java b/app/src/main/java/ca/pkay/rcloneexplorer/Rclone.java index 6e4a513..a3a856f 100644 --- a/app/src/main/java/ca/pkay/rcloneexplorer/Rclone.java +++ b/app/src/main/java/ca/pkay/rcloneexplorer/Rclone.java @@ -3,7 +3,6 @@ import android.content.Context; import android.content.SharedPreferences; import android.net.Uri; -import android.os.Build; import android.os.Environment; import android.preference.PreferenceManager; import android.webkit.MimeTypeMap; @@ -45,7 +44,7 @@ public class Rclone { public Rclone(Context context) { this.context = context; - this.rclone = context.getFilesDir().getPath() + "/rclone"; + this.rclone = context.getApplicationInfo().nativeLibraryDir + "/librclone.so"; this.rcloneConf = context.getFilesDir().getPath() + "/rclone.conf"; log2File = new Log2File(context); } @@ -846,44 +845,11 @@ public void exportConfigFile(Uri uri) throws IOException { } public boolean isRcloneBinaryCreated() { - String appsFileDir = context.getFilesDir().getPath(); - String exeFilePath = appsFileDir + "/rclone"; - File file = new File(exeFilePath); + File file = new File(rclone); return file.exists() && file.canExecute(); } public void createRcloneBinary() throws IOException { - String appsFileDir = context.getFilesDir().getPath(); - String rcloneArchitecture = null; - String[] supportedABIS = Build.SUPPORTED_ABIS; - if (supportedABIS[0].toUpperCase().contains("ARM")) { - if (supportedABIS[0].contains("64")) { - rcloneArchitecture = "rclone-arm64"; - } else { - rcloneArchitecture = "rclone-arm32"; - } - } else if (supportedABIS[0].toUpperCase().contains("X86")) { - if (supportedABIS[0].contains("64")) { - rcloneArchitecture = "rclone-x86_32"; - } else { - rcloneArchitecture = "rclone-x86_32"; - } - } else { - System.exit(1); - } - String exeFilePath = appsFileDir + "/rclone"; - InputStream inputStream = context.getAssets().open(rcloneArchitecture); - File outFile = new File(appsFileDir, "rclone"); - FileOutputStream fileOutputStream = new FileOutputStream(outFile); - - byte[] buffer = new byte[4096]; - int offset; - while ((offset = inputStream.read(buffer)) > 0) { - fileOutputStream.write(buffer, 0, offset); - } - inputStream.close(); - fileOutputStream.close(); - - Runtime.getRuntime().exec("chmod 0777 " + exeFilePath); + // this.rclone is extracted by Android during app installation } } From ce00f349dd3818e3764b67d50ed3f49dc85f8900 Mon Sep 17 00:00:00 2001 From: Davinder Singh Date: Mon, 24 Jun 2019 10:56:36 +0100 Subject: [PATCH 2/2] remove unneeded binary extraction functions --- .../ca/pkay/rcloneexplorer/MainActivity.java | 48 +------------------ .../java/ca/pkay/rcloneexplorer/Rclone.java | 9 ---- .../pkay/rcloneexplorer/SharingActivity.java | 2 +- 3 files changed, 3 insertions(+), 56 deletions(-) diff --git a/app/src/main/java/ca/pkay/rcloneexplorer/MainActivity.java b/app/src/main/java/ca/pkay/rcloneexplorer/MainActivity.java index 2ea2b27..a04bec6 100644 --- a/app/src/main/java/ca/pkay/rcloneexplorer/MainActivity.java +++ b/app/src/main/java/ca/pkay/rcloneexplorer/MainActivity.java @@ -140,9 +140,7 @@ public void onClick(View v) { int currentVersionCode = BuildConfig.VERSION_CODE; String currentVersionName = BuildConfig.VERSION_NAME; - if (!rclone.isRcloneBinaryCreated()) { - new CreateRcloneBinary().execute(); - } else if (lastVersionCode < currentVersionCode || !lastVersionName.equals(currentVersionName)) { + if (lastVersionCode < currentVersionCode || !lastVersionName.equals(currentVersionName)) { // In version code 24 there were changes to app shortcuts // Remove this in the long future if (lastVersionCode <= 23) { @@ -150,7 +148,7 @@ public void onClick(View v) { AppShortcutsHelper.populateAppShortcuts(this, rclone.getRemotes()); } - new CreateRcloneBinary().execute(); + startRemotesFragment(); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putInt(getString(R.string.pref_key_version_code), currentVersionCode); @@ -513,48 +511,6 @@ public void removeRemoteFromNavDrawer() { pinRemotesToDrawer(); } - @SuppressLint("StaticFieldLeak") - private class CreateRcloneBinary extends AsyncTask { - - private LoadingDialog loadingDialog; - - @Override - protected void onPreExecute() { - super.onPreExecute(); - loadingDialog = new LoadingDialog() - .setTitle(R.string.creating_rclone_binary) - .setCanCancel(false); - loadingDialog.show(getSupportFragmentManager(), "loading dialog"); - } - - @Override - protected Boolean doInBackground(Void... voids) { - try { - rclone.createRcloneBinary(); - } catch (IOException e) { - e.printStackTrace(); - return false; - } - return true; - } - - @Override - protected void onPostExecute(Boolean success) { - super.onPostExecute(success); - if (!success) { - Toasty.error(context, getString(R.string.error_creating_rclone_binary), Toast.LENGTH_LONG, true).show(); - finish(); - System.exit(0); - } - if (loadingDialog.isStateSaved()) { - loadingDialog.dismissAllowingStateLoss(); - } else { - loadingDialog.dismiss(); - } - startRemotesFragment(); - } - } - @SuppressLint("StaticFieldLeak") private class CopyConfigFile extends AsyncTask { diff --git a/app/src/main/java/ca/pkay/rcloneexplorer/Rclone.java b/app/src/main/java/ca/pkay/rcloneexplorer/Rclone.java index a3a856f..7d43f80 100644 --- a/app/src/main/java/ca/pkay/rcloneexplorer/Rclone.java +++ b/app/src/main/java/ca/pkay/rcloneexplorer/Rclone.java @@ -843,13 +843,4 @@ public void exportConfigFile(Uri uri) throws IOException { outputStream.flush(); outputStream.close(); } - - public boolean isRcloneBinaryCreated() { - File file = new File(rclone); - return file.exists() && file.canExecute(); - } - - public void createRcloneBinary() throws IOException { - // this.rclone is extracted by Android during app installation - } } diff --git a/app/src/main/java/ca/pkay/rcloneexplorer/SharingActivity.java b/app/src/main/java/ca/pkay/rcloneexplorer/SharingActivity.java index faa559c..ce53883 100644 --- a/app/src/main/java/ca/pkay/rcloneexplorer/SharingActivity.java +++ b/app/src/main/java/ca/pkay/rcloneexplorer/SharingActivity.java @@ -68,7 +68,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { return; } - if (!rclone.isRcloneBinaryCreated() || rclone.isConfigEncrypted() || !rclone.isConfigFileCreated() || rclone.getRemotes().isEmpty()) { + if (rclone.isConfigEncrypted() || !rclone.isConfigFileCreated() || rclone.getRemotes().isEmpty()) { AlertDialog.Builder builder; if (isDarkTheme) { builder = new AlertDialog.Builder(this, R.style.DarkDialogTheme);