weixin_39627390
weixin_39627390
2020-11-28 05:34

many: create system-usernames user/group if both don't exist

This builds on https://github.com/snapcore/snapd/pull/7111 and https://github.com/snapcore/snapd/pull/7112. The tests from https://github.com/snapcore/snapd/pull/7111 are moved here since the snap_daemon user didn't exist there and this PR can put it all together.

supportedSystemUsernames for now contains the hardcoded list of system users (and implied system group of same name) that snaps may specify. This will eventually be moved out of here into the store.

Since the snap is mounted read-only and to avoid problems associated with different systems using different uids and gids for the same user name and group name, snapd will create system-usernames where 'scope' is not 'external' (currently snapd only supports 'scope: shared') with the following characteristics:

  • uid and gid shall match for the specified system-username
  • a snapd-allocated [ug]id for a user/group name shall never change
  • snapd should avoid [ug]ids that are known to overlap with uid ranges of common use cases and user namespace container managers so that DAC and AppArmor owner match work as intended.
  • [ug]id shall be < 2^31 to avoid (at least) broken devpts kernel code
  • [ug]id shall be >= 524288 (0x00080000) to give plenty of room for large sites, default uid/gid ranges for docker (231072-296608), LXD installs that setup a default /etc/sub{uid,gid} (100000-165536) and podman whose tutorials reference setting up a specific default user and range (100000-165536)
  • [ug]id shall not be between 1,000,000 and 1,001,000,000 (ie, 1,000,000 subordinate uid with 1,000,000,000 range) to avoid overlapping with LXD's minimum and maximum id ranges. LXD allows for any id range >= 65536 and doesn't perform any [ug]id overlap detection with current users
  • [ug]ids assigned by snapd initially will fall within a 65536 (2^16) range (see below) where the first [ug]id in the range has the 16 lower bits all set to zero. This allows snapd to conveniently be bitwise aligned, follows sensible conventions (see https://systemd.io/UIDS-GIDS.html) but also potentially discoverable by systemd-nspawn (it assigns a different 65536 range to each container. Its allocation algorithm is not sequential and may choose anything within its range that isn't already allocated. It's detection algorithm includes (effectively) performing a getpwent() operation on CANDIDATE_UID & 0XFFFF0000 and selecting another range if it is assigned).

What [ug]id range(s) should snapd use?

While snapd does not employ user namespaces, it will operate on systems with container managers that do and will assign from a range of [ug]ids. It is desirable that snapd assigns [ug]ids that minimally conflict with the system and other software (potential conflicts with admin-assigned ranges in /etc/subuid and /etc/subgid cannot be avoided, but can be documented as well as detected/logged). Overlapping with container managers is non-fatal for snapd and the container, but introduces the possibility that a uid in the container matches a uid a snap is using, which is undesirable in terms of security (eg, DoS via ulimit, same ownership of files between container and snap (even if the other's files are otherwise inaccessible), etc).

snapd shall assign [ug]ids from range(s) of 65536 where the lowest value in the range has the 16 lower bits all set to zero (initially just one range, but snapd can add more as needed).

To avoid [ug]id overlaps, snapd shall only assign [ug]ids >= 524288 (0x00080000) and <= 983040 (0x000F0000, ie the first 65536 range under LXD's minimum where the lower 16 bits are all zeroes). While [ug]ids >= 1001062400 (0x3BAB0000, the first 65536 range above LXD's maximum where the lower 16 bits are all zeroes) would also avoid overlap, considering nested containers (eg, LXD snap runs a container that runs a container that runs snapd), choosing >= 1001062400 would mean that the admin would need to increase the LXD id range for these containers for snapd to be allowed to create its [ug]ids in the deeply nested containers. The requirements would both be an administrative burden and artificially limit the number of deeply nested containers the host could have.

Looking at the LSB and distribution defaults for login.defs, we can observe uids and gids in the system's initial 65536 range (ie, 0-65536):

  • 0-99 LSB-suggested statically assigned range (eg, root, daemon, etc)
  • 0 mandatory 'root' user
  • 100-499 LSB-suggested dynamically assigned range for system users (distributions often prefer a higher range, see below)
  • 500-999 typical distribution default for dynamically assigned range for system users (some distributions use a smaller SYS_[GU]ID_MIN)
  • 1000-60000 typical distribution default for dynamically assigned range for regular users
  • 65535 (-1) should not be assigned since '-1' might be evaluated as this with set[ug]id* and chown families of functions
  • 65534 (-2) nobody/nogroup user for NFS/etc [ug]id anonymous squashing
  • 65519-65533 systemd recommended reserved range for site-local anonymous additions, etc

To facilitate potential future use cases within the 65536 range snapd will assign from, snapd will only assign from the following subset of ranges relative to the range minimum (ie, its 'base' which has the lower 16 bits all set to zero):

  • 60500-60999 'scope: shared' system-usernames
  • 61000-65519 'scope: private' system-usernames

Since the first [ug]id range must be >= 524288 and <= 983040 (see above) and following the above guide for system-usernames [ug]ids within this 65536 range, the lowest 'scope: shared' user in this range is 584788 (0x0008EC54).

Since this number is within systemd-nspawn's range of 524288-1879048191 (0x00080000-0x6FFFFFFF), the number's lower 16 bits are not all zeroes so systemd-nspawn won't detect this allocation and could potentially assign the 65536 range starting at 0x00080000 to a container. snapd will therefore also create the 'snapd-range-524288-root' user and group with [ug]id 524288 to work within systemd-nspawn's collision detection. This user/group will not be assigned to snaps at this time.

In short (phew!), use the following:


$ snappy-debug.id-range 524288 # 0x00080000
Host range:              524288-589823 (00080000-0008ffff; 0-65535)
LSB static range:        524288-524387 (00080000-00080063; 0-99)
Useradd system range:    524788-525287 (000801f4-000803e7; 500-999)
Useradd regular range:   525288-584288 (000803e8-0008ea60; 1000-60000)
Snapd shared range:      584788-585287 (0008ec54-0008ee47; 60500-60999)
Snapd private range:     585288-589807 (0008ee48-0008ffef; 61000-65519)

Snapd is of course free to add more ranges (eg, 589824 (0x00090000)) with new snapd-range-<base>-root users, or to allocate differently within its 65536 range in the future (sequentially assigned [ug]ids are not required), but for now start very regimented to avoid as many problems as possible.

References: - https://forum.snapcraft.io/t/multiple-users-and-groups-in-snaps/ - https://systemd.io/UIDS-GIDS.html - https://docs.docker.com/engine/security/userns-remap/ - https://github.com/lxc/lxd/blob/master/doc/userns-idmap.md

该提问来源于开源项目:snapcore/snapd

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

10条回答

  • weixin_39627390 weixin_39627390 5月前

    Only failed test is from 7265:

    2019-08-16 16:46:17 Failed tasks: 1 - google:ubuntu-18.04-64:tests/main/user-libnss error: unsuccessful run

    Will keep merging in changes from there (or feel free to push them to here).

    点赞 评论 复制链接分享
  • weixin_39627390 weixin_39627390 5月前

    Thanks for the reviews, polishing and merge!

    点赞 评论 复制链接分享
  • weixin_39995439 weixin_39995439 5月前

    Codecov Report

    Merging #7124 into master will decrease coverage by <.01%. The diff coverage is 79.62%.

    Impacted file tree graph

    diff
    @@            Coverage Diff            @@
    ##           master   #7124      +/-   ##
    =========================================
    - Coverage   80.41%   80.4%   -0.01%     
    =========================================
      Files         630     630              
      Lines       49396   49551     +155     
    =========================================
    + Hits        39720   39842     +122     
    - Misses       6598    6617      +19     
    - Partials     3078    3092      +14
    

    | Impacted Files | Coverage Δ | | |---|---|---| | sandbox/seccomp/compiler.go | 100% <ø> (ø) | :arrow_up: | | interfaces/builtin/process_control.go | 100% <ø> (ø) | :arrow_up: | | snap/info.go | 86.49% <ø> (ø) | :arrow_up: | | interfaces/apparmor/backend.go | 82.37% <100%> (+0.12%) | :arrow_up: | | osutil/user.go | 81% <100%> (+7.02%) | :arrow_up: | | interfaces/system_key.go | 57.14% <25%> (ø) | :arrow_up: | | overlord/snapstate/check_snap.go | 79.84% <75%> (-1.56%) | :arrow_down: | | snap/info_snap_yaml.go | 94.59% <77.77%> (-2.33%) | :arrow_down: | | interfaces/seccomp/backend.go | 76.1% <80%> (+0.04%) | :arrow_up: | | overlord/patch/patch6_2.go | 74.28% <0%> (-2.86%) | :arrow_down: | | ... and 4 more | |

    Continue to review full report at Codecov.

    Legend - Click here to learn more Δ = absolute <relative> (impact), ø = not affected, ? = missing data Powered by Codecov. Last update c4d273a...f07f69e. Read the comment docs.

    点赞 评论 复制链接分享
  • weixin_39627390 weixin_39627390 5月前

    , - after you read the rationale regarding the ranges/etc in this PR, if you have questions, perhaps we can discuss in a meeting for expediency (summarizing outcomes here).

    点赞 评论 复制链接分享
  • weixin_39627390 weixin_39627390 5月前

    I noticed there is a problem with this PR wrt osutil.FindUid() and osutil.FindGid() on core since the builtin os/user functions only look at /etc/passwd and /etc/group (extrausers is configured via nsswitch.conf but we don't support being built with cgo) and we need to see if the user/group exists before creating them, otherwise on refresh/another snap is installed, groupadd will fail. The fix is straightforward: adjust FindUid()/FindGid() to call out to getent.

    点赞 评论 复制链接分享
  • weixin_39627390 weixin_39627390 5月前

    I noticed there is a problem with this PR wrt osutil.FindUid() and osutil.FindGid() on core since the builtin os/user functions only look at /etc/passwd and /etc/group (extrausers is configured via nsswitch.conf but we don't support being built with cgo) and we need to see if the user/group exists before creating them, otherwise on refresh/another snap is installed, groupadd will fail. The fix is straightforward: adjust FindUid()/FindGid() to call out to getent.

    This is now addressed.

    点赞 评论 复制链接分享
  • weixin_39627390 weixin_39627390 5月前

    and - this should be ready to review (spread tests should pass again (needed updates for new error output)) and I addressed the PR, IRC and my own feedback re core. I wasn't sure what you would prefer, so I went with two new API calls: FindUidGetent() and FindGidGetent() that only (the new in this snap_daemon PR series) EnsureUserGroup() will use to err on the side of caution and not change any existing behavior. Happy to adjust here or in a followup PR.

    点赞 评论 复制链接分享
  • weixin_39520988 weixin_39520988 5月前

    I wasn't sure what you would prefer, so I went with two new API calls: FindUidGetent() and FindGidGetent() that only (the new in this snap_daemon PR series) EnsureUserGroup() will use

    I'm confused, afaict snap-seccomp is using FindGid/FindUid as well, I would expect that to need changing too?

    点赞 评论 复制链接分享
  • weixin_39708502 weixin_39708502 5月前

    There is a spread error here that looks real:

    
    2019-08-16 03:32:34 Error executing google:fedora-30-64:tests/main/system-usernames : 
    -----
    ...
    + echo fedora-30-64
    + for regex in $EXFAIL
    + grep -Eq fedora-30-64
    + echo fedora-30-64
    + ok_to_fail=yes
    + break
    + '[' no = no ']'
    + '[' yes = no ']'
    + '[' no = yes ']'
    + '[' no = yes ']'
    + MATCH 'require a snapd built against libseccomp >= 2.4'
    + snap install --edge test-snapd-daemon-user
    grep error: pattern not found, got:
    error: cannot perform the following tasks:
    - Mount snap "test-snapd-daemon-user" (110) (snap "test-snapd-daemon-user" system usernames require a snapd built against golang-seccomp >= 0.9.1)
    
    点赞 评论 复制链接分享
  • weixin_39627390 weixin_39627390 5月前

    With the merging of 7265 and other commits, I believe all feedback has been addressed.

    点赞 评论 复制链接分享

相关推荐