LD_LIBRARY_PATH иногда игнорируется на Android

У меня есть приложение для Android, которое порождает много собственных исполняемых файлов, динамически связанных с библиотеками, которые я распространяю с пакетом. Чтобы запустить эти двоичные файлы, я использую переменную среды LD_LIBRARY_PATH, чтобы они знали о месте загрузки библиотек, но на некоторых устройствах это невообще не работает, LD_LIBRARY_PATH корректно обновляется, но двоичный файл все равно не может найти библиотеку. Это не то, что я могу воспроизвести, потому что на моих двух устройствах (Galaxy Nexus & Nexus 7 со стоковыми ромами) он просто отлично работает.

Я пробовал много способов, например, я порождаю:

LD_LIBRARY_PATH=/my/package/custom/libs:$LD_LIBRARY_PATH && cd /binary/directory && ./binary

А также :

    String[] envp = { "LD_LIBRARY_PATH=" + libPath + ":$LD_LIBRARY_PATH" };

    Process process = Runtime.getRuntime().exec( "su", envp );

    writer = new DataOutputStream( process.getOutputStream() );
    reader = new BufferedReader( new InputStreamReader( process.getInputStream() ) );

    writer.writeBytes( "export LD_LIBRARY_PATH=" + libPath + ":$LD_LIBRARY_PATH\n" );
    writer.flush();

Но на этих устройствах ничего не работало ... так что яЯ начинаю думать, что это проблема, связанная с ядром, некоторые ядра (например, мое) используют LD_LIBRARY_PATH, другие ядра нет (просто игнорируйте это, или онииспользовать только LD_LIBRARY_PATH, который был установлен при запуске приложения, поэтомунет способа изменить его во время выполнения).

Я также пытался использовать System.load, но это невозможно, потому что эти библиотеки не являются JNI ... Есть ли что-то, что я мог бы попробовать, прежде чем начать думать об использовании статически связанных двоичных файлов? >>

 ra.15 окт. 2012 г., 17:07
но на некоторых устройствах это невообще не работаетМожете ли вы предоставить мне модели устройств, где это нет работа. Не уверен, что может помочь, но попробуйте посмотреть (если у меня есть такое устройство).
 auselen15 окт. 2012 г., 23:35
Это компоновщик, который имеет дело с LD_LIBRARY_PATH //github.com/android/platform_bionic/tree/master/linker

Ответы на вопрос(4)

Решение Вопроса

Вот простая оболочка, о которой я писал:

#include 
#include 
#include 
#include 

typedef int (*main_t)(int argc, char** argv);

static int help(const char* argv0)
{
    printf("%s: simple wrapper to work around LD_LIBRARY_PATH\n\n", argv0);
    printf("Args: executable, list all the libraries you need to load in dependency order, executable again, optional parameters\n");
    printf("example: %s /data/local/ttte /data/data/app/com.testwrapper/lib/ttt.so /data/local/ttte 12345\n", argv0);
    printf("Note: the executable should be built with CFLAGS=\"-fPIC -pie\", LDFLAGS=\"-rdynamic\"\n");

    return -1;
}

int main(int argc, char** argv)
{
    int rc, nlibs;
    void *dl_handle;

    if (argc < 2)
    {
        return help(argv[0]);
    }

    __android_log_print(ANDROID_LOG_DEBUG, "wrapper", "running '%s'", argv[1]);

    for (nlibs = 2; ; nlibs++)
    {
        if (nlibs >= argc)
        {
            return help(argv[0]);
        }

        __android_log_print(ANDROID_LOG_DEBUG, "wrapper", "loading '%s'", argv[nlibs]);
        dl_handle = dlopen(argv[nlibs], 0); // do not keep the handle, except for the last
        __android_log_print(ANDROID_LOG_DEBUG, "wrapper", "loaded '%s' -> %p", argv[nlibs], dl_handle);
        if (strcmp(argv[1], argv[nlibs]) == 0)
        {
            break;
        }
    }

    main_t pmain = (main_t)dlsym(dl_handle, "main");
    __android_log_print(ANDROID_LOG_DEBUG, "wrapper", "found '%s' -> %p", "main", pmain);
    rc = pmain(argc - nlibs, argv + nlibs);

//   we are exiting the process anyway, don't need to clean the handles actually

//   __android_log_print(3, "wrapper", "closing '%s'", argv[1]);
//   dlclose(dl_handle);

    return 0;
}

Чтобы сделать его читабельным, я отбрасываю большую часть обработки ошибок, необязательной очистки и обработки особых случаев.

Android.mk для этого исполняемого файла:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := wrapper
LOCAL_SRC_FILES := wrapper/main.c
LOCAL_LDLIBS    := -llog

include $(BUILD_EXECUTABLE)

Обратите внимание, что вы должны позаботиться о развертывании: упаковка этоwrapper в APK, извлечение на некоторый локальный путь (никогда на USB-накопитель или на/sdcard!), помечая его как исполняемый (chmod 777).

Это дополнительные параметры, которые вы должны указать при создании исполняемых файлов, которые вы запускаете черезwrapper, Если вы используетеndk-build для их построения это выглядит следующим образом:

LOCAL_C_FLAGS   += -fPIC -pie
LOCAL_LDFLAGS   += -rdynamic 

Обратите внимание, что вы нене нужноchmod для этих исполняемых файлов больше. Еще один трюк: вы можете построитьвторичный исполняемые файлы в разделяемые библиотеки, и та же самая обертка продолжит работать! Это избавляет от проблем развертывания этих двоичных файлов. NDK и Android build безопасно доставят их через libs / armeabi из APK в ваше приложение. 'S lib каталог автоматически.

Обновить

Кажется, есть гораздо более простое решение, используяProcessBuilder с измененной средой:https://stackoverflow.com/a/8962189/192373.

Это не проблема ядра, а проблема LD: загрузка библиотек полностью в пользовательском режиме, а не в режиме ядра, поэтому ядро не имеет к этому никакого отношения. Ядро отвечает только за передачу управления в ld, который зацикливается на секции DYNAMIC двоичного файла ELF, загружает любые библиотеки и выясняет, что делать с переменными среды, такими как LD_PRELOAD и LD_PRELOAD.

Переменные, однако, могут представлять собой неотъемлемую угрозу безопасности: LD_LIBRARY_PATH позволяет вам указывать собственные пути до значений по умолчанию системы (/ lib или - в Android, / system / lib). LD_PRELOAD еще хуже, потому что он принудительно загружает (пихает) вашу библиотеку в процесс, независимо от того, запросил ли процесс его - что может привести к внедрению вредоносного кода в чувствительный процесс. По этой причине это не разрешено в корневых процессах Setuid. Однако, если вы находитесь в корневой оболочке (то есть на рутированном телефоне), большинство устройств это разрешат. Поставщик может изменить LD, что приведет к вашим проблемам.

Что вы можете сделать, чтобы обойти:

Самый простой: перемонтировать / system как чтение / запись (mount -o remount / system) и скопировать свои библиотеки в / system / lib. Потребуется рутированный телефон

Smartest: Статически связывайте свои библиотеки в двоичный файл, одновременно поддерживая динамические другие (системные) библиотеки

Надеюсь это поможет,

TG

Я неЯ думаю, что LD_LIBRARY_PATH будет игнорироваться. То, как вы обновляете системную среду, в порядке. LD_LIBRARY_PATH будет обновляться под пользователем root.

Решение не сможет работать на некоторых машинах, может иметь несколько причин:

Приложение Android всегда запускается под своим собственным идентификатором пользователя. Он не запускается с правами root. Если вы изменяете только системную переменную пользователя root. Приложение все еще не может найти правильный путь к библиотеке в своем собственном окружении.

Даже если вы правильно обновили LD_LIBRARY_PATH при инициализации приложения, вам все равно нужно убедиться, что приложение 'Соответствующий идентификатор пользователя имеет доступ для чтения этих библиотек.

Некоторые поставщики модифицируют ядро Android по соображениям безопасности. Они могут отключить загрузку сторонних библиотек из внешнего хранилища или что-то в этом роде.

Тот'Правильно, вы не можете полагаться на LD_LIBRARY_PATH на Android. Вы можете использовать System.load () с любой библиотекой, но это не очень помогает при порождении дочерних процессов. Вы можете использовать dlopen в своем коде, но обычно это означает, что многие строки кода должны быть переписаны.

Забавный трюк состоит в том, чтобы преобразовать ваши исполняемые файлы в разделяемые библиотеки и загрузить их из исполняемых файлов-обёрток, которые будут раздавать библиотеки в порядке зависимости.

Тем не менее, настоятельно рекомендуется преобразовать как можно больше спавнов в вызовы в процессе.

 Alex Cohn16 окт. 2012 г., 16:27
Я не'сказать "LD_LIBRARY_PATH не работает на Android ", Я сказал "на тебя нельзя положиться, Я оцениваю 80% как довольно высокий. Но, может быть, вы смотрите в основном на современные устройства высокого класса ...
 Simone Margaritelli16 окт. 2012 г., 00:42
и почему тогда это работает на некоторых устройствах (80%) и не работает на других? например, на Huawei U8510 Ideos X3 с Android версия 2.3.3 не работает.
 Simone Margaritelli16 окт. 2012 г., 16:40
Хорошо, так как я могуконвертировать мои исполняемые файлы, потому что исходный код действительно большой (мыВы говорите об ettercap, nmap и т. д.), и я могуне преобразовывать порождения в вызовы процессов, чтобы избежать зависания приложений во время выполнения процессов ... у вас есть идеи, как решить эту проблему? :)
 Alex Cohn17 окт. 2012 г., 12:49
Хорошо, после некоторого тестирования: если вы можете перестроить свои исполняемые файлы (те, которые зависят от общих библиотек, которые вы устанавливаете) с-fPIC -pie флаги (какописано в другом месте на стеке потока), затем вы можете подготовить свой собственный исполняемый файл-обертку (вид замены или, скорее, дополнения к системному динамическому компоновщику), который запустится, динамически загрузит необходимые разделяемые библиотеки, наконец загрузит требуемый исполняемый файл с помощьюdlopenи назовите егоглавный() черезdlsym ()

Ваш ответ на вопрос