เป็นไปได้ที่จะปลอมเส้นทางเฉพาะสำหรับกระบวนการหรือไม่?


9

ฉันกำลังพยายามเรียกใช้ ADB บนเซิร์ฟเวอร์ linux ที่มีผู้ใช้หลายคนที่ฉันไม่ได้รูท (เล่นกับ android emulator ของฉัน) ภูต adb เขียนบันทึกของระบบไปยังแฟ้ม/tmp/adb.logซึ่งน่าเสียดายที่ดูเหมือนว่าจะยากเขียนเป็น ADB และสถานการณ์เช่นนี้จะไม่เกิดการเปลี่ยนแปลง

ดังนั้น adb cannot open '/tmp/adb.log': Permission deniedเป็นความล้มเหลวในการทำงานให้เกิดข้อผิดพลาดที่เห็นได้ชัด: ไฟล์นี้สร้างโดยผู้ใช้รายอื่นและ/tmpมีบิตติดอยู่ ถ้าฉันเริ่ม adb ด้วยadb nodaemon serverการทำให้มันเขียนถึง stdout จะไม่มีข้อผิดพลาดเกิดขึ้น (ฉันยังตั้งค่าพอร์ตเป็นค่าที่ไม่ซ้ำกันเพื่อหลีกเลี่ยงความขัดแย้ง)

คำถามของฉันคือ: มีวิธีทำให้ ADB เขียนไปยังไฟล์อื่นกว่า/tmp/adb.log? โดยทั่วไปแล้วจะมีวิธีสร้าง symlink เฉพาะกระบวนการหรือไม่ ฉันต้องการที่จะเปลี่ยนเส้นทางการเข้าถึงไฟล์ทั้งหมดเพื่อที่จะบอกว่าแฟ้ม/tmp/adb.log~/tmp/adb.log

อีกครั้งผมไม่ได้รากบนเซิร์ฟเวอร์ดังนั้นchroot, mount -o rbindและchmodไม่ได้เป็นตัวเลือกที่ถูกต้อง ถ้าเป็นไปได้ฉันไม่ต้องการแก้ไขแหล่งที่มาของ ADB แต่แน่นอนว่าถ้าไม่มีวิธีแก้ไขปัญหาอื่น ๆ ฉันจะทำเช่นนั้น

ป.ล. สำหรับกรณี ADB เฉพาะฉันสามารถใช้adb nodaemon serverกับnohupและเปลี่ยนเส้นทางการส่งออก แต่คำถามทั่วไปยังคงเกี่ยวข้อง


2
ใช่. คุณสามารถนำกระบวนการของคุณในการติด namespace ส่วนตัวและติดบางไฟล์อื่น ๆ/tmp/adb.logหรือแม้กระทั่งติดส่วนตัวของตัวเอง/tmpโดยสิ้นเชิง ทำman unshareและและman namespaces man nsenter
mikeserv

1
@mikeserv ดีที่ดูเหมือนว่าจะเป็นสิ่งที่ฉันต้องการขอบคุณ! หากคุณฟอร์แมตความคิดเห็นของคุณเป็นคำตอบฉันจะสามารถกำหนดความคิดเห็นของคุณได้
gluk47

หรือมีกลLD_PRELOADอุบายแม้ว่ามันจะซับซ้อนกว่า
thrig

@ thrig ใช่ฉัน แต่เกี่ยวกับ LD_PRELOAD แต่ตรงไปตรงมามันจะง่ายกว่าในการ hardcode /home/$USER/tmp/adb.logและสร้าง adb :)
gluk47

คำตอบ:


5

นี่คือตัวอย่างง่ายๆของการใช้util-linux's unshareที่จะนำกระบวนการในการติด namespace ส่วนตัวและให้มุมมองที่แตกต่างกันของระบบแฟ้มเดียวกันแม่ในปัจจุบันมี:

{   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 ที่ทันสมัยถึงแม้ว่าสิ่งอำนวยความสะดวก mount namespace เองนั้นค่อนข้างเป็นผู้ใหญ่สำหรับเคอร์เนลซีรี่ย์ 3.x ทั้งชุด คุณสามารถป้อน namespaces ที่มีอยู่ก่อนทุกชนิดที่มียูทิลิตี้จากแพคเกจเดียวกันและคุณจะพบมากขึ้นด้วยnsenterman


คำถามเดียว: มันเป็นฉันหรือมันเป็นโซลูชั่นที่สมบูรณ์แบบ แต่สำหรับผู้ใช้รูทเท่านั้น?
gluk47

@ gluk47 - ไม่จำเป็นต้องเป็น คุณสามารถunsharenamespaces ทุกชนิด - เพื่อรวม namespace ผู้ใช้ และเพื่อให้ผู้ใช้ของคุณสามารถเรียกใช้เนมสเปซที่มีการเข้าถึงรูทและสิ่งใดก็ตามที่อยู่ภายในที่ผู้ใช้รูทอาจพลาดไม่ส่งผลกระทบต่อเนมสเปซหลัก กล่าวอีกนัยหนึ่งเมาท์เนมสเปซสามารถฝังอยู่ภายในเนมสเปซของผู้ใช้ คุณต้องอ่านmanหน้าเหล่านั้นจริงๆ มันลึกลงไป นี่เป็นวิธีdockerและการsytemd-nspawnทำงานที่แม่นยำ
mikeserv

ฉันได้อ่าน man pages และตัวอย่างจากอินเทอร์เน็ต) ดูเหมือนว่าฉันจะต้องอ่านพวกมันให้มากขึ้นขอขอบคุณที่ชี้ให้เห็นถึงเทคโนโลยีนี้ฉันก็ไม่ได้ตระหนักถึงมันเลย
gluk47

@ gluk47 - ไม่ยอมรับคำตอบเพื่อประโยชน์ของความภักดี ในขณะที่ความรู้สึกชื่นชมสิ่งต่าง ๆ ที่เอาชนะจุดประสงค์ของสถานที่แห่งนี้ ยอมรับคำตอบที่คุณใช้ หากที่หนึ่งไม่ได้เป็นหนึ่งนี้โปรดอย่าไม่ยอมรับคำตอบนี้ โดยวิธีการเพียงเพราะกระบวนการเปิดตัวเป็นรากไม่ได้หมายความว่ามันจะยังคงเป็นกระบวนการราก มีrunuserยูทิลิตีที่สามารถใช้งานได้unshareและหากคุณเปิดเพื่อเขียนโปรแกรมที่คอมไพล์แล้วไม่มีเหตุผลที่คุณไม่สามารถใช้unshare()syscall เพื่อทำสิ่งเดียวกันหรือแม้แต่system()กับไบนารี suid
mikeserv

ฉันแน่ใจว่าจะไม่ยอมรับคำตอบถ้ามันไม่มีประโยชน์ ผมพบว่าทั้งสองคำตอบที่เกี่ยวข้องและเป็นประโยชน์เพื่อให้ความเชื่อมั่นคือเหตุผลเดียวที่แตกต่างในการตรวจสอบหนึ่งในคำตอบเหล่านี้ :)
gluk47

11

LD_PRELOAD ไม่ยากเกินไปและคุณไม่จำเป็นต้องรูท แทรกรูทีน C ของคุณเองซึ่งถูกเรียกแทนของจริงopen()ในไลบรารี C รูทีนของคุณจะตรวจสอบว่าไฟล์ที่จะเปิดเป็น "/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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.