capabilities: prevent by-passing lack of CAP_SETFCAP (v4)

Current, a process running as uid 0 but without cap_setfcap can
unshare a new user namespace with uid 0 mapped to 0.  While this task
will not have new capabilities against the parent namespace, there is
a loophole due to the way namespaced file capabilities work.  File
capabilities valid in userns 1 are distinguised from file capabilities
valid in userns 2 by the kuid which underlies uid 0.  Therefore
the restricted root process can unshare a new self-mapping namespace,
add a namespaced file capability onto a file, then use that file
capability in the parent namespace.

To prevent that, mark a namespace which should not be allowed to
create file capabilities, and honor that when creating fscaps.

When a task creates a user namespace, mark in the child whether
the parent had cap_setfcap.

When a user namespace gets its uid 0 mapped, check whether that
uid 0 is shared with uid 0 for any ancestors.  If so, verify
that that ancestor had cap_setfcap when it created its immediate
child.  If not, then mark the new namespace as !may_setfcap.
When creating a namespaced file capability, refuse if may_setfcap
is false.

With this patch:

1. unprivileged user can still unshare -Ur

ubuntu@caps:~$ unshare -Ur
root@caps:~# logout

2. root user can still unshare -Ur

ubuntu@caps:~$ sudo bash
root@caps:/home/ubuntu# unshare -Ur
root@caps:/home/ubuntu# logout

3. root user without CAP_SETFCAP cannot unshare -Ur:

root@caps:/home/ubuntu# /sbin/capsh --drop=cap_setfcap --
root@caps:/home/ubuntu# /sbin/setcap cap_setfcap=p /sbin/setcap
unable to set CAP_SETFCAP effective capability: Operation not permitted
root@caps:/home/ubuntu# unshare -Ur
unshare: write failed /proc/self/uid_map: Operation not permitted

Signed-off-by: Serge Hallyn <serge@hallyn.com>
4 files changed