简体   繁体   English

无法打开uid_map以便从设置了cap_setuid功能的应用程序进行写入

[英]Cannot open uid_map for writing from an app with cap_setuid capability set

While toying around with an example from user_namespaces(7) , I've come across a strange behaviour. 在摆弄user_namespaces(7)的示例时,我遇到了一种奇怪的行为。

What the application does 该应用程序做什么

The application user-ns-ex calls clone(2) with CLONE_NEWUSER, thus creating a new process in a new user namespace. 应用程序user-ns-ex使用CLONE_NEWUSER调用clone(2),从而在新的用户命名空间中创建一个新进程。 The parent process writes a map ( 0 1000 1 ) to /proc//uid_map file and tells (via a pipe) the child that it can proceed. 父进程将映射( 0 1000 1 )写入/ proc // uid_map文件,并(通过管道)告诉子进程可以继续。 The child process then execs bash . 然后,子进程执行bash

I've copied the source code here . 我已经在这里复制了源代码。

The problem 问题

The application opens /proc//uid_map for writing if I either set it no capabilites or all of them. 如果我没有设置功能或全部功能,则应用程序会打开/ proc // uid_map进行编写。

When I set only set_capuid,set_capgid and optionally cap_sys_admin the call to open(2) fails: 当我仅设置set_capuid,set_capgid和可选的cap_sys_admin时,对open(2)的调用失败:

Set caps: 设置上限:

arksnote linux-namespaces   # setcap 'cap_setuid,cap_setgid,cap_sys_admin=epi' ./user-ns-ex
arksnote linux-namespaces   # getcap ./user-ns-ex
./user-ns-ex = cap_setgid,cap_setuid,cap_sys_admin+eip

Try to run: 尝试运行:

kamyshev@arksnote ~/workspace/personal/linux-kernel/linux-namespaces  $ ./user-ns-ex -v -U -M '0 1000 1' bash
./user-ns-ex: PID of child created by clone() is 19666
ERROR: open /proc/19666/uid_map: Permission denied
About to exec bash

And now a successfull case: 现在是一个成功的案例:

No capabilities: 无功能:

arksnote linux-namespaces   # setcap '=' ./user-ns-ex
arksnote linux-namespaces   # getcap ./user-ns-ex
./user-ns-ex =

Runs Ok: 运行正常:

 kamyshev@arksnote ~/workspace/personal/linux-kernel/linux-namespaces  $ ./user-ns-ex -v -U -M '0 1000 1' bash
./user-ns-ex: PID of child created by clone() is 19557
About to exec bash
arksnote linux-namespaces   # exit

I've been trying to find the reason in man-pages and playing with different capabilities but with no luck as of this moment. 我一直在尝试在手册页中查找原因,并尝试使用不同的功能,但到目前为止没有运气。 What puzzles me the most, is that the application runs with less capabilities and does not with more. 最让我困惑的是,该应用程序运行时功能较少,而运行时功能却不足。

Can someone help me and clarify the issue? 有人可以帮我解决这个问题吗?

The research 这项研究

I have found the reason. 我找到了原因。 During my reasearch I have found that uid_map file is not open because its ownership is changed to root . 在我的reasearch中,我发现uid_map文件未打开,因为其所有权已更改为root

Unprivileged process, no capabilities: 无特权的流程,无功能:

parent(m): capabilities: '='
parent(m): file /proc/4644/uid_map owner uid: 1000
parent(m): file /proc/4644/uid_map owner gid: 1000

Unprivileged process, capabilities are set (cap_setuid=pe): 非特权进程,功能已设置(cap_setuid = pe):

parent(m): capabilities: '= cap_setuid+ep'
parent(m): file /proc/4644/uid_map owner uid: 0
parent(m): file /proc/4644/uid_map owner gid: 0
ERROR: open /proc/4668/uid_map: Permission denied

The following research has led me to this topic: what causes proc pid resources to become owned by root? 以下研究使我想到了这个话题: 是什么原因导致proc pid资源由root拥有?

The rules on "dumpable" flag “可倾销”标志的规则

This is what happens: 这是发生了什么:

1) When a process is not dumpable, its /proc/<pid> inodes are given a root ownership: 1)当进程不可转储时,其/proc/<pid>索引节点被赋予根所有权:

// linux/base.c

struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task)
...
        if (task_dumpable(task)) {
                rcu_read_lock();
                cred = __task_cred(task);
                inode->i_uid = cred->euid;
                inode->i_gid = cred->egid;
                rcu_read_unlock();
        }

2) The process is dumpable only when its "dumpable" attribute has a value 1 (SUID_DUMP_USER). 2)仅当其“ dumpable”属性的值为1(SUID_DUMP_USER)时,该过程才可转储。 See ptrace(2) . 参见ptrace(2)

3) prctl(2) clears the situation further: 3) prctl(2)进一步清除了这种情况:

  Normally, this flag is set to 1. However, it is reset to the current value contained in the file /proc/sys/fs/suid_dumpable (which by default has the value 0), in the following circumstances: * The process's effective user or group ID is changed. * The process's filesystem user or group ID is changed (see credentials(7)). * The process executes (execve(2)) a set-user-ID or set- group-ID program, resulting in a change of either the effective user ID or the effective group ID. * The process executes (execve(2)) a program that has file capabilities (see capabilities(7)), but only if the permitted capabilities gained exceed those already permitted for the process. 

Thus my problem arose from the last of the above rules: 因此,我的问题来自上述规则的最后一个:

int commit_creds(struct cred *new)
<...> 
    /* dumpability changes */
    if (!uid_eq(old->euid, new->euid) ||
        !gid_eq(old->egid, new->egid) ||
        !uid_eq(old->fsuid, new->fsuid) ||
        !gid_eq(old->fsgid, new->fsgid) ||
        !cred_cap_issubset(old, new)) {
            if (task->mm)
                    set_dumpable(task->mm, suid_dumpable);

Fixes 修正

There are a number of ways to overcome the issue: 有多种方法可以解决此问题:

  1. Globally change /proc/sys/fs/suid_dumpable : 全局更改/proc/sys/fs/suid_dumpable

echo 1 > /proc/sys/fs/suid_dumpable

  1. Set "dumpable" flag just for the process: 仅为该过程设置“ dumpable”标志:

prctl(PR_SET_DUMPABLE, 1, 0, 0, 0)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM