首页  >  文章  >  后端开发  >  为什么在 Go 多线程环境中“setns”会失败并显示 EINVAL?

为什么在 Go 多线程环境中“setns”会失败并显示 EINVAL?

Linda Hamilton
Linda Hamilton原创
2024-11-01 09:23:30646浏览

Why Does 'setns' Fail with EINVAL in a Go Multithreaded Environment?

从 Go 调用 'setns' 失败,MNT 命名空间出现 EINVAL

问题

尝试从 Go 调用 'setns' 进入 MNT 时命名空间,调用始终返回 EINVAL。尽管相同功能的 C 实现正常工作,但仍观察到此问题。

原因

该问题源于 Go 是一种多线程语言,而 'setns' 期望是从单线程上下文调用。当从多线程环境调用时,“setns”无法正确地将当前线程与目标命名空间关联起来。

解决方案 - CGO 构造函数

此问题的解决方案是利用“CGO 构造函数技巧。”该技术允许您在 Go 运行时初始化之前指定要执行的 C 函数。通过使用这种方法,您的 C 函数可以在创建 Go 线程之前调用“setns”,确保调用是在单线程上下文中进行的。

  1. 构造一个调用“setns”的 C 函数' 与所需的参数。通过使用 __attribute__((constructor)) 宏修饰函数来实现此目的。
  2. 通过使用 import "C" 导入 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"

... rest of file is unchanged ...
</code>

请记住将占位符 替换为与目标进程的实际 PID。

限制

这种方法有一些限制:

  • PID 必须在 C 函数中硬编码,就像 Go 一样代码在 C 函数执行时可能不可用。
  • 不可能在 Go 代码中多次调用“setns”,因为 C 代码在 Go 运行时初始化之前运行。

附加说明

“setns(2)”的补丁确认了多线程环境中单线程执行的要求。具有功能的进程还必须在自己的用户命名空间中拥有 CAP_SYS_CHROOT 和 CAP_SYS_ADMIN,并在目标挂载命名空间中拥有 CAP_SYS_ADMIN。

以上是为什么在 Go 多线程环境中“setns”会失败并显示 EINVAL?的详细内容。更多信息请关注PHP中文网其他相关文章!

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