背景

背景

この質問の目的のために、/path/to/fileファイルシステム内に次のような特定のコンテンツを持つファイル ( ) があると仮定します。

$> cat /path/to/file
this is the content of the
file /path/to/file 

ほぼすべてのプロセスが実行され(このファイルへの読み取りアクセス権を持ち)、このコンテンツが読み取られていることに満足しています。
ただし、(これが質問の核心です) は特定のプロセスであり、読み取り時に/path/to/file異なるファイル コンテンツが提供される必要がある。

$> cat /path/to/file
this is the DIFFERNT content of the
file /path/to/file 

特定のプロセスのファイル内容を偽装するにはどうすればよいでしょうか?

私の推測では、どの道を選ぶべきかは次のような解決策に関連するでしょう。

  • シンボリックリンクのトリック
  • (Linux) 名前空間 (ファイルシステム名前空間) トリック
  • chroot騙す
  • $LD_PRELOADフックトリック
  • オーバーレイ

私のプラットフォームは GNU/linux ですが、これを実現する POSIX の方法があればさらに良いでしょう :)

アップデート

良い解決策/答えは何でしょうか?

適切なソリューション/回答の基準は、理想的には偽装されたファイルはそもそもユーザーが書き込み可能ではないはずであるにもかかわらず、ルートユーザーの操作を必要とせずに「特定のプロセスに対して異なるファイル コンテンツ」を実現できることです。

もう 1 つの適切な基準は、プロセスに表示されるファイル プロセスの変更が特定のものであり、理想的には競合状態のようなものがないことです。

背景

Mozilla Firefox は 2 つの zip アーカイブ/usr/lib/firefox/omni.jaと を使用します/usr/lib/firefox/browser/omni.ja。これらには Firefox のコード (主に JavaScript で書かれたもの) がかなり含まれています。ファイルを偽装することで、Firefox のバージョンを変更できます (拡張機能として実装できなくなった機能、XPCOM サポートの廃止、アドオン署名の強制の嫌悪感など)。

答え1

はい、名前空間をマウントするのは 1 つの方法です。

$ cat file
foo
$ cat other-file
bar
$ sudo unshare -m zsh -c 'mount --bind other-file file; USERNAME=$SUDO_USER; cat file'
bar
$ cat file
foo

上記は、zshハイジャックされた cat コマンドの元のユーザーの uid/gid を復元するために使用します。

答え2

これを行う方法は次のとおりですプリロード小さなコード片によって、プログラムとシステム ライブラリの間にコードを挟み込みます。これは、プログラムが動的にリンクされたバイナリ、または動的にリンクされたバイナリによって実行されるスクリプト (つまり、静的にリンクされていない) であることを前提としています。次のコードをファイルに書き込みますoverride_fopen.c

#include <dlfcn.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#ifndef FROM
#error "Define FROM to the path to override in double quotes, e.g. -DFROM='\"/bad\"'"
#endif
#ifndef TO
#error "Define TO to the path to use instead in double quotes, e.g. -DFROM='\"/good\"'"
#endif
FILE *fopen(const char *path, const char *mode) {
    void *(*original_fopen)(const char *, const char *) = dlsym(RTLD_NEXT, "fopen");
    if (!strcmp(path, FROM)) {
        path = TO;
    }
    return original_fopen(path, mode);
}
int open(const char *path, int oflag, ...) {
    int (*original_open)(const char *, int, ...) = dlsym(RTLD_NEXT, "open");
    int ret;
    va_list args;
    if (!strcmp(path, FROM)) {
        path = TO;
    }
    va_start(args, oflag);
    if (oflag & O_CREAT) {
        ret = original_open(path, oflag, (mode_t)va_arg(args, mode_t));
    } else {
        ret = original_open(path, oflag);
    }
    va_end(args);
    return ret;
}

次のコマンドでコンパイルします (これは Linux 用です。他の Unix 系では異なるオプションが必要な場合があります)。上書きするパスを引用符で囲むことに注意してください。

gcc -DFROM='"/path/to/file"' -DTO='"/path/to/alternate/content"' -D_GNU_SOURCE -O -Wall -fPIC -shared -o override_fopen.so override_fopen.c -ldl

プログラムを次のように実行します (OSX では、DYLD_PRELOADの代わりにを使用しますLD_PRELOAD)。

LD_PRELOAD=./override_fopen.so ./myexe

これはプログラムfopenがまたはopenライブラリ関数を呼び出す場合にのみ機能します。他の関数を呼び出す場合は、その関数をオーバーライドする必要があります。ltraceプログラムがどのようなライブラリ呼び出しを行うかを確認します。

関連情報