Heim  >  Artikel  >  Backend-Entwicklung  >  Wie behebe ich den Fehler „EINVAL“ bei der Eingabe des Mount-Namespace in Go?

Wie behebe ich den Fehler „EINVAL“ bei der Eingabe des Mount-Namespace in Go?

Susan Sarandon
Susan SarandonOriginal
2024-11-02 08:54:02587Durchsuche

How to resolve the

Eingabe des Mount-Namespace in Go

Problem:

In Go gibt der setns-Aufruf EINVAL zurück (ungültiges Argument) beim Versuch, den Mount-Namespace für einen Container einzugeben.

Erklärung:

Um einen Namespace mit setns einzugeben, muss der Aufruf zuvor aus einem Single-Threaded-Kontext erfolgen Die Go-Laufzeitthreads werden gestartet.

Lösung:

Es gibt zwei Ansätze zur Behebung dieses Problems:

1. Konstruktor-Trick verwenden:

  • Fügen Sie das Makro __attribute__((constructor)) zu einer C-Funktion hinzu, die setns aufruft, bevor Go startet.
  • Geänderter Go-Code:
<code class="go">/*
#include <sched.h>
#include <stdio.h>
#include <fcntl.h>

__attribute__((constructor)) void enter_namespace(void) {
   setns(open("/proc/<PID>/ns/mnt", O_RDONLY, 0644), 0);
}
*/
import "C"</code>

2. Mit syscall.RawSyscall:

  • Stellen Sie sicher, dass der setns-Aufruf im Hauptthread erfolgt, bevor Sie die Go-Laufzeitthreads starten.
  • Verwenden Sie runtime.LockOSThread, um den Hauptthread zu sperren bei Bedarf.
<code class="go">package main

import (
    "fmt"
    "os"
    "path/filepath"
    "syscall"
    "runtime"
)

func main() {
    if syscall.Geteuid() != 0 {
        fmt.Println("abort: you want to run this as root")
        os.Exit(1)
    }

    if len(os.Args) != 2 {
        fmt.Println("abort: you must provide a PID as the sole argument")
        os.Exit(2)
    }

    // Lock the main thread to the OS thread
    runtime.LockOSThread()

    namespaces := []string{"ipc", "uts", "net", "pid", "mnt"}

    for i := range namespaces {
        fd, _ := syscall.Open(filepath.Join("/proc", os.Args[1], "ns", namespaces[i]), syscall.O_RDONLY, 0644)
        err, _, msg := syscall.RawSyscall(308, uintptr(fd), 0, 0) // 308 == setns

        if err != 0 {
            fmt.Println("setns on", namespaces[i], "namespace failed:", msg)
        } else {
            fmt.Println("setns on", namespaces[i], "namespace succeeded")
        }

    }
}</code>

Hinweis:

  • Stellen Sie sicher, dass Ihr Kernel mehrere Namespaces unterstützt, indem Sie /proc/sys/kernel/namespaces_allowed überprüfen.
  • Der in der Dokumentation zitierte Kernel-Patch gibt an, dass der Prozess CAP_SYS_ADMIN im Ziel-Mount-Namespace haben muss. Stellen Sie sicher, dass diese Bedingungen erfüllt sind, bevor Sie versuchen, setns aufzurufen.

Das obige ist der detaillierte Inhalt vonWie behebe ich den Fehler „EINVAL“ bei der Eingabe des Mount-Namespace in Go?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn