LXD: file capabilities/discretionary access control are not working in unprivileged setups and do work in privileged

Hello,

I am running gentoo in an unpriviledged container and this is what I am getting when installing software using portage.

 * ERROR: sys-libs/pam-1.3.0-r2::core-kit failed (postinst phase):
 *   Checking caps 'cap_dac_override=ep' on '/sbin/unix_chkpwd' failed             
 *                                                                
 * Call stack:                                                    
 *     ebuild.sh, line  121:  Called pkg_postinst                 
 *   environment, line 3471:  Called fcaps 'cap_dac_override' 'sbin/unix_chkpwd'   
 *   environment, line 1723:  Called die                          
 * The specific snippet of code:                                  
 *                       ${cmd}_verify || die "Checking caps '${caps}' on '${file}' failed";                                                                                     
 *                                                                
 * If you need support, post the output of `emerge --info '=sys-libs/pam-1.3.0-r2::core-kit'`,                                                                                   
 * the complete build log and the output of `emerge -pqv '=sys-libs/pam-1.3.0-r2::core-kit'`.                                                                                    
 * The complete build log is located at '/var/tmp/portage/sys-libs/pam-1.3.0-r2/temp/build.log'.                                                                                 
 * The ebuild environment file is located at '/var/tmp/portage/sys-libs/pam-1.3.0-r2/temp/environment'.                                                                          
 * Working directory: '/var/tmp/portage/sys-libs/pam-1.3.0-r2/homedir'             
 * S: '/var/tmp/portage/sys-libs/pam-1.3.0-r2/work/Linux-PAM-1.3.0'                
 * FAILED postinst: 1                           

this is inside the same container:

fun-gnome26-test ~ # capsh --print
Current: = 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_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,"cap_setfcap",cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read+ep
Bounding set =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_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read
Securebits: 00/0x0/1'b0           
 secure-noroot: no (unlocked)     
 secure-no-suid-fixup: no (unlocked)                                                                
 secure-keep-caps: no (unlocked)  
uid=0(root)                       
gid=0(root)                       
groups=                           

Is this expected? What capabilities are dropped in unprivileged mode?

Thank you for clarifying.

Pavol

adding strace from unprivileged container:

execve("/usr/bin/filecap", ["filecap", "/sbin/unix_chkpwd"], 0x7ffc05793138 /* 28 vars */) = 0
brk(NULL)                               = 0x603000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 4
fstat(4, {st_mode=S_IFREG|0644, st_size=161994, ...}) = 0
mmap(NULL, 161994, PROT_READ, MAP_PRIVATE, 4, 0) = 0x7f50705c0000
close(4)                                = 0
openat(AT_FDCWD, "/usr/lib64/libcap-ng.so.0", O_RDONLY|O_CLOEXEC) = 4
read(4, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340\24\0\0\0\0\0\0@\0\0\0\0\0\0\0HB\0\0\0\0\0\0\0\0\0\0@\0008\0\7\0@\0\32\0\31\0\1\0\0\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0T=\0\0\0\0\0\0T=\0\0\0\0\0\0\0\0 \0\0\0\0\0\1\0\0\0\6\0\0\0\240=\0\0\0\0\0\0\240= \0\0\0\0\0\240= \0\0\0\0\0\324\3\0\0\0\0\0\0\330\3\0\0\0\0\0\0\0\0 \0\0\0\0\0\2\0\0\0\6\0\0\0\350=\0\0\0\0\0\0\350= \0\0\0\0\0\350= \0\0\0\0\0\340\1\0\0\0\0\0\0\340\1\0\0\0\0\0\0\10\0\0\0\0\0\0\0\7\0\0\0\4\0\0\0\240=\0\0\0\0\0\0\240= \0\0\0\0\0\240= \0\0\0\0\0000\0\0\0\0\0\0\0000\0\0\0\0\0\0\0\4\0\0\0\0\0\0\0P\345td\4\0\0\0(7\0\0\0\0\0\0(7\0\0\0\0\0\0(7\0\0\0\0\0\0\274\0\0\0\0\0\0\0\274\0\0\0\0\0\0\0\4\0\0\0\0\0\0\0Q\345td\6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0R\345td\4\0\0\0\240=\0\0\0\0\0\0\240= \0\0\0\0\0\240= \0\0\0\0\0`\2\0\0\0\0\0\0`\2\0\0\0\0\0\0\1\0\0\0\0\0\0\0)\0\0\0'\0\0\0\4\0\0\0\10\0\0\0D\20\24@\0\4L\224(\0B\200\0\20\22\2\20 \t\22\10\1@\r\0@\36\221\4\4\2\0\0\0\0\0'\0\0\0\0\0\0\0)\0\0\0\0\0\0\0\0\0\0\0+\0\0\0\0\0\0\0\0\0\0\0,\0\0\0\0\0\0\0\0\0\0\0-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0.\0\0\0/\0\0\0\0\0\0\0000\0\0\0001\0\0\0\0\0\0\0\0\0\0\0002\0\0\0003\0\0\0004\0\0\0005\0\0\0006\0\0\0\0\0\0\0007\0\0\0\0\0\0\0008\0\0\0009\0\0\0\0\0\0\0\0\0\0\0;\0\0\0\0\0\0\0<\0\0\0\0\0\0\0=\0\0\0\0\0\0\0002\352b^\323\"~\257BE\325\354\267\234uP\271\215\361\16\205\323\346\4\7\314s\205\331qX\34\273\343\222|\273\350\221\207\3\272\32\360\353\323\357\16u\271\204^\335T\237\251Ql\347\\q\26\365\222\221\231`Y3\36\312m\336\23AU=\22\205DQ\237wa\25:rP\320\316\246\3757?\370S\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\354\0\0\0\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0k\2\0\0\22\0\0\0\0\0\0\0\0\0\0\0", 832) = 832
fstat(4, {st_mode=S_IFREG|0755, st_size=18632, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f50705be000
mmap(NULL, 2113912, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 4, 0) = 0x7f50701bf000
mprotect(0x7f50701c3000, 2093056, PROT_NONE) = 0
mmap(0x7f50703c2000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0x3000) = 0x7f50703c2000
close(4)                                = 0
openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 4
read(4, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\20\2\0\0\0\0\0@\0\0\0\0\0\0\0\340\5\34\0\0\0\0\0\0\0\0\0@\0008\0\n\0@\0D\0C\0\6\0\0\0\5\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0000\2\0\0\0\0\0\0000\2\0\0\0\0\0\0\10\0\0\0\0\0\0\0\3\0\0\0\4\0\0\0\360\37\31\0\0\0\0\0\360\37\31\0\0\0\0\0\360\37\31\0\0\0\0\0\34\0\0\0\0\0\0\0\34\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\373\246\33\0\0\0\0\0\373\246\33\0\0\0\0\0\0\0 \0\0\0\0\0\1\0\0\0\6\0\0\0\240\247\33\0\0\0\0\0\240\247;\0\0\0\0\0\240\247;\0\0\0\0\0\200P\0\0\0\0\0\0\10\222\0\0\0\0\0\0\0\0 \0\0\0\0\0\2\0\0\0\6\0\0\0`\333\33\0\0\0\0\0`\333;\0\0\0\0\0`\333;\0\0\0\0\0\340\1\0\0\0\0\0\0\340\1\0\0\0\0\0\0\10\0\0\0\0\0\0\0\4\0\0\0\4\0\0\0p\2\0\0\0\0\0\0p\2\0\0\0\0\0\0p\2\0\0\0\0\0\0 \0\0\0\0\0\0\0 \0\0\0\0\0\0\0\4\0\0\0\0\0\0\0\7\0\0\0\4\0\0\0\240\247\33\0\0\0\0\0\240\247;\0\0\0\0\0\240\247;\0\0\0\0\0\20\0\0\0\0\0\0\0\220\0\0\0\0\0\0\0\10\0\0\0\0\0\0\0P\345td\4\0\0\0\f \31\0\0\0\0\0\f \31\0\0\0\0\0\f \31\0\0\0\0\0\354\\\0\0\0\0\0\0\354\\\0\0\0\0\0\0\4\0\0\0\0\0\0\0Q\345td\6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0R\345td\4\0\0\0\240\247\33\0\0\0\0\0\240\247;\0\0\0\0\0\240\247;\0\0\0\0\0`8\0\0\0\0\0\0`8\0\0\0\0\0\0\1\0\0\0\0\0\0\0\4\0\0\0\20\0\0\0\1\0\0\0GNU\0\0\0\0\0\3\0\0\0\2\0\0\0\0\0\0\0\363\3\0\0\t\0\0\0\0\1\0\0\16\0\0\0\0000\20D\240 \2\1\210\3\346\220\305E\214\0\304\0\30\0\7\204\0`\302\200\0\r\212\fA\4\20\0\210@2\10*@\210T<, \0162H&\204\300\214\4\10\0\2\2\16\241\254\32\4f\300\0\3002\0\300\0P\1 \201\10\204\v  ($\0\4 Z\0\20X\200\312DB(\0\6\200\0208C\0 @\200\0IP\0Q\212@\22\0\0\0\0\10\0\0\21\20@\210@\200\265\0!\310B\301\203\240\331\244X\2\10\4\20@\7\20\4\2\220@\"\0 \32\20\2\31\4F&\0\1\240\252", 832) = 832
fstat(4, {st_mode=S_IFREG|0755, st_size=1840864, ...}) = 0
mmap(NULL, 3946920, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 4, 0) = 0x7f506fdfb000
mprotect(0x7f506ffb6000, 2093056, PROT_NONE) = 0
mmap(0x7f50701b5000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0x1ba000) = 0x7f50701b5000
mmap(0x7f50701bb000, 14760, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f50701bb000
close(4)                                = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f50705bb000
arch_prctl(ARCH_SET_FS, 0x7f50705bb740) = 0
mprotect(0x7f50701b5000, 16384, PROT_READ) = 0
mprotect(0x7f50703c2000, 4096, PROT_READ) = 0
mprotect(0x601000, 4096, PROT_READ)     = 0
mprotect(0x7f50705e8000, 4096, PROT_READ) = 0
munmap(0x7f50705c0000, 161994)          = 0
lstat("/sbin/unix_chkpwd", {st_mode=S_IFREG|0711, st_size=31176, ...}) = 0
capget({version=0 /* _LINUX_CAPABILITY_VERSION_??? */, pid=0}, NULL) = 0
gettid()                                = 23651
openat(AT_FDCWD, "/proc/sys/kernel/cap_last_cap", O_RDONLY) = 4
read(4, "37\n", 7)                      = 3
close(4)                                = 0
openat(AT_FDCWD, "/sbin/unix_chkpwd", O_RDONLY|O_CLOEXEC) = 4
fgetxattr(4, "security.capability", 0x7fffc4db3b10, 20) = -1 ERANGE (Numerical result out of range)
close(4)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

It’s expected on everything but the most recent kernels as unprivileged users weren’t allowed to set filesystem capabilities.

Our very own @hallyn did the kernel work needed for this a while back and it’s been included in Linus’ tree for a few months now:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=8db6c34f1dbc8e06aa016a9b829b06902c3e1340

Kernels 4.14 and higher should have it included out of the box.

OK. This is on 4.14.12 kernel. I am going to check if I have that patch

Yes the patch is there. Why should it fail then?

@hallyn, could you comment on this please? or anyone else?

Hi,

It would be very helpful if you could start a container, install capsh, copy it to ~/ (in the container) as an unpriv user, then do the equivalent of

sudo setcap cap_sys_admin=pe capsh
./capsh --print
attr -S -l capsh

and for each attribute it shows, i.e. ‘capability’, do

attr -Sg capability capsh

Oh and what filesystem are you using for your container?

If ZFS, extended attributes have to be manually enabled in the zpool with zfs set xattr=sa ZPOOL.

1 Like

@stgraber using btrfs filesystem

@hallyn

palica@fun-capabilities ~ $ sudo cp /sbin/capsh .
palica@fun-capabilities ~ $ ls
capsh
palica@fun-capabilities ~ $ sudo setcap cap_sys_admin=pe capsh
palica@fun-capabilities ~ $ ./capsh --print
Current: = cap_sys_admin+ep
Bounding set =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_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read
Securebits: 00/0x0/1'b0
 secure-noroot: no (unlocked)
 secure-no-suid-fixup: no (unlocked)
 secure-keep-caps: no (unlocked)
uid=1000(palica)
gid=1000(palica)
groups=10(wheel),1000(palica)
palica@fun-capabilities ~ $ attr -S -l capsh
Attribute "capability" has a 24 byte value for capsh
palica@fun-capabilities ~ $ attr -Sg capability capsh
Attribute "capability" had a 24 byte value for capsh:
 
palica@fun-capabilities ~ $ 

Is this info good enough?

Thanks - so just to be sure, that’s inside the unprivileged container right?
It’s definately working. For fun you could do the same ‘attr’ commands on the files (either find the actual rootfs, or use /proc/$initpid/root/home/palica/capsh). You should find different name and value for the xattr there.
But so I don’t know why the package install is failing. I’ll have to try to reproduce. Please ping me here if I haven’t done so by tomorrow.
Oh can you show the exact command I should use/ “emerge pam” enough?

Yes, this is an unprivileged container.

Yes a simple emerge pam should be enough. @hallyn

emerge -av pam

These are the packages that would be merged, in order:

Calculating dependencies... done!
[ebuild   R    ] sys-libs/pam-1.3.0-r2::core-kit  USE="berkdb cracklib filecaps nls pie -audit -debug -nis (-selinux) {-test} -vim-syntax" ABI_X86="(64) -32 (-x32)" 0 KiB

the filecaps useflag is responsible for the filecaps settings at install.

Thank you for all the help @stgraber and @hallyn .

hi,

so I just tried this in a gentoo container on a fresh ubuntu artful VM, did USE=filecaps emerge -av pam. Succeeded, and afterward:

gentoo ~ # getcap /sbin/unix_chkpwd
/sbin/unix_chkpwd = cap_dac_override+ep
gentoo ~ # cat /proc/self/uid_map
0 100000 65536

I would say your kernel patch backport may be bad, but your test with capsh showed it working
 so that’s confusing. What is your kernel version, and where is the source?

this is what I am getting:

fun-capabilities ~ # getcap /sbin/unix_chkpwd
Failed to get capabilities of file `/sbin/unix_chkpwd' (Numerical result out of range)
fun-capabilities ~ # cat /proc/self/uid_map
         0     100000 1000000000

kernel 4.14.12

source: https://salsa.debian.org/kernel-team/linux/tree/debian/4.14.12-2/debian

@hallyn, what kernel are you using please? I would test with your kernel maybe?

Hi,

Linux gentoo 4.13.0-37-generic #42-Ubuntu SMP Wed Mar 7 14:13:23 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

It was a standard ubuntu artful VM created with uvt-kvm.

Seems that it was the kernel that was somehow influencing the filecaps. Can be closed. Thanks for support.