Apakah mungkin untuk memalsukan jalur tertentu untuk suatu proses?

9

Saya mencoba menjalankan ADB pada server linux dengan banyak pengguna di mana saya tidak melakukan root (untuk bermain dengan emulator android saya). Adb daemon menulis log-nya ke file /tmp/adb.logyang sayangnya tampaknya sulit dikodekan ke dalam ADB dan situasi ini tidak akan berubah .

Jadi, adb gagal untuk dijalankan, memberikan kesalahan yang jelas: cannot open '/tmp/adb.log': Permission denied. File ini dibuat oleh pengguna lain dan /tmpsedikit lengket. Jika saya memulai adb dengan adb nodaemon servermembuatnya menulis ke stdout, tidak ada kesalahan terjadi (saya juga mengatur port-nya ke nilai unik untuk menghindari konflik).

Pertanyaan saya adalah: adakah cara untuk membuat ADB menulis ke file lain /tmp/adb.log? Secara umum, adakah cara untuk membuat semacam symlink khusus proses? Saya ingin mengalihkan semua akses file /tmp/adb.logke, katakanlah, file ~/tmp/adb.log.

Sekali lagi, saya tidak melakukan root pada server, jadi chroot, mount -o rbinddan chmodbukan opsi yang valid. Jika memungkinkan, saya ingin tidak memodifikasi sumber ADB, tetapi tentu saja jika tidak ada solusi lain, saya akan melakukannya.

PS Untuk kasus ADB spesifik saya bisa resor untuk berjalan adb nodaemon serverdengan nohupdan output redirection, tapi pertanyaan umum masih relevan.

gluk47
sumber
2
Iya. Anda dapat menempatkan proses Anda di namespace mount pribadi, dan me-mount beberapa file lain /tmp/adb.log, atau bahkan me-mount privasinya sendiri /tmp. lakukan man unsharedan man namespacesdan man nsenter.
mikeserv
1
@ mikeserv hebat, sepertinya itulah yang saya butuhkan, terima kasih! Jika Anda memformat ulang komentar Anda sebagai jawaban, saya dapat menetapkannya sebagai diterima.
gluk47
Atau ada LD_PRELOADtrik, meski itu akan lebih rumit.
thrig
@ thrig ya, saya pikir tentang LD_PRELOAD, tapi terus terang, akan lebih mudah untuk hardcode /home/$USER/tmp/adb.logdan membangun kembali adb :)
gluk47

Jawaban:

5

Berikut ini adalah contoh yang sangat sederhana dari menggunakan util-linux's unshareuntuk menempatkan proses di dalam mount namespace pribadi dan memberikannya pandangan yang berbeda dari sistem file yang sama dengan yang dimiliki induknya:

{   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

Anda dapat memberikan proses tampilan pribadi dari sistem file dengan unshareutilitas pada sistem linux terbaru, meskipun fasilitas mount namespace sendiri sudah cukup matang untuk seluruh seri 3.x kernel. Anda dapat memasukkan ruang nama yang sudah ada sebelumnya dari semua jenis dengan nsenterutilitas dari paket yang sama, dan Anda bisa mencari tahu lebih banyak dengan man.

mikeserv
sumber
Hanya satu pertanyaan: apakah ini saya atau itu solusi sempurna tetapi hanya untuk pengguna root saja?
gluk47
@ gluk47 - tidak harus begitu. Anda dapat unsharesemua jenis ruang nama - untuk memasukkan ruang nama pengguna. dan sehingga pengguna Anda dapat menjalankan namespace di mana ia memiliki akses root dan apa pun yang dilakukannya di dalam yang pengguna root mungkin gagal tidak memengaruhi namespace induk. dengan kata lain, mount namespace dapat disematkan di dalam namespace pengguna. Anda benar-benar perlu membaca manhalaman - halaman itu. semakin dalam. inilah tepatnya cara dockerdan sytemd-nspawnkerjanya.
mikeserv
Saya sudah membaca halaman manual dan contoh-contoh dari Internet) Sepertinya saya perlu membacanya lebih lanjut, terima kasih telah menunjukkan teknologi ini, saya entah bagaimana tidak menyadarinya sama sekali.
gluk47
@ gluk47 - jangan terima jawaban demi kesetiaan. Sementara perasaan dihargai, hal-hal semacam itu mengalahkan tujuan tempat ini. terima jawaban yang Anda gunakan . jika salah satu yang tidak satu ini, jangan tidak menerima jawaban ini. omong-omong, hanya karena suatu proses diluncurkan sebagai root, tidak berarti harus tetap menjadi proses root. ada runuserutilitas yang dapat digunakan unshare, dan jika Anda tetap dapat menulis program yang dikompilasi, tidak ada alasan Anda tidak dapat menggunakan unshare()syscall untuk melakukan hal yang sama, atau bahkan hanya system()dengan biner suid.
mikeserv
Saya yakin tidak akan menerima jawabannya jika itu tidak berguna. Saya menemukan kedua jawaban itu relevan dan membantu, jadi sentimen adalah satu-satunya alasan yang membedakan untuk memeriksa salah satu dari jawaban ini :)
gluk47
11

LD_PRELOAD tidak terlalu sulit, dan Anda tidak perlu menjadi root. Sisipkan rutin C Anda sendiri yang disebut bukan yang asli open()di perpustakaan C. Rutin Anda memeriksa apakah file yang dibuka adalah "/tmp/adb.log" dan memanggil file yang sebenarnya terbuka dengan nama file yang berbeda. Inilah shim_open.c Anda:

/*
 * 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);
}

Kompilasi dengan gcc -Wall -O2 -fpic -shared -ldl -o shim_open.so shim_open.cdan mengujinya dengan memasukkan /tmp/myadb.logdan menjalankan sesuatu LD_PRELOAD=/.../shim_open.so cat /tmp/adb.log. Kemudian coba LD_PRELOAD di adb.

meuh
sumber
Ya, memang solusi Anda adalah satu-satunya yang saya berhasil membuat pekerjaan menjadi pengguna non-root. Saya tidak mengatasi unshare ( Operation not permitted). Saya harap itu opencukup untuk ditangani, tetapi akhirnya, menambahkan unlinkke pawang ini tidak sulit.
gluk47
Aww. Sayang sekali saya tidak bisa memeriksa dua jawaban. Saya berjanji mikeserv untuk memeriksa solusinya sebagai jawaban, dan itu memang yang layak.
gluk47
2
sudahlah. Saya belajar unsharejuga, jadi kita semua mendapat untung!
meuh
Setelah beberapa waktu, terima kasih lagi untuk sampel LD_PRELOAD. Sejak saya mencoba kode Anda, saya menggunakan LD_PRELOAD dalam berbagai situasi di mana saya bahkan tidak memikirkannya. Hidup saya telah berubah menjadi lebih baik :)
gluk47
2
@ gluk47 Itulah yang sangat menakjubkan dari Gnu / Linux: Anda tidak perlu berhenti menjelajah! Ada begitu banyak hal baik untuk ditemukan dan dibagikan.
meuh