Aufruf von Setns von Go gibt EINVAL für Mnt-Namespace zurück
Hintergrund
Das Ziel ist Geben Sie den mnt-Namespace eines Containers mit C- oder Go-Code ein. Der Go-Code gibt jedoch konsistent EINVAL vom setns-Aufruf zurück, wenn versucht wird, den mnt-Namespace einzugeben.
Arbeitender C-Code
Der folgende C-Code gibt erfolgreich alle angegebenen Namespaces ein :
<code class="c">#include <sched.h> main() { // ... for (i=0; i<5; i++) { setns(fd, 0); // Join the provided namespace } }</code>
Fehlerhafter Go-Code
Andererseits gibt der entsprechende Go-Code einen EINVAL-Fehler für den mnt-Namespace zurück:
<code class="go">import ( "syscall" ) func main() { // ... err := syscall.RawSyscall(308, fd, 0, 0) // Calling setns if err != 0 { fmt.Println("setns on", namespaces[i], "namespace failed") } }</code>
Antwort
Das Problem liegt in der Multithread-Natur von Go. Wenn Go setns aus einem Multithread-Kontext aufruft, schlägt dies für den mnt-Namespace fehl, da ein Single-Thread-Aufrufer erforderlich ist. Um dieses Problem zu beheben, muss der setns-Aufruf erfolgen, bevor die Go-Laufzeit zusätzliche Threads erstellt.
Lösung: Single-Threaded-Konstruktor-Trick
Eine Möglichkeit, dies zu erreichen, ist um den CGO-Konstruktor-Trick zu verwenden, bei dem eine C-Funktion ausgeführt wird, bevor Go startet:
<code class="c">__attribute__((constructor)) void enter_namespace(void) { setns(...); }</code>
Das Hinzufügen dieses Konstruktors zum Go-Code zusammen mit der Festcodierung der PID ermöglicht den erfolgreichen Eintritt in den mnt-Namespace:
<code class="go">/* __attribute__((constructor)) void enter_namespace(void) { ... } */ import "C"</code>
Dieser Ansatz erfordert jedoch eine harte Codierung der PID, was nicht ideal ist.
Alternative: Linux Kernel 4.16 und höher
Im Linux-Kernel 4.16 und höher wurde ein neuer Modus für setns eingeführt, der einen sicheren Aufruf aus Multithread-Kontexten ermöglicht. Durch die Verwendung einer modifizierten Version des setns-Aufrufs, die ein zusätzliches Argument (CLONE_IOCLONE_COMMON) akzeptiert, ist es möglich, den mnt-Namespace von Go aus einzugeben, auch wenn dieser multithreaded ist.
Das obige ist der detaillierte Inhalt vonWarum gibt der Aufruf von Setns von Go aus EINVAL für den Mnt-Namespace zurück?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!