Фон

Фон

Для решения этого вопроса предположим, что /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трюк с крючком
  • оверлеиfs

Моя платформа — GNU/Linux, но если есть способ сделать это с помощью POSIX, это было бы еще лучше :)

Обновлять

Какое решение/ответ было бы хорошим?

Критерием хорошего решения/ответа может быть возможность достижения «различного содержимого файла для определенного процесса» без необходимости взаимодействия с пользователем root, даже если в идеале поддельный файл изначально не должен быть доступен для записи пользователем.

Другим хорошим критерием было бы то, что изменение файлового процесса, показанное процессу, является конкретным и, в идеале, без какого-либо состояния гонки.

Фон

Mozilla Firefox использует 2 архива zip /usr/lib/firefox/omni.jaи /usr/lib/firefox/browser/omni.ja, которые содержат довольно много кода Firefox (в основном то, что написано на Javascript). Подделав файл, я смогу изменить свою версию Firefox (включив некоторые функции, которые я больше не могу реализовать как расширение, при условии отказа от поддержки XPCOM и нежелательного принудительного подписывания дополнений).

решение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для восстановления uid/gid исходного пользователя для захваченной команды cat.

решение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чтобы увидеть, какие библиотечные вызовы делает программа.

Связанный контент