首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么CAP_NET_ADMIN对ioctl(TUNSETIFF)的权限不足?

为什么CAP_NET_ADMIN对ioctl(TUNSETIFF)的权限不足?
EN

Unix & Linux用户
提问于 2019-03-17 04:29:05
回答 3查看 7.5K关注 0票数 8

我在用Rust写一个tun/tap程序。由于我不希望它以root的形式运行,所以我将CAP_NET_ADMIN添加到二进制的功能中:

代码语言:javascript
运行
复制
$sudo setcap cap_net_admin=eip target/release/tunnel
$getcap target/release/tunnel
target/release/tunnel = cap_net_admin+eip

然而,这是行不通的。我所读到的一切都表明,这是创建调谐器所需的唯一功能,但是程序在ioctl上得到了一个EPERM。在strace中,我看到了这个错误:

代码语言:javascript
运行
复制
openat(AT_FDCWD, "/dev/net/tun", O_RDWR|O_CLOEXEC) = 3
fcntl(3, F_GETFD)                       = 0x1 (flags FD_CLOEXEC)
ioctl(3, TUNSETIFF, 0x7ffcdac7c7c0)     = -1 EPERM (Operation not permitted)

我已经验证了二进制文件在完全根权限下成功运行,但我不希望这需要sudo来运行。为什么CAP_NET_ADMIN在这里还不够?

作为参考,我在Linux version 4.15.0-45上只有几种方法,我看到这个ioctl可以在内核(https://elixir.bootlin.com/linux/v4.15/source/drivers/net/tun.c#L2194)中返回EPERM,而且其中至少有一种似乎是满意的。我不知道怎么去探测其他人:

代码语言:javascript
运行
复制
if (!capable(CAP_NET_ADMIN))
    return -EPERM;
...
if (tun_not_capable(tun))
    return -EPERM;
...
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
    return -EPERM;
EN

回答 3

Unix & Linux用户

回答已采纳

发布于 2023-02-14 19:43:30

我在编写一个Rust程序时也遇到了同样的问题,这个程序产生了一个用于创建和管理TUN/TAP接口的tunctl过程。

例如:

代码语言:javascript
运行
复制
let tunctl_status = Command::new("tunctl")
            .args(&["-u", "user", "-t", "tap0"])
            .stdout(Stdio::null())
            .status()?;

失败:

代码语言:javascript
运行
复制
$ ./target/debug/nio
TUNSETIFF: Operation not permitted
tunctl failed to create tap network device.

即使设置了NET_ADMIN文件功能:

代码语言:javascript
运行
复制
$ sudo setcap cap_net_admin=+ep ./target/debug/nio
$ getcap ./target/debug/nio                       
./target/debug/nio cap_net_admin=ep

手册规定:

由于当作为非根用户运行时,可继承功能通常不会在execve(2)中保留,因此希望运行功能提升的助手程序的应用程序应该考虑使用环境功能,如下所述。

为了涵盖execve()系统调用的情况,我使用了环境功能。

Ambient (因为Linux4.3)这是一组功能,在没有特权的程序的execve(2)中保留。环境能力集遵循不变条件,即如果能力既不允许也不可继承,则任何能力都不可能是环境能力。

Example解决方案:为了方便起见,我使用caps-rs库。

代码语言:javascript
运行
复制
// Check if `NET_ADMIN` is in permitted set.
let perm_net_admin = caps::has_cap(None, CapSet::Permitted, Capability::CAP_NET_ADMIN);
match perm_net_admin {
    Ok(is_in_perm) => {
        if !is_in_perm {
            eprintln!("Error: The capability 'NET_ADMIN' is not in the permitted set!");
            std::process::exit(1)
        }
    }
    Err(e) => {
        eprintln!("Error: {:?}", e);
        std::process::exit(1)
    }
}


// Note: The ambient capability set obeys the invariant that no capability can ever be ambient if it is not both permitted and inheritable.
caps::raise(
    None,
    caps::CapSet::Inheritable,
    caps::Capability::CAP_NET_ADMIN,
)
.unwrap_or_else(fail_due_to_caps_err);

caps::raise(None, caps::CapSet::Ambient, caps::Capability::CAP_NET_ADMIN)
    .unwrap_or_else(fail_due_to_caps_err);

最后,设置NET_ADMIN文件功能就足够了:

代码语言:javascript
运行
复制
$ sudo setcap cap_net_admin=+ep ./target/debug/nio
票数 2
EN

Unix & Linux用户

发布于 2019-03-17 06:41:21

我猜您的target/release/tunnel二进制文件系统是用nosuid选项挂载的。这也将影响文件功能,而不仅仅是setuid位。

此外,您将无法像您所做的那样占用setuid二进制或setuid二进制文件,内核在从execve() d进程调用ptrace时将忽略文件功能:

代码语言:javascript
运行
复制
$ getcap tapy
tapy = cap_net_admin+eip
$ ./tapy
tapy: {tap1}
^C
$ strace -e trace=ioctl ./tapy
ioctl(3, TUNSETIFF, 0x7ffdc5b2fef0)     = -1 EPERM (Operation not permitted)
tapy: ioctl TUNSETIFF: Operation not permitted
+++ exited with 1 +++
票数 5
EN

Unix & Linux用户

发布于 2022-11-24 21:53:57

虽然CAP_NET_ADMIN允许您修改网络配置(如iptables、接口等)以进行实际的攻入和网络i/o读取,但除了CAP_NET_ADMIN之外,您还必须添加CAP_NET_RAW功能。

他们将共同给予你你所寻求的能力。

票数 0
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/506766

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档