c++ - 为什么我使用 unshare(CLONE_NEWUSER) 后无法运行某些程序
问题描述
我正在努力为我的构建过程添加一些限制——特别是检测周期。为了实现这一点,我一直在尝试用户命名空间。
这是我的“hello world”程序:
#include <sched.h>
#include <unistd.h>
int main()
{
if( unshare(CLONE_NEWUSER) != 0)
{
return -1;
}
execl("/bin/sh", "/bin/sh", "-e", "-c", "make", NULL);
return 0;
}
这是make运行的makefile,namespace_test.cpp是上面文件的名字:
namespace_test: namespace_test.cpp
g++ namespace_test.cpp -o ./namespace_test
当一切都是最新的(由 make 确定)时,exec'd 程序按预期工作:
make: 'namespace_test' is up to date.
但如果make
实际运行g++
调用,我会收到一个不透明的错误:
g++ namespace_test.cpp -o ./namespace_test
make: g++: Invalid argument
make: *** [Makefile:2: namespace_test] Error 127
这种行为的原因是什么?
解决方案
此错误是由于我未能设置uid_map
and gid_map
。我还没有给出一个令人满意的、明确的、最小的错误示例,但是我已经编写了一个可行的最小解决方案,我将在这里分享。请注意,这int main()
是相同的,除了在exec
'ing 目标命令之前,我们首先设置了uid_map
,然后设置了gid_map
(通过 授予我们自己的权限setgroups
)。
在我的终端上$ id
通知我,我的真实 uid 和 gid 都是 1000,所以我在地图中硬编码了它。在流程开始时查询原始 id 更正确,请参阅这篇出色的博客文章。此手册页也有助于此解决方案。
#include <cstdio>
#include <cstring>
#include <fcntl.h>
#include <sched.h>
#include <stdlib.h>
#include <unistd.h>
#define fatal_error(...) \
do { \
fprintf(stderr, "namespace_test \033[1;31merror:\033[0m "); \
fprintf(stderr, __VA_ARGS__ ); \
fprintf(stderr, "\n"); \
exit(EXIT_FAILURE); \
} while(0)
void write_string_to_file(const char* filename, const char* str, size_t str_len)
{
int fd = open(filename, O_RDWR);
if(fd == -1)
{
fatal_error("Failed to open %s: %m", filename);
}
if( write(fd, str, str_len) != str_len )
{
fatal_error("Failed to write %s: %m", filename);
}
close(fd);
}
void write_uid_mapping()
{
const char* mapping = "0 1000 1";
write_string_to_file("/proc/self/uid_map", mapping, strlen(mapping));
}
void write_set_groups()
{
const char* deny = "deny\n";
write_string_to_file("/proc/self/setgroups", deny, strlen(deny));
}
void write_gid_mapping()
{
write_set_groups();
const char* mapping = "0 1000 1";
write_string_to_file("/proc/self/gid_map", mapping, strlen(mapping));
}
int main()
{
if(unshare(CLONE_NEWUSER) != 0)
{
fatal_error("Failed to move into new user namespace");
}
write_uid_mapping();
write_gid_mapping();
execl("/bin/sh", "/bin/sh", "-e", "-c", "make", NULL);
return 0;
}
推荐阅读
- amazon-web-services - 在 Alexa 技能中使用 aws-sdk
- api - 如何为 IG 媒体获取 Instagram 图像分辨率
- java - @DataJpaTest 不能排除反应性 mongo 的存储库
- c# - 使用自动映射器映射对象的问题
- javascript - 如何计算 jalali 日历中的闰年?
- python - 用于类型生成函数的 Python3 类型注释
- reactjs - y 轴上的 react-chart-js-2 单位
- java - java.lang.NullPointerException 运行 cucumber+maven 测试
- javascript - 在客户端读取提要时出现 NotAllowedException
- c# - Unity Json 无法序列化通用列表