aboutsummaryrefslogtreecommitdiff
path: root/app/src/main
diff options
context:
space:
mode:
authorpacien2020-01-20 17:07:12 +0100
committerpacien2020-01-20 17:07:12 +0100
commit883b5abc7b2a770146683e7e27bf275bd4064511 (patch)
tree81dd200fc2cea8e2030b5b5b68c39abe3c32ab46 /app/src/main
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
Diffstat (limited to 'app/src/main')
-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
7 files changed, 48 insertions, 108 deletions
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}") }
36 .apply { if (rsaPrivateKeyFd != null) withOption("option", "PrivateKeyFile=/proc/self/fd/$rsaPrivateKeyFd") }) 38 .apply { if (rsaPrivateKey != null) withOption("option", "PrivateKeyFile=${rsaPrivateKey.absolutePath}") }
39 ).thenApply { }
37} 40}
diff --git a/app/src/main/java/org/pacien/tincapp/context/App.kt b/app/src/main/java/org/pacien/tincapp/context/App.kt
index a877929..4d8d5d0 100644
--- a/app/src/main/java/org/pacien/tincapp/context/App.kt
+++ b/app/src/main/java/org/pacien/tincapp/context/App.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-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
@@ -21,6 +21,7 @@ package org.pacien.tincapp.context
21import android.app.Application 21import android.app.Application
22import android.content.Context 22import android.content.Context
23import android.content.Intent 23import android.content.Intent
24import android.content.pm.ApplicationInfo
24import android.net.Uri 25import android.net.Uri
25import android.os.Build 26import android.os.Build
26import android.os.Handler 27import android.os.Handler
@@ -47,7 +48,7 @@ class App : Application() {
47 48
48 private fun setupCrashHandler() { 49 private fun setupCrashHandler() {
49 val logger = LoggerFactory.getLogger(this.javaClass) 50 val logger = LoggerFactory.getLogger(this.javaClass)
50 val systemCrashHandler = Thread.getDefaultUncaughtExceptionHandler() 51 val systemCrashHandler = Thread.getDefaultUncaughtExceptionHandler()!!
51 val crashRecorder = CrashRecorder(logger, systemCrashHandler) 52 val crashRecorder = CrashRecorder(logger, systemCrashHandler)
52 Thread.setDefaultUncaughtExceptionHandler(crashRecorder) 53 Thread.setDefaultUncaughtExceptionHandler(crashRecorder)
53 } 54 }
@@ -61,6 +62,11 @@ class App : Application() {
61 fun getContext() = appContext!! 62 fun getContext() = appContext!!
62 fun getResources() = getContext().resources!! 63 fun getResources() = getContext().resources!!
63