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