首页  >  文章  >  后端开发  >  如何解决Go中输入挂载命名空间时出现“EINVAL”错误?

如何解决Go中输入挂载命名空间时出现“EINVAL”错误?

Susan Sarandon
Susan Sarandon原创
2024-11-02 08:54:02587浏览

How to resolve the

在 Go 中输入 Mount 命名空间

问题:

在 Go 中,setns 调用返回 EINVAL(无效参数)尝试进入容器的挂载命名空间时。

说明:

要使用 setns 进入命名空间,必须先从单线程上下文进行调用Go 运行时线程启动。

解决方案:

有两种方法可以解决此问题:

1.使用构造函数技巧:

  • 将 __attribute__((constructor)) 宏添加到在 Go 启动之前调用 setns 的 C 函数。
  • 修改的 Go 代码:
<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。使用syscall.RawSyscall:

  • 确保在启动Go运行时线程之前在主线程中进行setns调用。
  • 使用runtime.LockOSThread锁定主线程
<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>

注意:

  • 通过检查 /proc/sys/kernel/namespaces_allowed 确保您的内核支持多个命名空间。
  • 文档中引用的内核补丁指定进程在目标挂载命名空间中必须具有 CAP_SYS_ADMIN。在尝试调用 setns 之前,请确保满足这些条件。

以上是如何解决Go中输入挂载命名空间时出现“EINVAL”错误?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn