From 69e0215b9db103f2fe58b7576a7fb5c17a1c7cdd Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 17 Jun 2015 15:31:24 +0200 Subject: [PATCH] android: Manually load libraries with dlopen() and RTLD_GLOBAL on Android M This fixes an issue when using the Android M preview. Bionic's dynamic linker was changed so that symbols in libraries loaded with RTLD_LOCAL were not found anymore in dlsym(RTLD_DEFAULT, ...). This is the case for libraries loaded with System.loadLibrary(), therefore, the plugin loader in libstrongswan was not able to resolve any symbols defined in other libraries loaded later. While this seems to have been broken unintentionally for existing apps (fix at [1]), it will again be a problem whenever we decide to increase targetSdkVersion beyond 22 (or until that fix makes it into the system/emulator images). Unfortunately, the dynamic loader in releases prior to Android 4.3 can't load libandroidbridge without also loading its dependencies. [1] https://github.com/android/platform_bionic/commit/1913352c6b --- .../jni/libandroidbridge/android_jni.c | 39 ++++++++++++++++++- .../android/logic/CharonVpnService.java | 26 +++++++------ 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/frontends/android/jni/libandroidbridge/android_jni.c b/src/frontends/android/jni/libandroidbridge/android_jni.c index 7ab9a24bd..a6412bdf7 100644 --- a/src/frontends/android/jni/libandroidbridge/android_jni.c +++ b/src/frontends/android/jni/libandroidbridge/android_jni.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012-2015 Tobias Brunner * Copyright (C) 2012 Giuliano Grassi * Copyright (C) 2012 Ralf Sager * Hochschule fuer Technik Rapperswil @@ -15,6 +15,8 @@ * for more details. */ +#include + #include "android_jni.h" #include @@ -25,6 +27,21 @@ */ static JavaVM *android_jvm; +static struct { + char name[32]; + void *handle; +} libs[] = { + { "libstrongswan.so", NULL }, +#ifdef USE_BYOD + { "libtncif.so", NULL }, + { "libtnccs.so", NULL }, + { "libimcv.so", NULL }, +#endif + { "libhydra.so", NULL }, + { "libcharon.so", NULL }, + { "libipsec.so", NULL }, +}; + jclass *android_charonvpnservice_class; jclass *android_charonvpnservice_builder_class; android_sdk_version_t android_sdk_version; @@ -79,6 +96,7 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) JNIEnv *env; jclass jversion; jfieldID jsdk_int; + int i; android_jvm = vm; @@ -87,6 +105,15 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) return -1; } + for (i = 0; i < countof(libs); i++) + { + libs[i].handle = dlopen(libs[i].name, RTLD_GLOBAL); + if (!libs[i].handle) + { + return -1; + } + } + androidjni_threadlocal = thread_value_create(attached_thread_cleanup); android_charonvpnservice_class = @@ -109,6 +136,16 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) */ void JNI_OnUnload(JavaVM *vm, void *reserved) { + int i; + androidjni_threadlocal->destroy(androidjni_threadlocal); + + for (i = countof(libs) - 1; i >= 0; i--) + { + if (libs[i].handle) + { + dlclose(libs[i].handle); + } + } } diff --git a/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java b/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java index 236e759f8..482caa220 100644 --- a/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java +++ b/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java @@ -42,6 +42,7 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.net.VpnService; +import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.ParcelFileDescriptor; @@ -732,22 +733,25 @@ public class CharonVpnService extends VpnService implements Runnable /* * The libraries are extracted to /data/data/org.strongswan.android/... - * during installation. + * during installation. On newer releases most are loaded in JNI_OnLoad. */ static { - System.loadLibrary("strongswan"); - - if (MainActivity.USE_BYOD) + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) { - System.loadLibrary("tncif"); - System.loadLibrary("tnccs"); - System.loadLibrary("imcv"); - } + System.loadLibrary("strongswan"); - System.loadLibrary("hydra"); - System.loadLibrary("charon"); - System.loadLibrary("ipsec"); + if (MainActivity.USE_BYOD) + { + System.loadLibrary("tncif"); + System.loadLibrary("tnccs"); + System.loadLibrary("imcv"); + } + + System.loadLibrary("hydra"); + System.loadLibrary("charon"); + System.loadLibrary("ipsec"); + } System.loadLibrary("androidbridge"); } }