Maison  >  Article  >  développement back-end  >  Comment résoudre l'erreur \"EINVAL\" lors de la saisie de l'espace de noms de montage dans Go ?

Comment résoudre l'erreur \"EINVAL\" lors de la saisie de l'espace de noms de montage dans Go ?

Susan Sarandon
Susan Sarandonoriginal
2024-11-02 08:54:02587parcourir

How to resolve the

Entrée dans l'espace de noms Mount dans Go

Problème :

Dans Go, l'appel setns renvoie EINVAL (argument invalide) lorsque vous tentez d'entrer l'espace de noms de montage pour un conteneur.

Explication :

Pour entrer un espace de noms à l'aide de setns, l'appel doit être effectué à partir d'un contexte à thread unique avant les threads d'exécution Go démarrent.

Solution :

Il existe deux approches pour résoudre ce problème :

1. Utilisation de l'astuce du constructeur :

  • Ajoutez la macro __attribute__((constructor)) à une fonction C qui appelle setns avant le démarrage de Go.
  • Code Go modifié :
<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. Utilisation de syscall.RawSyscall :

  • Assurez-vous que l'appel setns est effectué dans le thread principal avant de démarrer les threads d'exécution Go.
  • Utilisez runtime.LockOSThread pour verrouiller le thread principal si nécessaire.
<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>

Remarque :

  • Assurez-vous que votre noyau prend en charge plusieurs espaces de noms en vérifiant /proc/sys/kernel/namespaces_allowed.
  • Le correctif du noyau cité dans la documentation précise que le processus doit avoir CAP_SYS_ADMIN dans l'espace de noms de montage cible. Assurez-vous que ces conditions sont remplies avant de tenter d'appeler setns.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn