问题描述
内核版本
[root@localhost ~]# uname -a
Linux localhost.localdomain 4.18.0-240.1.1.el8_3.x86_64 #1 SMP Thu Nov 19 17:20:08 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
unshare
- fork before launching bash
- map current user to root
- unshare user namespace
[root@localhost ~]# unshare -fru /bin/bash
[root@localhost ~]# id
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
命令执行
[root@localhost ~]# chown nginx:root a
chown: changing ownership of 'a': Invalid argument
[root@localhost ~]# cat /etc/passwd
....
nginx:x:1001:1001::/home/nginx:/bin/bash
....
[root@localhost ~]# chown 1001:1001 a
chown: changing ownership of 'a': Invalid argument
权限
[root@localhost ~]# cat /proc/$$/status | egrep 'Cap(Inh|Prm|Eff)'
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
[root@localhost ~]# capsh --decode=0000003fffffffff
0x0000003fffffffff=cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read
已经将当前 root 用户 map 到 user namespace 中,并且拥有
cap_chown 权限。
期待解决问题
为什么 Chown 会失败?
如何修改才能正确执行 chown 命令呢?
这个是 uid、gid 映射问题。
现在命名空间内的 uid 0 映射到根命名空间 uid 0:
Child Namespace Root Namespace
process uid = 0 ---> process uid = 0 # 容器内的 uid = 0 对应宿主 uid = 0
file owner = 0 <--- file owner = 0 # 宿主的文件所有者 owner = 0,映射到容器 owner = 0,自己的文件还是自己的文件
file owner = ??? <--- file owner = 1000 # 宿主的文件所有者 owner = 1000, 映射到容器 owner 是 什么?
前两个很好理解,都是直接映射,但是第 3 个就有问题了,如果你在命名空间内 ls 一下,发现除了自己的文件都变成了 nobody。因为 unshare
的时候定义了一个 uid 映射,只把 0 映射到 0,没有映射其他 uid:
# unshare -fru /bin/bash
# cat /proc/self/uid_map
0 0 1
所以文件所以者的 uid 映射有问题,chown 的时候反向映射 uid 也有问题。
解决方法是自己定义 uid 映射:
先在第一个 shell unshare,拿到进程 id
# unshare -fR /bin/bash
# echo $$
16699
然后再另一个 shell 写入映射:
# echo '0 0 10000' > /proc/16699/gid_map
# echo '0 0 10000' > /proc/16699/uid_map
然后第一个 shell 里就能正常 chown 了。