È possibile falsificare un percorso specifico per un processo?


9

Sto cercando di eseguire ADB su un server Linux con più utenti in cui non sono root (per giocare con il mio emulatore Android). Il demone adb scrive i suoi log nel file /tmp/adb.logche sfortunatamente sembra essere hardcoded in ADB e questa situazione non cambierà .

Quindi, adb non riesce a correre, dando l'errore evidente: cannot open '/tmp/adb.log': Permission denied. Questo file viene creato da un altro utente e /tmpha un po 'di sticky on. Se inizio adb adb nodaemon serverfacendolo scrivere su stdout, non si verificano errori (ho anche impostato la sua porta su un valore univoco per evitare conflitti).

La mia domanda è: c'è un modo per far scrivere ADB su un altro file di /tmp/adb.log? Più in generale, esiste un modo per creare una sorta di link simbolico specifico del processo? Voglio reindirizzare tutti gli accessi ai file /tmp/adb.log, dicendo, un file ~/tmp/adb.log.

Ancora una volta, non sono root sul server, quindi chroot, mount -o rbinde chmodnon sono opzioni valide. Se possibile, mi piacerebbe non modificare le fonti ADB, ma sicuramente se non ci sono altre soluzioni, lo farò.

PS Per il caso ADB speciali Io può ricorrere a correre adb nodaemon servercon nohupe il reindirizzamento di uscita, ma la questione generale è ancora rilevante.


2
sì. puoi mettere il tuo processo in uno spazio dei nomi di mount privato e montare qualche altro file /tmp/adb.log, o addirittura montare il suo privato /tmp. fare man unsharee man namespacese man nsenter.
Mikeserv,

1
@mikeserv fantastico, sembra esattamente quello di cui ho bisogno, grazie! Se riformatti il ​​tuo commento come risposta, sarò in grado di impostarlo come accettato.
gluk47,

Oppure ci sono LD_PRELOADtrucchi, anche se sarebbe più complicato.
thrig

@thrig sì, ho pensato a LD_PRELOAD, ma francamente, sarebbe più facile codificare /home/$USER/tmp/adb.loge ricostruire adb :)
gluk47

Risposte:


5

Ecco un esempio molto semplice di come usare util-linux's unshareper inserire un processo in uno spazio dei nomi di mount privato e dargli una visione diversa dello stesso filesystem che ha attualmente il suo genitore:

{   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

Puoi dare a un processo una vista privata del suo filesystem con l' unshareutilità su sistemi Linux aggiornati, sebbene la funzione dello spazio dei nomi mount sia stata abbastanza matura per l'intera serie del kernel 3.x. Puoi inserire spazi dei nomi preesistenti di tutti i tipi con l' nsenterutilità dallo stesso pacchetto e puoi scoprire di più con man.


Solo una domanda: sono io o è una soluzione perfetta ma solo per l'utente root?
gluk47,

@ gluk47 - non deve essere. puoi unsharetutti i tipi di spazi dei nomi - per includere lo spazio dei nomi utente. e quindi l'utente può eseguire uno spazio dei nomi in cui ha accesso come root e tutto ciò che fa all'interno di un utente root potrebbe rovinare lo spazio dei nomi principale. in altre parole, uno spazio dei nomi mount può essere incorporato in uno spazio dei nomi utente. hai davvero bisogno di leggere quelle manpagine. diventa profondo. questo è esattamente come dockere come sytemd-nspawnfunziona.
Mikeserv,

Ho letto quelle pagine man ed esempi da Internet) Sembra proprio che debba leggerle di più, solo grazie per aver sottolineato questa tecnologia, in qualche modo non ne ero affatto a conoscenza.
gluk47,

@ gluk47 - non accettare le risposte per amore della lealtà. mentre il sentimento è apprezzato, quel tipo di cose sconfigge lo scopo di questo posto. accetta la risposta che usi . se quello non è questo, per favore non accettare questa risposta. a proposito, solo perché un processo viene avviato come root, non significa che debba rimanere un processo root. c'è l' runuserutilità che può essere usata con unshare, e se sei aperto a scrivere programmi compilati comunque, non c'è motivo per cui non puoi usare unshare()syscall per fare lo stesso, o anche solo system()con binario suid.
Mikeserv,

Non accetterei sicuramente la risposta se non fosse utile. Trovo entrambe le risposte pertinenti e utili, quindi il sentimento è l'unica ragione distintiva per controllare una di queste risposte :)
gluk47

11

LD_PRELOAD non è troppo difficile e non è necessario essere root. Interpone la tua routine C che viene chiamata al posto del reale open()nella libreria C. La tua routine controlla se il file da aprire è "/tmp/adb.log" e chiama la vera apertura con un nome file diverso. Ecco il tuo 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);
}

Compilalo con gcc -Wall -O2 -fpic -shared -ldl -o shim_open.so shim_open.ce testalo mettendo qualcosa dentro /tmp/myadb.loge in esecuzione LD_PRELOAD=/.../shim_open.so cat /tmp/adb.log. Quindi prova LD_PRELOAD su adb.


Bene, in effetti la tua soluzione è l'unica che sono riuscito a far funzionare come utente non root. Non ho affrontato unshare ( Operation not permitted). Spero che opensia abbastanza da gestire, ma alla fine, aggiungere unlinka questo gestore non è difficile.
gluk47,

Aww. Che peccato non poter controllare due risposte. Ho promesso a Mikeserv di verificare la sua soluzione come risposta, ed è davvero valida.
gluk47,

2
non importa. Ho imparato anche io unshare, quindi guadagniamo tutti!
Meuh

Dopo qualche tempo, grazie ancora per l'esempio LD_PRELOAD. Da quando ho provato il tuo codice, sto usando LD_PRELOAD in varie situazioni in cui non ci avrei nemmeno pensato. La mia vita è cambiata in meglio :)
gluk47

2
@ gluk47 Ecco cosa c'è di così meraviglioso in Gnu / Linux: non devi mai smettere di esplorare! Ci sono così tante cose buone da scoprire e condividere.
Meuh
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.