Чи можливо підробити певний шлях для процесу?


9

Я намагаюся запустити ADB на сервері Linux з декількома користувачами, де я не root (щоб грати зі своїм емулятором Android). Демон adb записує свої журнали у файл, /tmp/adb.logякий, на жаль, здається, що він важко закодований в ADB, і ця ситуація не зміниться .

Таким чином, ADB не в змозі бігти, даючи очевидну помилку: cannot open '/tmp/adb.log': Permission denied. Цей файл створений іншим користувачем і /tmpмає клейкий біт. Якщо я починаю adb з того, adb nodaemon serverщоб він писав у stdout, помилок не виникає (я також встановлюю його порт на унікальне значення, щоб уникнути конфліктів).

Моє запитання: чи є якийсь спосіб змусити ADB писати в інший файл, ніж /tmp/adb.log?Загалом, чи є спосіб створити якусь символьну посилання, характерну для певного процесу? Я хочу перенаправити всі файли, до яких звертається, /tmp/adb.logдо, мовляв, файлу ~/tmp/adb.log.

Знову ж таки, я не root на сервері, так chroot , mount -o rbindі chmodне є дійсними параметрами. Якщо можливо, я хотів би не змінювати джерела ADB, але, безумовно, якщо інших рішень немає, я це зроблю.

PS Для конкретного випадку АБР я можу вдатися до управління adb nodaemon serverз nohupі перенаправленням виводу, але загальне питання по - , як і раніше актуальний.


2
так. ви можете помістити процес у приватний простір імен, а також змонтувати якийсь інший файл /tmp/adb.logабо навіть змонтувати його власний приватний файл /tmpвзагалі. робити man unshareі man namespacesі man nsenter.
mikeserv

1
@mikeserv чудово, що, здається, саме те, що мені потрібно, дякую! Якщо ви переформатуєте коментар як відповідь, я зможу встановити його як прийняте.
gluk47

Або є LD_PRELOADхитрощі, хоча це було б складніше.
триг

@thrig Так, я хоч про LD_PRELOAD, але, чесно кажучи, було б простіше /home/$USER/tmp/adb.log
жорсткий код

Відповіді:


5

Ось дуже простий приклад використання util-linux's, unshareщоб розмістити процес у приватному просторі імен файлів монтажу та надати йому інший вигляд тієї ж файлової системи, яку наразі має його батько:

{   cd /tmp                      #usually a safe place for this stuff
    echo hey   >file             #some
    echo there >file2            #evidence
    sudo unshare -m sh -c '      #unshare requires root by default
         mount -B file2 file     #bind mount there over hey
         cat file                #show it
         kill -TSTP "$$"         #suspend root shell and switch back to parent
         umount file             #unbind there
         cat file'               #show it
    cat file                     #root shell just suspended
    fg                           #bring it back
    cat file2                    #round it off
}

there                            #root shell
hey                              #root shell suspended
hey                              #root shell restored
there                            #rounded

Ви можете надати процесу приватний вигляд його файлової системи за допомогою unshareутиліти в сучасних системах Linux, хоча сам об'єкт простору імен монтування був досить зрілим для всієї серії ядер 3.x. Ви можете вводити наявні простори імен усіх видів за допомогою nsenterутиліти з одного пакету, і ви можете дізнатися більше за допомогою man.


Лише одне запитання: це я чи це ідеальне рішення, але лише для кореневого користувача?
gluk47

@ gluk47 - цього не повинно бути. Ви можете використовувати unshareвсі види просторів імен - включати простір імен користувачів. і тому ваш користувач може запускати простір імен, в якому він має доступ до кореня, і все, що він може робити в межах, що може виконувати користувач root, не впливає на батьківську область імен. Іншими словами, простір імен монтажу може бути вбудований в простору імен користувача. вам справді потрібно прочитати ці manсторінки. вона стає глибокою. саме так dockerі sytemd-nspawnпрацює.
mikeserv

Я читав ті сторінки чоловіків і приклади з Інтернету) Просто здається, що мені потрібно їх більше читати, просто дякую за те, що вказували на цю технологію, я якось про це не усвідомлював.
gluk47

@ gluk47 - не приймай відповіді заради вірності. в той час, як настрої оцінюються, такі речі перемагають призначення цього місця. прийняти відповідь, яку ви використовуєте . якщо це не цей, будь ласка, не приймайте цю відповідь. до речі, саме те, що процес запущений як root, не означає, що він повинен залишатися кореневим процесом. є runuserутиліта, з якою можна скористатися unshare, і якщо ви все одно готові до написання скомпільованих програм, немає ніяких причин, щоб ви не могли використовувати unshare()syscall, щоб зробити те саме, або навіть просто system()із бідоном Suid .
mikeserv

Я б точно не прийняв відповідь, якщо вона не була корисною. Я вважаю обидві відповіді релевантними та корисними, тому настрої є єдиною відмінною причиною перевірити одну з цих відповідей :)
gluk47

11

LD_PRELOAD не надто складний, і вам не потрібно мати корінь. Вставте свій власний розпорядок C, який викликається замість реального open()в бібліотеці С. Ваша звичайна програма перевіряє, чи файл, який потрібно відкрити, "/tmp/adb.log" і викликає справжній відкритий з іншим ім'ям файлу. Ось ваш shim_open.c:

/*
 * capture calls to a routine and replace with your code
 * gcc -Wall -O2 -fpic -shared -ldl -o shim_open.so shim_open.c
 * LD_PRELOAD=/.../shim_open.so cat /tmp/adb.log
 */
#define _FCNTL_H 1 /* hack for open() prototype */
#define _GNU_SOURCE /* needed to get RTLD_NEXT defined in dlfcn.h */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dlfcn.h>
#define OLDNAME "/tmp/adb.log"
#define NEWNAME "/tmp/myadb.log"

int open(const char *pathname, int flags, mode_t mode){
    static int (*real_open)(const char *pathname, int flags, mode_t mode) = NULL;

    if (!real_open) {
        real_open = dlsym(RTLD_NEXT, "open");
        char *error = dlerror();
        if (error != NULL) {
            fprintf(stderr, "%s\n", error);
            exit(1);
        }
    }
    if (strcmp(pathname,OLDNAME)==0) pathname = NEWNAME;
    fprintf(stderr, "opening: %s\n", pathname);
    return real_open(pathname, flags, mode);
}

Скомпілюйте його gcc -Wall -O2 -fpic -shared -ldl -o shim_open.so shim_open.cі протестуйте, додавши щось /tmp/myadb.logі запустивши LD_PRELOAD=/.../shim_open.so cat /tmp/adb.log. Потім спробуйте LD_PRELOAD на adb.


Щоправда, ваше рішення - єдине, що мені вдалося зробити так, щоб робота була некористувачем. Я не впорався з unshare ( Operation not permitted). Я сподіваюся, що openцього достатньо впоратися, але, нарешті, додати unlinkдо цього обробника не складно.
gluk47

Aww. Як прикро, що я не можу перевірити дві відповіді. Я пообіцяв mikeserv перевірити його рішення як відповідь, і це справді життєздатний.
gluk47

2
не звертай уваги. Я також дізнався про unshareце, тому ми всі отримуємо!
meuh

Через деякий час ще раз дякую за зразок LD_PRELOAD. Оскільки я спробував ваш код, я використовую LD_PRELOAD у різних ситуаціях, коли я навіть не думав про це. Моє життя змінилося на краще :)
gluk47

2
@ gluk47 Ось що так чудово в Gnu / Linux: вам ніколи не припиняйте досліджувати! Є так багато хороших речей, щоб відкрити та поділитися.
meuh
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.