
Para efeitos desta questão, vamos supor que exista um arquivo ( /path/to/file
) no sistema de arquivos com um determinado conteúdo como este:
$> cat /path/to/file
this is the content of the
file /path/to/file
Estou feliz com quase todos os processos em execução (e com acesso de leitura a este arquivo), lendo este conteúdo.
Deveria, no entanto (e este é o cerne da questão) ser um processo específico, que durante a leitura /path/to/file
deve ser fornecido com conteúdo de arquivo diferente.
$> cat /path/to/file
this is the DIFFERNT content of the
file /path/to/file
Como posso falsificar o conteúdo do arquivo para um processo específico?
Algumas suposições minhas sobre qual caminho seguir seriam soluções relacionadas a:
- truque de link simbólico
- (linux) truque de namespaces (namespace do sistema de arquivos)
chroot
truque$LD_PRELOAD
truque de fisgar- sobreposições
Minha plataforma é GNU/linux, mas se houver uma maneira POSIX de conseguir isso seria ainda melhor :)
Atualizar
Qual seria uma boa solução/resposta?
Um critério para uma boa solução/resposta seria que fosse possível obter "conteúdo de arquivo diferente para um processo específico", sem a necessidade da interação do usuário root, mesmo que, idealmente, o arquivo falsificado não deva ser gravável pelo usuário em primeiro lugar.
Outro bom critério seria que a modificação do processo de arquivo mostrado ao processo seja específica e, idealmente, sem tipo de condição de corrida.
Fundo
O Mozilla firefox usa 2 arquivos zip /usr/lib/firefox/omni.ja
e /usr/lib/firefox/browser/omni.ja
, que contêm uma boa quantidade de código do firefox (principalmente o material escrito em Javascript), falsificando o arquivo eu seria capaz de modificar minha versão do firefox (inclui alguns recursos que não posso mais implementar como um extensão, forneceu suporte XPCOM abandonado e não gostou da coerção de assinatura de complementos)
Responder1
Sim, montar namespaces é uma abordagem:
$ 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
Acima, usando zsh
para restaurar o uid/gids do usuário original para o comando cat sequestrado.
Responder2
Aqui está uma maneira de fazer isso compré-carregamentocolocar algum código entre o programa e a biblioteca do sistema, por meio de um pequeno trecho de código. Isto assume que o programa é um binário vinculado dinamicamente ou um script executado por um binário vinculado dinamicamente (ou seja, não está vinculado estaticamente). Escreva o seguinte código em um arquivo 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;
}
Compile com o seguinte comando (para Linux, outras variantes do Unix podem exigir opções diferentes). Observe as aspas ao redor do caminho que você deseja substituir.
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
Execute o programa da seguinte maneira (no OSX, use DYLD_PRELOAD
em vez de LD_PRELOAD
):
LD_PRELOAD=./override_fopen.so ./myexe
Isso só funciona se o programa estiver chamando a função da biblioteca fopen
ou open
. Se chamar alguma outra função, você precisará substituí-la. Você pode usarltrace
para ver quais chamadas de biblioteca o programa faz.