diff options
author | pacien | 2020-01-20 17:07:12 +0100 |
---|---|---|
committer | pacien | 2020-01-20 17:07:12 +0100 |
commit | 883b5abc7b2a770146683e7e27bf275bd4064511 (patch) | |
tree | 81dd200fc2cea8e2030b5b5b68c39abe3c32ab46 | |
parent | 3fc8a2ed3bfbcbd29bc22c2c73416e2708cd7615 (diff) | |
download | tincapp-883b5abc7b2a770146683e7e27bf275bd4064511.tar.gz |
pass network device fd via unix socket instead of inheritance
Workaround for new shared memory restrictions added in Android 10
preventing file descriptor leakage to sub-processes.
This change set BREAKS ENCRYPTED PRIVATE KEYS SUPPORT.
GitHub: https://github.com/pacien/tincapp/issues/92
-rw-r--r-- | app/CMakeLists.txt | 9 | ||||
-rw-r--r-- | app/build.gradle | 4 | ||||
-rw-r--r-- | app/src/main/c/exec.c | 60 | ||||
-rw-r--r-- | app/src/main/c/main.c | 1 | ||||
-rw-r--r-- | app/src/main/java/org/pacien/tincapp/commands/Executor.kt | 34 | ||||
-rw-r--r-- | app/src/main/java/org/pacien/tincapp/commands/Tincd.kt | 15 | ||||
-rw-r--r-- | app/src/main/java/org/pacien/tincapp/context/App.kt | 10 | ||||
-rw-r--r-- | app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt | 34 | ||||
-rw-r--r-- | app/src/main/play/listings/en-US/full-description.txt | 2 | ||||
-rw-r--r-- | readme.md | 2 |
10 files changed, 55 insertions, 116 deletions
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 073f7d7..6449aeb 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt | |||
@@ -54,9 +54,8 @@ ExternalProject_Add(libressl | |||
54 | 54 | ||
55 | ExternalProject_Add(tinc | 55 | ExternalProject_Add(tinc |
56 | DEPENDS lzo libressl | 56 | DEPENDS lzo libressl |
57 | URL https://github.com/gsliepen/tinc/archive/017a7fb57655d9b1d706ee78f7e3d0000411b883.tar.gz | 57 | URL https://github.com/gsliepen/tinc/archive/6682a0d29cbb70b216a3fe02f2812963dee607d0.tar.gz |
58 | URL_HASH SHA256=27f361706d09f81fbbef7021f37adf5375f01857b23272a490df066ca290a530 | 58 | URL_HASH SHA256=ffb0e6c02b0112c095366b3baa89f5ed56cc5f644be40268696ce7741e76452a |
59 | PATCH_COMMAND sed -i -e "s/test(void)/test(void *x)/" <SOURCE_DIR>/m4/attribute.m4 | ||
60 | CONFIGURE_COMMAND autoreconf -fsi <SOURCE_DIR> && | 59 | CONFIGURE_COMMAND autoreconf -fsi <SOURCE_DIR> && |
61 | <SOURCE_DIR>/configure ${xCONFIG} | 60 | <SOURCE_DIR>/configure ${xCONFIG} |
62 | --with-openssl=${CMAKE_CURRENT_BINARY_DIR}/usr/local | 61 | --with-openssl=${CMAKE_CURRENT_BINARY_DIR}/usr/local |
@@ -72,5 +71,5 @@ ExternalProject_Add(tinc | |||
72 | rm -r <BINARY_DIR> | 71 | rm -r <BINARY_DIR> |
73 | ) | 72 | ) |
74 | 73 | ||
75 | add_library(exec SHARED src/main/c/exec.c) | 74 | add_library(main SHARED src/main/c/main.c) |
76 | add_dependencies(exec tinc) | 75 | add_dependencies(main tinc) |
diff --git a/app/build.gradle b/app/build.gradle index 5ef4f4a..25e449e 100644 --- a/app/build.gradle +++ b/app/build.gradle | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon | 2 | * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon |
3 | * Copyright (C) 2017-2019 Pacien TRAN-GIRARD | 3 | * Copyright (C) 2017-2020 Pacien TRAN-GIRARD |
4 | * | 4 | * |
5 | * This program is free software: you can redistribute it and/or modify | 5 | * This program is free software: you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -35,7 +35,7 @@ android { | |||
35 | defaultConfig { | 35 | defaultConfig { |
36 | applicationId 'org.pacien.tincapp' | 36 | applicationId 'org.pacien.tincapp' |
37 | minSdkVersion 21 | 37 | minSdkVersion 21 |
38 | targetSdkVersion 28 // FIXME: bad file descriptor in daemon when targeting 29 | 38 | targetSdkVersion 29 |
39 | multiDexEnabled true | 39 | multiDexEnabled true |
40 | versionCode 28 | 40 | versionCode 28 |
41 | versionName '0.28' | 41 | versionName '0.28' |
diff --git a/app/src/main/c/exec.c b/app/src/main/c/exec.c deleted file mode 100644 index c335b20..0000000 --- a/app/src/main/c/exec.c +++ /dev/null | |||
@@ -1,60 +0,0 @@ | |||
1 | /* | ||
2 | * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon | ||
3 | * Copyright (C) 2017-2018 Pacien TRAN-GIRARD | ||
4 | * | ||
5 | * This program is free software: you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation, either version 3 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <jni.h> | ||
20 | #include <unistd.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <sys/wait.h> | ||
23 | |||
24 | static inline const char **to_string_array(JNIEnv *env, jobjectArray ja) { | ||
25 | const int len = (*env)->GetArrayLength(env, ja); | ||
26 | const char **ca = calloc((size_t) len + 1, sizeof(char *)); | ||
27 | |||
28 | for (int i = 0; i < len; ++i) { | ||
29 | jstring jstr = (jstring) (*env)->GetObjectArrayElement(env, ja, i); | ||
30 | ca[i] = (*env)->GetStringUTFChars(env, jstr, NULL); | ||
31 | } | ||
32 | |||
33 | ca[len] = NULL; | ||
34 | return ca; | ||
35 | } | ||
36 | |||
37 | static inline void exec(const char **argcv) { | ||
38 | execv(argcv[0], (char *const *) argcv); | ||
39 | exit(1); | ||
40 | } | ||
41 | |||
42 | JNIEXPORT jint JNICALL | ||
43 | Java_org_pacien_tincapp_commands_Executor_forkExec(JNIEnv *env, __attribute__((unused)) jclass class, jobjectArray args) { | ||
44 | pid_t pid = fork(); | ||
45 | switch (pid) { | ||
46 | case 0: | ||
47 | exec(to_string_array(env, args)); | ||
48 | return 0; | ||
49 | |||
50 | default: | ||
51 | return pid; | ||
52 | } | ||
53 | } | ||
54 | |||
55 | JNIEXPORT jint JNICALL | ||
56 | Java_org_pacien_tincapp_commands_Executor_wait(__attribute__((unused))JNIEnv *env, __attribute__((unused)) jclass class, jint pid) { | ||
57 | int status; | ||
58 | waitpid(pid, &status, 0); | ||
59 | return WIFEXITED(status) ? WEXITSTATUS(status) : -1; | ||
60 | } | ||
diff --git a/app/src/main/c/main.c b/app/src/main/c/main.c new file mode 100644 index 0000000..68007d8 --- /dev/null +++ b/app/src/main/c/main.c | |||
@@ -0,0 +1 @@ | |||
// This file intentionally left blank. | |||
diff --git a/app/src/main/java/org/pacien/tincapp/commands/Executor.kt b/app/src/main/java/org/pacien/tincapp/commands/Executor.kt index 29e011f..0a8a774 100644 --- a/app/src/main/java/org/pacien/tincapp/commands/Executor.kt +++ b/app/src/main/java/org/pacien/tincapp/commands/Executor.kt | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon | 2 | * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon |
3 | * Copyright (C) 2017-2018 Pacien TRAN-GIRARD | 3 | * Copyright (C) 2017-2020 Pacien TRAN-GIRARD |
4 | * | 4 | * |
5 | * This program is free software: you can redistribute it and/or modify | 5 | * This program is free software: you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -30,42 +30,10 @@ import java.io.InputStreamReader | |||
30 | * @author pacien | 30 | * @author pacien |
31 | */ | 31 | */ |
32 | internal object Executor { | 32 | internal object Executor { |
33 | private const val FAILED = -1 | ||
34 | private const val SUCCESS = 0 | ||
35 | |||
36 | class CommandExecutionException(msg: String) : Exception(msg) | 33 | class CommandExecutionException(msg: String) : Exception(msg) |
37 | 34 | ||
38 | init { | ||
39 | System.loadLibrary("exec") | ||
40 | } | ||
41 | |||
42 | /** | ||
43 | * @return FAILED (-1) on error, forked child PID otherwise | ||
44 | */ | ||
45 | private external fun forkExec(args: Array<String>): Int | ||
46 | |||
47 | /** | ||
48 | * @return FAILED (-1) on error, the exit status of the process otherwise | ||
49 | */ | ||
50 | private external fun wait(pid: Int): Int | ||
51 | |||
52 | private fun read(stream: InputStream) = BufferedReader(InputStreamReader(stream)).readLines() | 35 | private fun read(stream: InputStream) = BufferedReader(InputStreamReader(stream)).readLines() |
53 | 36 | ||
54 | fun forkExec(cmd: Command): CompletableFuture<Unit> { | ||
55 | val pid = forkExec(cmd.asArray()).also { | ||
56 | if (it == FAILED) throw CommandExecutionException("Could not fork child process.") | ||
57 | } | ||
58 | |||
59 | return runAsyncTask { | ||
60 | val exitCode = wait(pid) | ||
61 | when (exitCode) { | ||
62 | SUCCESS -> Unit | ||
63 | FAILED -> throw CommandExecutionException("Process terminated abnormally.") | ||
64 | else -> throw CommandExecutionException("Non-zero exit status code ($exitCode).") | ||
65 | } | ||
66 | } | ||
67 | } | ||
68 | |||
69 | fun run(cmd: Command): Process = try { | 37 | fun run(cmd: Command): Process = try { |
70 | ProcessBuilder(cmd.asList()).start() | 38 | ProcessBuilder(cmd.asList()).start() |
71 | } catch (e: IOException) { | 39 | } catch (e: IOException) { |
diff --git a/app/src/main/java/org/pacien/tincapp/commands/Tincd.kt b/app/src/main/java/org/pacien/tincapp/commands/Tincd.kt index 92be0f5..c0b0048 100644 --- a/app/src/main/java/org/pacien/tincapp/commands/Tincd.kt +++ b/app/src/main/java/org/pacien/tincapp/commands/Tincd.kt | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon | 2 | * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon |
3 | * Copyright (C) 2017-2018 Pacien TRAN-GIRARD | 3 | * Copyright (C) 2017-2020 Pacien TRAN-GIRARD |
4 | * | 4 | * |
5 | * This program is free software: you can redistribute it and/or modify | 5 | * This program is free software: you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -18,20 +18,23 @@ | |||
18 | 18 | ||
19 | package org.pacien.tincapp.commands | 19 | package org.pacien.tincapp.commands |
20 | 20 | ||
21 | import java8.util.concurrent.CompletableFuture | ||
21 | import org.pacien.tincapp.context.AppPaths | 22 | import org.pacien.tincapp.context.AppPaths |
23 | import java.io.File | ||
22 | 24 | ||
23 | /** | 25 | /** |
24 | * @author pacien | 26 | * @author pacien |
25 | */ | 27 | */ |
26 | object Tincd { | 28 | object Tincd { |
27 | fun start(netName: String, deviceFd: Int, ed25519PrivateKeyFd: Int? = null, rsaPrivateKeyFd: Int? = null) = | 29 | fun start(netName: String, device: String, ed25519PrivateKey: File? = null, rsaPrivateKey: File? = null): CompletableFuture<Unit> = |
28 | Executor.forkExec(Command(AppPaths.tincd().absolutePath) | 30 | Executor.call(Command(AppPaths.tincd().absolutePath) |
29 | .withOption("no-detach") | 31 | .withOption("no-detach") |
30 | .withOption("config", AppPaths.confDir(netName).absolutePath) | 32 | .withOption("config", AppPaths.confDir(netName).absolutePath) |
31 | .withOption("pidfile", AppPaths.pidFile(netName).absolutePath) | 33 | .withOption("pidfile", AppPaths.pidFile(netName).absolutePath) |
32 | .withOption("logfile", AppPaths.logFile(netName).absolutePath) | 34 | .withOption("logfile", AppPaths.logFile(netName).absolutePath) |
33 | .withOption("option", "DeviceType=fd") | 35 | .withOption("option", "DeviceType=fd") |
34 | .withOption("option", "Device=$deviceFd") | 36 | .withOption("option", "Device=@$device") |
35 | .apply { if (ed25519PrivateKeyFd != null) withOption("option", "Ed25519PrivateKeyFile=/proc/self/fd/$ed25519PrivateKeyFd") } | 37 | .apply { if (ed25519PrivateKey != null) withOption("option", "Ed25519PrivateKeyFile=${ed25519PrivateKey.absolutePath}") } |