shadow/libmisc
Christian Brauner 52c081b02c
new{g,u}idmap: align setuid and fscaps behavior
Commit 1ecca8439d ("new[ug]idmap: not require CAP_SYS_ADMIN in the parent userNS")
does contain a wrong commit message, is lacking an explanation of the
issue, misses some simplifications and hardening features. This commit
tries to rectify this.

In (crazy) environment where all capabilities are dropped from the
capability bounding set apart from CAP_SET{G,U}ID setuid- and
fscaps-based new{g,u}idmap binaries behave differently when writing
complex mappings for an unprivileged user:

1. newuidmap is setuid

unshare -U sleep infinity &
newuidmap $? 0 100000 65536

First file_ns_capable(file, ns, CAP_SYS_ADMIN) is hit. This calls into
cap_capable() and hits the loop

for (;;) {
        /* Do we have the necessary capabilities? */
        if (ns == cred->user_ns)
                return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;

        /*
         * If we're already at a lower level than we're looking for,
         * we're done searching.
         */
        if (ns->level <= cred->user_ns->level)
                return -EPERM;

        /*
         * The owner of the user namespace in the parent of the
         * user namespace has all caps.
        */
        if ((ns->parent == cred->user_ns) && uid_eq(ns->owner, cred->euid))
                return 0;

        /*
         * If you have a capability in a parent user ns, then you have
         * it over all children user namespaces as well.
        */
        ns = ns->parent;
}

The first check fails and falls through to the end of the loop and
retrieves the parent user namespace and checks whether CAP_SYS_ADMIN is
available there which isn't.

2. newuidmap has CAP_SETUID as fscaps set

unshare -U sleep infinity &
newuidmap $? 0 100000 65536

The first file_ns_capable() check for CAP_SYS_ADMIN is passed since the
euid has not been changed:

if ((ns->parent == cred->user_ns) && uid_eq(ns->owner, cred->euid))
        return 0;

Now new_idmap_permitted() is hit which calls ns_capable(ns->parent,
CAP_SET{G,U}ID). This check passes since CAP_SET{G,U}ID is available in
the parent user namespace.
Now file_ns_capable(file, ns->parent, CAP_SETUID) is hit and the
cap_capable() loop (see above) is entered again. This passes

if (ns == cred->user_ns)
        return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;

since CAP_SET{G,U}ID is available in the parent user namespace. Now the
mapping can be written.

There is no need for this descrepancy between setuid and fscaps based
new{g,u}idmap binaries. The solution is to do a
seteuid() back to the unprivileged uid and PR_SET_KEEPCAPS to keep
CAP_SET{G,U}ID. The seteuid() will cause the
file_ns_capable(file, ns, CAP_SYS_ADMIN) check to pass and the
PR_SET_KEEPCAPS for CAP_SET{G,U}ID will cause the CAP_SET{G,U}ID to
pass.

Fixes: 1ecca8439d ("new[ug]idmap: not require CAP_SYS_ADMIN in the parent userNS")
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
2018-10-28 01:27:48 +02:00
..
.indent.pro Commit the last version from the PLD CVS repository. 2007-10-07 14:36:51 +00:00
addgrps.c * NEWS, libmisc/addgrps.c: Fix allocator loop. Continue to 2011-06-02 15:36:29 +00:00
age.c * libmisc/env.c, libmisc/age.c: Added splint annotations. 2009-04-23 17:33:21 +00:00
audit_help.c * libmisc/audit_help.c (audit_logger):pgname is not used. We let 2010-08-21 15:22:39 +00:00
basename.c Miscellaneous: 2011-09-18 21:02:43 +00:00
chkname.c * libmisc/chkname.c: Do not include <utmp.h> and <utmpx.h>. There 2009-04-28 19:14:05 +00:00
chkname.h Updated copyright dates. 2008-05-25 23:31:10 +00:00
chowndir.c * libmisc/chowndir.c: Add splint annotations. 2011-08-14 14:00:14 +00:00
chowntty.c * libmisc/limits.c: Avoid implicit conversion of integer to 2010-08-22 19:13:53 +00:00
cleanup_group.c * libmisc/cleanup_group.c: Fix compilation when compiled without 2008-12-23 00:39:54 +00:00
cleanup_user.c * libmisc/audit_help.c: Added audit_logger_message() to log 2008-12-22 21:52:43 +00:00
cleanup.c * lib/prototypes.h, libmisc/cleanup.c, lib/spawn.c, src/chage.c: 2011-10-18 20:23:33 +00:00
console.c Fix some issues found in Coverity scan. 2018-10-10 12:22:04 +02:00
copydir.c 2012-02-13 Mike Frysinger <vapier@gentoo.org> 2012-02-13 19:16:29 +00:00
entry.c Make sure every source files are distributed with a copyright and license. 2008-04-27 00:40:09 +00:00
env.c * libmisc/isexpired.c: Added parenthesis. 2011-06-16 21:25:36 +00:00
failure.c * libmisc/limits.c: Avoid implicit conversion of integer to 2010-08-22 19:13:53 +00:00
failure.h spelling: cumulative 2017-10-22 18:33:13 +00:00
find_new_gid.c add --prefix option 2017-03-01 22:51:09 +01:00
find_new_sub_gids.c Tweak uid/gid map default configuration 2016-02-15 18:11:10 -05:00
find_new_sub_uids.c Tweak uid/gid map default configuration 2016-02-15 18:11:10 -05:00
find_new_uid.c add --prefix option 2017-03-01 22:51:09 +01:00
getdate.h * libmisc/limits.c: Avoid implicit conversion of integer to 2010-08-22 19:13:53 +00:00
getdate.y spelling: gratuitously 2017-10-22 19:17:02 +00:00
getgr_nam_gid.c * lib/prototypes.h, libmisc/getgr_nam_gid.c: getgr_nam_gid() 2011-08-14 13:16:26 +00:00
getrange.c * libmisc/get_gid.c, libmisc/get_uid.c, libmisc/Makefile.am, 2009-03-08 20:26:56 +00:00
gettime.c Make the sp_lstchg shadow field reproducible. 2017-04-10 22:29:21 +01:00
hushed.c * libmisc/limits.c: Avoid implicit conversion of integer to 2010-08-22 19:13:53 +00:00
idmapping.c new{g,u}idmap: align setuid and fscaps behavior 2018-10-28 01:27:48 +02:00
idmapping.h new{g,u}idmap: align setuid and fscaps behavior 2018-10-28 01:27:48 +02:00
isexpired.c * libmisc/isexpired.c: Added parenthesis. 2011-06-16 21:25:36 +00:00
limits.c * man/limits.5.xml, libmisc/limits.c: Sort limit identifiers. 2011-11-06 18:39:47 +00:00
list.c * libmisc/console.c, libmisc/motd.c, libmisc/setupenv.c, 2010-08-21 15:32:53 +00:00
log.c * lib/prototypes.h: Replace HAVE_UTMPX_H by USE_UTMPX. 2009-04-27 20:15:09 +00:00
loginprompt.c * libmisc/salt.c (SHA_salt_rounds): It is statically ensured that 2011-09-18 20:41:38 +00:00
mail.c * libmisc/mail.c, libmisc/copydir.c: Added missing include of 2009-04-27 20:09:18 +00:00
Makefile.am Merge remote-tracking branch 'upstream/master' 2018-03-28 21:11:36 +02:00
motd.c * libmisc/console.c, libmisc/motd.c, libmisc/setupenv.c, 2010-08-21 15:32:53 +00:00
myname.c * libmisc/myname.c: Updated splint annotations. 2009-04-26 17:10:49 +00:00
obscure.c * libmisc/limits.c: Avoid implicit conversion of integer to 2010-08-22 19:13:53 +00:00
pam_pass_non_interactive.c spelling: interactive 2017-10-22 20:24:32 +00:00
pam_pass.c * libmisc/pam_pass.c: Removed comment regarding pam_misc. This is 2009-05-09 13:15:17 +00:00
prefix_flag.c fix unguarded ENABLE_SUBIDS code 2018-06-18 15:51:27 +02:00
pwd_init.c Make sure every source files are distributed with a copyright and license. 2008-04-27 00:40:09 +00:00
pwd2spwd.c * lib/prototypes.h, libmisc/addgrps.c: restrict add_groups() to 2009-04-05 22:29:42 +00:00
pwdcheck.c * libmisc/pwdcheck.c (passwd_check): The progname is not used. 2009-04-23 20:17:02 +00:00
remove_tree.c Integrate review comments from Julien Cristau 2010-09-05 15:34:42 +00:00
rlogin.c * lib/exitcodes.h: Define E_SUCCESS as EXIT_SUCCESS. Added FIXMEs. 2009-04-30 21:08:49 +00:00
root_flag.c use chdir() before calling chroot() 2013-07-29 11:05:16 +02:00
salt.c (shadow_random): Use long instead of size_t. 2013-08-13 19:16:24 +02:00
setugid.c Updated copyrights. 2010-08-22 13:04:54 +00:00
setupenv.c spelling: else 2017-10-22 19:08:39 +00:00
shell.c * libmisc/limits.c: Avoid implicit conversion of integer to 2010-08-22 19:13:53 +00:00
strtoday.c spelling: cumulative 2017-10-22 18:33:13 +00:00
sub.c Fix typo in comment. 2013-08-04 15:56:32 +02:00
sulog.c Updated copyrights. 2010-08-22 13:04:54 +00:00
ttytype.c * libmisc/limits.c: Avoid implicit conversion of integer to 2010-08-22 19:13:53 +00:00
tz.c Updated copyrights. 2010-08-22 13:04:54 +00:00
ulimit.c * libmisc/limits.c: Add brackets and parenthesis. 2008-06-15 21:59:41 +00:00
user_busy.c user_busy: fix missing close of subuid file on error 2017-03-23 17:07:46 -05:00
utmp.c Support systems that only have utmpx 2018-06-24 00:13:12 -05:00
valid.c crypt() in glibc/eglibc 2.17 now fails if passed 2013-07-28 18:41:11 +02:00
xgetgrgid.c * libmisc/xgetXXbyYY.c, libmisc/xgetpwnam.c, libmisc/xgetgrnam.c, 2009-06-11 21:33:00 +00:00
xgetgrnam.c * libmisc/xgetXXbyYY.c, libmisc/xgetpwnam.c, libmisc/xgetgrnam.c, 2009-06-11 21:33:00 +00:00
xgetpwnam.c * libmisc/xgetXXbyYY.c, libmisc/xgetpwnam.c, libmisc/xgetgrnam.c, 2009-06-11 21:33:00 +00:00
xgetpwuid.c * libmisc/xgetXXbyYY.c, libmisc/xgetpwnam.c, libmisc/xgetgrnam.c, 2009-06-11 21:33:00 +00:00
xgetspnam.c * libmisc/xgetXXbyYY.c, libmisc/xgetpwnam.c, libmisc/xgetgrnam.c, 2009-06-11 21:33:00 +00:00
xgetXXbyYY.c Re-indent. 2011-11-06 18:40:06 +00:00
xmalloc.c * libmisc/xmalloc.c: Harmonize message. 2011-06-02 18:41:05 +00:00
yesno.c * libmisc/yesno.c: Ignore the return value of puts. 2009-04-23 11:14:56 +00:00