Có thể giả mạo một đường dẫn cụ thể cho một quá trình?


9

Tôi đang cố gắng chạy ADB trên máy chủ linux có nhiều người dùng mà tôi không root (để chơi với trình giả lập Android của tôi). Trình nền adb ghi nhật ký của nó vào tệp /tmp/adb.log, điều không may dường như được mã hóa cứng vào ADB và tình huống này sẽ không thay đổi .

Vì vậy, adb không chạy được, đưa ra lỗi rõ ràng : cannot open '/tmp/adb.log': Permission denied. Tập tin này được tạo bởi một người dùng khác và /tmpcó bit dính trên. Nếu tôi bắt đầu adb bằng adb nodaemon servercách làm cho nó ghi vào thiết bị xuất chuẩn, sẽ không có lỗi xảy ra (tôi cũng thiết lập cổng của nó thành một giá trị duy nhất để tránh xung đột).

Câu hỏi của tôi là: có cách nào để làm cho ADB ghi vào một tệp khác /tmp/adb.logkhông? Tổng quát hơn, có cách nào để tạo ra một loại liên kết tượng trưng cụ thể cho quá trình không? Tôi muốn chuyển hướng tất cả các tệp truy cập /tmp/adb.logđến, nói, một tệp ~/tmp/adb.log.

Một lần nữa, tôi không root trên máy chủ, vì vậy chroot, mount -o rbindchmodkhông phải là tùy chọn hợp lệ. Nếu có thể, tôi muốn không sửa đổi các nguồn ADB, nhưng chắc chắn nếu không có giải pháp nào khác, tôi sẽ làm điều đó.

PS Đối với trường hợp cụ thể của ADB tôi có thể nghỉ mát để chạy adb nodaemon servervới nohupvà chuyển hướng đầu ra, nhưng câu hỏi chung là vẫn có liên quan.


2
Đúng. bạn có thể đặt quy trình của mình trong một không gian tên gắn kết riêng tư và gắn kết một số tệp khác /tmp/adb.loghoặc thậm chí gắn kết riêng tư của nó /tmp. làm man unshareman namespacesman nsenter.
mikeerv

1
@mikeerv tuyệt vời, đó dường như là chính xác những gì tôi cần, cảm ơn bạn! Nếu bạn định dạng lại nhận xét của mình dưới dạng câu trả lời, tôi sẽ có thể đặt nhận xét đó là chấp nhận.
gluk47

Hoặc có những LD_PRELOADmánh khóe, mặc dù điều đó sẽ phức tạp hơn.
thrig

@thrig yeah, tôi nghĩ về LD_PRELOAD, nhưng thật lòng mà nói, việc mã hóa /home/$USER/tmp/adb.logvà xây dựng lại adb sẽ dễ dàng hơn :)
gluk47

Câu trả lời:


5

Dưới đây là một ví dụ rất đơn giản của việc sử dụng util-linux's unshaređể đặt một quá trình trong một gắn kết không gian tên riêng và cung cấp cho nó một cái nhìn khác nhau của hệ thống tập tin cùng mẹ của nó hiện đang có:

{   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

Bạn có thể cung cấp cho chế độ một chế độ xem riêng tư về hệ thống tệp của nó với unsharetiện ích trên các hệ thống linux cập nhật, mặc dù chính cơ sở không gian tên mount đã khá hoàn thiện cho toàn bộ chuỗi hạt nhân 3.x. Bạn có thể nhập các không gian tên có sẵn của tất cả các loại với nsentertiện ích từ cùng một gói và bạn có thể tìm hiểu thêm với man.


Chỉ cần một câu hỏi: đó là tôi hay nó là một giải pháp hoàn hảo nhưng chỉ dành cho người dùng root?
gluk47

@ gluk47 - không cần phải như vậy. bạn có thể unsharetất cả các loại không gian tên - để bao gồm không gian tên người dùng. và vì vậy người dùng của bạn có thể chạy một không gian tên trong đó nó có quyền truy cập root và bất cứ điều gì nó làm trong đó người dùng root có thể làm hỏng không ảnh hưởng đến không gian tên cha. nói cách khác, một không gian tên mount có thể được nhúng trong một không gian tên người dùng. bạn thực sự cần phải đọc những mantrang đó nó trở nên sâu sắc đây chính xác là cách thức dockersytemd-nspawncông việc
mikeerv

Tôi đã đọc những trang người đàn ông và ví dụ từ Internet) Dường như tôi cần đọc chúng nhiều hơn, chỉ cảm ơn bạn đã chỉ ra công nghệ này, bằng cách nào đó tôi không biết gì về nó cả.
gluk47

@ gluk47 - không chấp nhận câu trả lời vì lợi ích của lòng trung thành. trong khi tình cảm được đánh giá cao, loại công cụ đó đánh bại mục đích của nơi này. chấp nhận câu trả lời bạn sử dụng . Nếu đó không phải là cái này, xin vui lòng không chấp nhận câu trả lời này. bằng cách này, chỉ vì một quy trình được khởi chạy với quyền root, không có nghĩa là nó phải duy trì quá trình root. có runusertiện ích có thể được sử dụng unsharevà nếu bạn vẫn sẵn sàng viết các chương trình được biên dịch, không có lý do gì bạn không thể sử dụng tòa nhà unshare()để làm điều tương tự, hoặc thậm chí chỉ system()với nhị phân suid.
mikeerv

Tôi chắc chắn không chấp nhận câu trả lời nếu nó không hữu ích. Tôi thấy cả hai câu trả lời đều phù hợp và hữu ích, vì vậy tình cảm là lý do duy nhất để kiểm tra một trong những câu trả lời này :)
gluk47

11

LD_PRELOAD không quá khó và bạn không cần phải root. Thay thế thói quen C của riêng bạn được gọi thay vì thực open()trong thư viện C. Thường trình của bạn kiểm tra xem tệp cần mở là "/tmp/adb.log" và gọi mở thực sự với một tên tệp khác. Đây là shim_open.c của bạn:

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

Biên dịch nó gcc -Wall -O2 -fpic -shared -ldl -o shim_open.so shim_open.cvà kiểm tra nó bằng cách đặt một cái gì đó vào /tmp/myadb.logvà chạy LD_PRELOAD=/.../shim_open.so cat /tmp/adb.log. Sau đó thử LD_PRELOAD trên adb.


Chà, thực sự giải pháp của bạn là giải pháp duy nhất mà tôi quản lý để biến công việc thành người dùng không root. Tôi đã không đối phó với unshare ( Operation not permitted). Tôi hy vọng điều đó openlà đủ để xử lý, nhưng cuối cùng, việc thêm unlinkvào trình xử lý này không khó.
gluk47

À. Thật là xấu hổ khi tôi không thể kiểm tra hai câu trả lời. Tôi đã hứa với mikeerv sẽ kiểm tra giải pháp của anh ấy như một câu trả lời, và đó thực sự là một giải pháp khả thi.
gluk47

2
đừng bận tâm. Tôi đã học về unsharenhư là tốt, vì vậy tất cả chúng ta đạt được!
meuh

Sau một thời gian, cảm ơn bạn một lần nữa cho mẫu LD_PRELOAD. Vì tôi đã thử mã của bạn, tôi đang sử dụng LD_PRELOAD trong nhiều tình huống mà tôi thậm chí không nghĩ về nó. Cuộc sống của tôi đã thay đổi tốt hơn :)
gluk47

2
@ gluk47 Đó là điều tuyệt vời về Gnu / Linux: bạn không bao giờ ngừng khám phá! Có rất nhiều thứ tốt để khám phá và chia sẻ.
meuh
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.