
Für die Zwecke dieser Frage nehmen wir an, dass es /path/to/file
im Dateisystem eine Datei () mit einem bestimmten Inhalt wie diesem gibt:
$> cat /path/to/file
this is the content of the
file /path/to/file
Ich bin zufrieden damit, dass fast alle Prozesse laufen (und Lesezugriff auf diese Datei haben) und diesen Inhalt lesen.
Es sollte jedoch (und das ist der Kern der Frage) ein bestimmter Prozess sein, welcher beim Lesen /path/to/file
mit unterschiedlichen Dateiinhalten versorgt werden soll.
$> cat /path/to/file
this is the DIFFERNT content of the
file /path/to/file
Wie kann ich den Dateiinhalt für einen bestimmten Prozess irgendwie fälschen?
Einige meiner Vermutungen, welchen Weg man einschlagen sollte, hängen mit Folgendem zusammen:
- Symlink-Trick
- (Linux) Namespaces (Dateisystem-Namespace) Trick
chroot
Trick$LD_PRELOAD
Hakentrick- Überlagerungen
Meine Plattform ist GNU/Linux, aber wenn es eine POSIX-Möglichkeit gäbe, dies zu erreichen, wäre das noch besser :)
Aktualisieren
Was wäre eine gute Lösung/Antwort?
Ein Kriterium für eine gute Lösung/Antwort wäre, dass es möglich ist, „unterschiedliche Dateiinhalte für bestimmte Prozesse“ zu erreichen, ohne dass eine Interaktion des Root-Benutzers erforderlich ist, obwohl die gefälschte Datei im Idealfall von vornherein nicht vom Benutzer beschreibbar sein sollte.
Ein weiteres gutes Kriterium wäre, dass die dem Prozess angezeigte Änderung des Dateiprozesses spezifisch ist und im Idealfall ohne eine Art Race-Condition erfolgt.
Hintergrund
Mozilla Firefox verwendet zwei Zip-Archive /usr/lib/firefox/omni.ja
und /usr/lib/firefox/browser/omni.ja
, die einen Großteil des Firefox-Codes enthalten (hauptsächlich das in Javascript geschriebene Zeug). Durch das Fälschen der Datei könnte ich meine Version von Firefox ändern (einige Funktionen einbauen, die ich nicht mehr als Erweiterung implementieren kann, vorausgesetzt, die XPCOM-Unterstützung wurde eingestellt und die Add-On-Signierungserzwingung wird nicht mehr gemocht).
Antwort1
Ja, das Einbinden von Namespaces ist ein Ansatz:
$ 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
Oben wird zsh
die UID/GID des ursprünglichen Benutzers für den entführten Cat-Befehl verwendet.
Antwort2
Hier ist eine Möglichkeit, dies zu tun mitVorladenum Code zwischen dem Programm und der Systembibliothek einzufügen, und zwar durch ein kleines Stück Code. Dies setzt voraus, dass das Programm eine dynamisch verknüpfte Binärdatei oder ein Skript ist, das von einer dynamisch verknüpften Binärdatei ausgeführt wird (d. h. es ist nicht statisch verknüpft). Schreiben Sie den folgenden Code in eine Datei 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;
}
Kompilieren Sie mit dem folgenden Befehl (das ist für Linux, andere Unix-Varianten erfordern möglicherweise andere Optionen). Beachten Sie die Anführungszeichen um den Pfad, den Sie überschreiben möchten.
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
Führen Sie das Programm wie folgt aus (unter OSX verwenden Sie DYLD_PRELOAD
anstelle von LD_PRELOAD
):
LD_PRELOAD=./override_fopen.so ./myexe
fopen
Dies funktioniert nur, wenn das Programm die Bibliotheksfunktion oder aufruft open
. Wenn es eine andere Funktion aufruft, müssen Sie diese überschreiben. Sie können verwendenltrace
um zu sehen, welche Bibliotheksaufrufe das Programm macht.