aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpacien2020-01-20 17:07:12 +0100
committerpacien2020-01-20 17:07:12 +0100
commit883b5abc7b2a770146683e7e27bf275bd4064511 (patch)
tree81dd200fc2cea8e2030b5b5b68c39abe3c32ab46
parent3fc8a2ed3bfbcbd29bc22c2c73416e2708cd7615 (diff)
downloadtincapp-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.txt9
-rw-r--r--app/build.gradle4
-rw-r--r--app/src/main/c/exec.c60
-rw-r--r--app/src/main/c/main.c1
-rw-r--r--app/src/main/java/org/pacien/tincapp/commands/Executor.kt34
-rw-r--r--app/src/main/java/org/pacien/tincapp/commands/Tincd.kt15
-rw-r--r--app/src/main/java/org/pacien/tincapp/context/App.kt10
-rw-r--r--app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt34
-rw-r--r--app/src/main/play/listings/en-US/full-description.txt2
-rw-r--r--readme.md2
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
55ExternalProject_Add(tinc 55ExternalProject_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
75add_library(exec SHARED src/main/c/exec.c) 74add_library(main SHARED src/main/c/main.c)
76add_dependencies(exec tinc) 75add_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
24static 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
37static inline void exec(const char **argcv) {
38 execv(argcv[0], (char *const *) argcv);
39 exit(1);
40}
41
42JNIEXPORT jint JNICALL
43Java_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
55JNIEXPORT jint JNICALL
56Java_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 */
32internal object Executor { 32internal 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
19package org.pacien.tincapp.commands 19package org.pacien.tincapp.commands
20 20
21import java8.util.concurrent.CompletableFuture
21import org.pacien.tincapp.context.AppPaths 22import org.pacien.tincapp.context.AppPaths
23import java.io.File
22 24
23/** 25/**
24 * @author pacien 26 * @author pacien
25 */ 27 */
26object Tincd { 28object 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}") }