Ich möchte einen Systemaufruf machen und den Kernel so verhalten, als wäre es ein anderer Prozess, der den Anruf tätigt. Man könnte es sich so vorstellen, als würde man sich einen anderen Prozess vorstellen. Ich weiß, dass ich mich mit dem Programmcode mit ptrace anlegen könnte, aber das ist nicht sehr elegant und erfordert wahrscheinlich Optimierungen, um mit dem Prozess, den ich mache, zu arbeiten. Plus, was ich verlange, sollte für den Kernel möglich sein, ohne den Speicher- oder Ausführungsprozess des anderen Prozesses zu berühren, es sei denn, der Effekt des Systemaufrufs, den ich ausführe, würde das natürlich verursachen.Gibt es einen Linux-Systemaufruf, mit dem ich Systemaufrufe im Kontext eines anderen Prozesses ausführen kann?
Die Art, wie ich denke, dass es funktionieren würde, wäre ein (privilegierter) Systemaufruf (nennen wir es setepid
, für "Set effektive PID"), die eine PID als Argument akzeptiert. Nach setepid
verhalten sich alle zukünftigen Systemaufrufe, die von diesem Prozess (oder möglicherweise nur diesem Thread) ausgeführt werden, so, als wäre es der angegebene Prozess, der den Systemaufruf veranlasst. Die Ausnahme ist der Aufruf setepid
selbst, der verwendet werden kann, um den ursprünglichen Kontext wiederherzustellen oder anderweitig einen anderen Prozess zu verwenden.
Zum Beispiel könnte der folgende Code verwendet werden, um die Standardausgabe eines bereits laufenden Prozess (PID 1234 in diesem Beispiel) in die Datei output.txt
, in Prozess 1234 der aktuellen Arbeitsverzeichnis zu umleiten:
setepid(1234); /* perform following system calls on process 1234 */
int fd = open("output.txt", O_WRONLY|O_CREAT|O_TRUNC);
if (fd > 0) {
dup2(fd, 1);
close(fd);
}
setepid(0); /* done acting as 1234, restore original context */
Ein mögliches Problem, das das haben könnte, ist die "output.txt"
Zeichenfolge-Konstante, die als ein Zeiger übergeben wird. Abhängig davon, wie setepid
implementiert wird, kann es sein, dass dieser Zeiger möglicherweise als eine Adresse im Speicher des Prozesses 1234 behandelt wird. Da es auch dann nicht sinnvoll, statisch Speicher zuweisen (einschließlich für eine konstante) in einem anderen Prozess zum Zeitpunkt der Kompilierung, um das immer etwas hässlich wie diese stattdessen erfordern würde:
setepid(1234);
char *buf = mmap(NULL, 12, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
setepid(0);
const char *str = "output.txt\0"; /* extra byte to make it a multiple of 4 */
/* Disclaimer: I'm not sure if I'm using ptrace correctly, but you get the idea. */
ptrace(PTRACE_ATTACH, 1234, NULL, NULL);
ptrace(PTRACE_POKEDATA, 1234, buf, *(void**)str);
ptrace(PTRACE_POKEDATA, 1234, buf+4, *(void**)(str+4));
ptrace(PTRACE_POKEDATA, 1234, buf+8, *(void**)(str+8));
ptrace(PTRACE_DETACH, 1234, NULL, NULL);
setepid(1234);
int fd = open(buf, O_WRONLY|O_CREAT|O_TRUNC);
if (fd > 0) {
dup2(fd, 1);
close(fd);
}
setepid(0);
Ich gehe davon aus eine solche Mechanismus existiert nicht, obwohl ich hoffe, ich liege falsch. Wenn meine Annahme richtig ist, gibt es Probleme, die verhindern, dass dies in einer zukünftigen Version von Linux hinzugefügt wird? Wäre es einfach (oder sogar möglich), dies in einem Kernelmodul zu implementieren? Es klingt, als wäre es ein gefährliches, aber mächtiges und potentiell nützliches Werkzeug.
Sinn macht. Ich wollte damit experimentieren, aber danke. – flarn2006