web-dev-qa-db-ja.com

プロセスの特定のパスを偽造することは可能ですか?

私がrootではない複数のユーザーがいるLinuxサーバーでADBを実行しようとしています(私のAndroidエミュレータで遊ぶため)。adbデーモンは、残念ながらファイル/tmp/adb.logにログを書き込みますADBとこの状況にハードコードされる 変更されない

そのため、adbは実行に失敗し、明白なエラーcannot open '/tmp/adb.log': Permission deniedが発生します。このファイルは別のユーザーによって作成され、/tmpにスティッキービットがオンになっています。 adb nodaemon serverでadbを開始してstdoutに書き込む場合、エラーは発生しません(競合を回避するために、ポートを一意の値に設定します)。

私の質問は、ADBが/tmp/adb.log以外の別のファイルに書き込む方法はありますか? より一般的には、プロセス固有のシンボリックリンクのようなものを作成する方法はありますか?/tmp/adb.logへのすべてのファイルアクセスをリダイレクトして、ファイル~/tmp/adb.log

繰り返しますが、私はサーバーのルートではないため、chrootmount -o rbind、およびchmodは有効なオプションではありません。できればADBのソースを変更したくないのですが、他に解決策がなければきっと修正します。

追伸特定のADBケースでは、Nohupと出力リダイレクトを使用してadb nodaemon serverを実行することに頼ることができますが、一般的な質問は依然として関連しています。

9
gluk47

以下は、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

最新のLinuxシステムでは、unshareユーティリティを使用してプロセスにファイルシステムのプライベートビューを提供できますが、マウント名前空間機能自体は3.xカーネルシリーズ全体でかなり成熟しています。同じパッケージのnsenterユーティリティを使用して、既存のすべての種類の名前空間を入力できます。詳細は、manを使用して確認できます。

5
mikeserv

LD_PRELOADはそれほど難しくなく、ルートである必要はありません。 Cライブラリの実際のopen()の代わりに呼び出される独自のCルーチンを挿入します。ルーチンは、開くファイルが「/tmp/adb.log」であるかどうかを確認し、実際のopenを別のファイル名で呼び出します。これが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を試してください。

11
meuh