init: correctly handle unmapped stdio with multiple mappings

Previously we would handle the "unmapped stdio" case by just doing a
simple check, however this didn't handle cases where the overflow_uid
was actually mapped in the user namespace. Instead of doing some
userspace checks, just try to do the fchown(2) and ignore EINVAL
(unmapped) or EPERM (lacking privilege over inode) errors.

Signed-off-by: Aleksa Sarai <asarai@suse.de>
This commit is contained in:
Aleksa Sarai 2017-10-25 00:10:35 +11:00
parent 74a1729647
commit ff5075c33f
No known key found for this signature in database
GPG Key ID: 9E18AA267DDB8DB4
1 changed files with 9 additions and 8 deletions

View File

@ -348,14 +348,6 @@ func fixStdioPermissions(config *initConfig, u *user.ExecUser) error {
continue continue
} }
// Skip chown if s.Gid is actually an unmapped gid in the host. While
// this is a bit dodgy if it just so happens that the console _is_
// owned by overflow_gid, there's no way for us to disambiguate this as
// a userspace program.
if _, err := config.Config.HostGID(int(s.Gid)); err != nil {
continue
}
// We only change the uid owner (as it is possible for the mount to // We only change the uid owner (as it is possible for the mount to
// prefer a different gid, and there's no reason for us to change it). // prefer a different gid, and there's no reason for us to change it).
// The reason why we don't just leave the default uid=X mount setup is // The reason why we don't just leave the default uid=X mount setup is
@ -363,6 +355,15 @@ func fixStdioPermissions(config *initConfig, u *user.ExecUser) error {
// this code, you couldn't effectively run as a non-root user inside a // this code, you couldn't effectively run as a non-root user inside a
// container and also have a console set up. // container and also have a console set up.
if err := unix.Fchown(int(fd), u.Uid, int(s.Gid)); err != nil { if err := unix.Fchown(int(fd), u.Uid, int(s.Gid)); err != nil {
// If we've hit an EINVAL then s.Gid isn't mapped in the user
// namespace. If we've hit an EPERM then the inode's current owner
// is not mapped in our user namespace (in particular,
// privileged_wrt_inode_uidgid() has failed). In either case, we
// are in a configuration where it's better for us to just not
// touch the stdio rather than bail at this point.
if err == unix.EINVAL || err == unix.EPERM {
continue
}
return err return err
} }
} }