프로세스의 특정 경로를 위조 할 수 있습니까?


9

루트가 아닌 여러 사용자가있는 Linux 서버에서 ADB를 실행하려고합니다 (안드로이드 에뮬레이터로 재생). adb 데몬은 파일에 로그를 기록하지만 /tmp/adb.log불행히도 ADB에 하드 코딩 된 것처럼 보이며이 상황 은 바뀌지 않을 것 입니다.

따라서 adb가 실행되지 않아 명백한 오류가 발생 cannot open '/tmp/adb.log': Permission denied합니다. 이 파일은 다른 사용자가 작성했으며 /tmp고정 비트가 있습니다. adb nodaemon serverstdout에 쓰면서 adb를 시작하면 오류가 발생하지 않습니다 (충돌을 피하기 위해 포트를 고유 값으로 설정했습니다).

내 질문은 : ADB가 아닌 다른 파일에 쓸 수있는 방법이 /tmp/adb.log있습니까? 보다 일반적으로 일종의 프로세스 별 심볼릭 링크를 만드는 방법이 있습니까? 나는 모든 파일 액세스를 리디렉션하려면 /tmp/adb.log, 파일 말에 ~/tmp/adb.log.

다시 말하지만, 정말, 서버에 루트 아닙니다 chroot, mount -o rbind그리고 chmod유효한 옵션이 아니다. 가능하다면 ADB 소스를 수정하고 싶지는 않지만 다른 솔루션이 없다면 그렇게 할 것입니다.

PS는 특정 ADB 케이스를 위해 나는 실행에 의지 할 수 adb nodaemon servernohup출력 재 지정하지만, 일반적인 질문은 여전히 관련이있다.


2
예. 프로세스를 개인용 마운트 네임 스페이스에 넣고 다른 파일을 /tmp/adb.log에 마운트하거나 자체의 개인용 마운트를 마운트 할 수도 있습니다 /tmp. 수행 man unshareman namespacesman nsenter.
mikeserv

1
@ mikeserv 위대한, 그게 내가 필요한 것 같아요, 감사합니다! 의견을 답변으로 다시 형식화하면 의견을 수락 한 것으로 설정할 수 있습니다.
gluk47

또는 LD_PRELOAD트릭이 있지만 더 복잡 할 수 있습니다.
thrig

@thrig 그래, LD_PRELOAD에 대해서는 잘 알고 있지만 솔직히 /home/$USER/tmp/adb.logadb 를 하드 코딩 하고 재 구축하는 것이 더 쉬울 것이다. :)
gluk47

답변:


5

여기에 사용하는 매우 간단한 예제 util-linuxunshare개인 마운트 네임 스페이스에 프로세스를 넣어 그것을 부모가 현재 가지고있는 동일한 파일 시스템의 다른보기를 제공하는이 :

{   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마운트 네임 스페이스 기능 자체는 전체 3.x 커널 시리즈에서 상당히 성숙했지만 프로세스에 최신 Linux 시스템 의 유틸리티를 사용하여 파일 시스템의 개인보기를 제공 할 수 있습니다 . nsenter동일한 패키지의 유틸리티를 사용하여 모든 종류의 기존 네임 스페이스를 입력 할 수 있으며를 통해 자세한 내용을 확인할 수 있습니다 man.


단 한 번의 Quiestion : 나입니까, 아니면 완벽한 사용자이지만 루트 사용자에게만 해당됩니까?
gluk47

@ gluk47-반드시 그럴 필요는 없습니다. 당신은 수있는 unshare네임 스페이스의 모든 종류 - 사용자 네임 스페이스를 포함합니다. 따라서 사용자는 루트 액세스 권한이있는 네임 스페이스를 실행할 수 있으며 루트 사용자가 망칠 수있는 네임 스페이스는 부모 네임 스페이스에 영향을 미치지 않습니다. 즉, 마운트 네임 스페이스는 사용자 네임 스페이스 내에 임베드 될 수 있습니다. 당신은 정말로 그 man페이지 들을 읽어야 합니다. 깊어진다. 이 정확히 어떻게 docker하고 sytemd-nspawn작동합니다.
mikeserv

인터넷에서 그 매뉴얼 페이지와 예제를 읽었습니다) 더 읽어야 할 것 같습니다.이 기술을 지적 해 주셔서 감사합니다. 어쨌든 전혀 알지 못했습니다.
gluk47

@ gluk47-충성을 위해 답변을 수락하지 마십시오. 감정은 높이 평가되지만, 그런 종류의 것들이이 장소의 목적을 무너 뜨립니다. 사용 하는 답변을 수락하십시오 . 이 중 하나가 아닌 경우이 답변을 수락 하지 마십시오 . 그런데 프로세스가 루트 로 시작 되었다고 해서 루트 프로세스 를 유지 해야한다는 의미는 아닙니다 . 가 runuser함께 사용할 수있는 유틸리티는 unshare, 당신이 어떻게 든 컴파일 된 프로그램을 작성 열려 있다면, 당신은 사용할 수없는 이유가 없다 unshare()같은, 또는 단지 할 콜을 system()SUID 바이너리는.
mikeserv

유용하지 않은 경우 답변을 수락하지 않을 것입니다. 나는 답이 적절하고 도움이된다는 것을 알게되었으므로 감정은 이러한 답 중 하나를 확인하는 유일한 이유입니다.)
gluk47

11

LD_PRELOAD는 그리 어렵지 않으며 루트 일 필요는 없습니다. open()C 라이브러리에서 실제 대신 호출되는 자신의 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. 그런 다음 adb에서 LD_PRELOAD를 시도하십시오.


글쎄, 귀하의 솔루션은 루트가 아닌 사용자가 작업을 수행 할 수있는 유일한 솔루션입니다. 공유 해제 ( Operation not permitted)에 대처하지 않았습니다 . 나는 그것이 open처리하기에 충분하기를 희망 하지만, 마침내이 unlink핸들러에 추가 하는 것은 어렵지 않습니다.
gluk47

앗 두 가지 답변을 확인할 수 없다는 것이 부끄러운 일입니다. 나는 Mikeserv가 자신의 솔루션을 답으로 확인하겠다고 약속했으며 실제로는 실용적입니다.
gluk47

2
신경 쓰지 마. 나도 배웠 unshare으므로 우리 모두는 얻는다!
meuh

얼마 후 LD_PRELOAD 샘플에 다시 한번 감사드립니다. 코드를 사용해 보았으므로 생각조차하지 못하는 다양한 상황에서 LD_PRELOAD를 사용하고 있습니다. 내 인생이 더 좋아졌다 :)
gluk47

2
@ gluk47 그게 GNU / 리눅스에서 정말 멋진 점입니다. 탐험을 중단 할 필요는 없습니다! 발견하고 공유 할 좋은 것들이 많이 있습니다.
meuh
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.