Skip to content

Group-readable host files rejected in sandbox: gid unmapped, setgroups denied, and the owner display misdirects #13

Description

@sshine

Summary

A host file that is group-readable to a group the invoking user belongs to cannot be read inside the
sandbox, and --ro-binding it explicitly does not help. The file lists as nobody:nogroup, which
reads as a failed mount or changed ownership, so the obvious next moves — re-check the mount, re-check
the host permissions, reboot — all investigate the wrong thing.

Concretely: a service credential at /etc/foo/credentials.yaml, mode 0640, owner root:foo, with
the user a member of foo. Readable outside, EACCES inside.

Root cause

  • The user namespace maps exactly one uid and one gid, each of length 1 — the invoking user's.
    Every other host id, including gid foo, is unmapped.

    $ cat /proc/self/uid_map /proc/self/gid_map
          1000          0          1
           100          0          1
    
  • stat() has no in-namespace number for an unmapped owner, so it reports
    /proc/sys/kernel/overflowuid and overflowgid — both 65534, which resolve by name to
    nobody and nogroup. The display is purely cosmetic, but it is indistinguishable from a real
    ownership problem.

  • /proc/self/setgroups is deny, so supplementary groups cannot be acquired in the namespace.
    id -G returns only the mapped gid and the overflow gid, so the user's real membership of foo
    is unusable for permission checks.

  • --ro on the file changes where the inode is visible, not the ids it carries, and the access
    check uses the real ids. So an explicit bind looks like it should fix this and cannot.

  • /etc/group is visible and getent group foo correctly lists the user as a member. Everything
    therefore looks correctly configured from inside the sandbox, which is what makes the
    misdiagnosis stick.

Same unmapped-id mechanism as

but for group membership rather than root-owned files. There the failure was a loud error naming the
file; here it is a bare EACCES behind an owner display that points elsewhere.

Evidence

/etc/foo/credentials.yaml, mode 0640, owner root:foo, user in group foo:

Condition ls -l shows read
outside sandbox root foo ok
in sandbox, no extra mount nobody nogroup EACCES
in sandbox, --ro /etc/foo/credentials.yaml nobody nogroup EACCES

The owner display is identical in both failing cases and gives no hint that the cause is the gid map
rather than the mount.

Not verified, and stated as prediction rather than evidence: mode 0644 on the host file, or a copy
owned by the invoking uid, should both read fine — the first via the other bits, the second via the
one mapped uid. That follows from the permission model above but was not run before the sandbox in
question was gone.

Fix directions

Tightest first:

  • Warn when a path given to --ro/--rw is not readable with the sandboxed credentials. Cheap,
    no privilege needed, and it turns a silent EACCES plus a misleading owner into a pointer at the
    actual cause. This alone would have been sufficient here.
  • Document that group-based access does not survive the namespace: only the invoking uid and the
    other bits work. Worth stating next to --ro/--rw, since binding a path is exactly the moment
    the assumption gets made.
  • An --allow-groups flag mapping the invoking user's supplementary gids into the namespace, to fit
    the existing --allow-* taxonomy. Note this needs setgroups not to be deny and a wider
    gid_map, which may not be reachable unprivileged — worth confirming before promising it.
  • Map a uid/gid range so host ids read as themselves. Broadest, and the same trade-off as the third
    option in ssh fails in sandbox: root-owned /etc/ssh/ssh_config rejected under unmapped-uid userns #6.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions