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


9

ルートではない(Androidエミュレーターでプレイする)複数のユーザーがいる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

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

PS特定のADBの場合、リダイレクトを実行adb nodaemon servernohupて出力をリダイレクトすることに頼ることができますが、一般的な質問は依然として関連しています。


2
はい。プロセスをプライベートマウント名前空間に配置し、他のファイルをにマウントするか/tmp/adb.log、独自のプライベートを/tmp完全にマウントすることもできます。行うman unshareman namespacesman nsenter
mikeserv 2015年

1
@mikeserv素晴らしい、それは私がまさに必要としているもののようです、ありがとう!コメントを回答として再フォーマットすると、承認済みに設定できます。
gluk47

またはLD_PRELOAD、トリックがありますが、より複雑になります。
2015年

@thrigええ、私はLD_PRELOADについては考えましたが、率直に言って、/home/$USER/tmp/adb.logadb をハードコーディングして再構築する方が簡単です:)
gluk47

回答:


5

ここで使用したのは非常に簡単な例であるutil-linuxのをunshareプライベートマウント名前空間にプロセスを入れて、それをその親が現在持っている同じファイルシステムの異なるビューを提供します:

{   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システムのユーティリティを使用して、プロセスにそのファイルシステムのプライベートビューを与えることができますが、マウントネームスペース機能自体は3.xカーネルシリーズ全体に対してかなり成熟しています。nsenter同じパッケージのユーティリティを使用して、あらゆる種類の既存の名前空間を入力できますman。さらに、を使用して詳細を調べることができます。


ただ1つの静止:それは私ですか、それとも完全なソリューションですが、rootユーザーのみですか?
gluk47 2015年

@ gluk47-である必要はありません。unshareすべての種類の名前空間を使用できます-ユーザー名前空間を含めることができます。そして、ユーザーはrootアクセスが可能なネームスペースを実行でき、rootユーザーが失敗する可能性のある操作は親ネームスペースには影響しません。つまり、マウント名前空間をユーザー名前空間に埋め込むことができます。あなたは本当にそれらのmanページを読む必要があります。深くなる。これがまさに方法dockersytemd-nspawn働きです。
mikeserv 2015年

それらのマンページと例をインターネットから読んだことがあります)もっと読む必要があるようですが、このテクノロジーを指摘してくれてありがとう、どういうわけかまったく知りませんでした。
gluk47 2015年

@ gluk47-忠誠心のための回答を受け入れない。感情は高く評価されますが、そのようなことはこの場所の目的を無効にします。使用する答えを受け入れます。それがこれではない場合、この答えを受け入れないでください。ちなみに、プロセスがルートとして起動されたからといって、それがルートプロセスのままである必要あるわけではありません。でrunuser使用できるユーティリティがあり、unshareとにかくコンパイルされたプログラムを作成することに心を開いている場合は、unshare()syscallを使用して同じことを実行できなかった、または単にsystem()suidバイナリでさえ実行できなかったという理由はありません。
mikeserv 2015年

それが役に立たなかった場合、私はその答えを受け入れないでしょう。私は回答が適切で役立つと思うので、感情はこれらの回答の1つを確認する唯一の際立った理由です:)
gluk47

11

LD_PRELOADはそれほど難しくなく、ルートである必要はありません。open()Cライブラリの実際のルーチンの代わりに呼び出される独自の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を試してください。


まあ、確かにあなたの解決策は私がroot以外のユーザーとして仕事をすることができた唯一のものです。共有解除(Operation not permitted)には対応しませんでした。これopenで十分ですが、最後に、unlinkこのハンドラに追加することは難しくありません。
gluk47

ああ。2つの答えを確認できないのは残念です。私は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.