github.com/tompreston/snapd@v0.0.0-20210817193607-954edfcb9611/snap/system_usernames.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2021 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package snap
    21  
    22  type systemUsername struct {
    23  	Id uint32
    24  	// List of snap IDs which are allowed to declare this user or nil if no
    25  	// such restriction exists
    26  	AllowedSnapIds []string
    27  }
    28  
    29  // SupportedSystemUsernames for now contains the hardcoded list of system
    30  // users (and implied system group of same name) that snaps may specify. This
    31  // will eventually be moved out of here into the store.
    32  //
    33  // Since the snap is mounted read-only and to avoid problems associated with
    34  // different systems using different uids and gids for the same user name and
    35  // group name, snapd will create system-usernames where 'scope' is not
    36  // 'external' (currently snapd only supports 'scope: shared') with the
    37  // following characteristics:
    38  //
    39  // - uid and gid shall match for the specified system-username
    40  // - a snapd-allocated [ug]id for a user/group name shall never change
    41  // - snapd should avoid [ug]ids that are known to overlap with uid ranges of
    42  //   common use cases and user namespace container managers so that DAC and
    43  //   AppArmor owner match work as intended.
    44  // - [ug]id shall be < 2^31 to avoid (at least) broken devpts kernel code
    45  // - [ug]id shall be >= 524288 (0x00080000) to give plenty of room for large
    46  //   sites, default uid/gid ranges for docker (231072-296608), LXD installs
    47  //   that setup a default /etc/sub{uid,gid} (100000-165536) and podman whose
    48  //   tutorials reference setting up a specific default user and range
    49  //   (100000-165536)
    50  // - [ug]id shall be < 1,000,000 and > 1,001,000,000 (ie, 1,000,000 subordinate
    51  //   uid with 1,000,000,000 range) to avoid overlapping with LXD's minimum and
    52  //   maximum id ranges. LXD allows for any id range >= 65536 and doesn't
    53  //   perform any [ug]id overlap detection with current users
    54  // - [ug]ids assigned by snapd initially will fall within a 65536 (2^16) range
    55  //   (see below) where the first [ug]id in the range has the 16 lower bits all
    56  //   set to zero. This allows snapd to conveniently be bitwise aligned, follows
    57  //   sensible conventions (see https://systemd.io/UIDS-GIDS.html) but also
    58  //   potentially discoverable by systemd-nspawn (it assigns a different 65536
    59  //   range to each container. Its allocation algorithm is not sequential and
    60  //   may choose anything within its range that isn't already allocated. It's
    61  //   detection algorithm includes (effectively) performing a getpwent()
    62  //   operation on CANDIDATE_UID & 0XFFFF0000 and selecting another range if it
    63  //   is assigned).
    64  //
    65  // What [ug]id range(s) should snapd use?
    66  //
    67  // While snapd does not employ user namespaces, it will operate on systems with
    68  // container managers that do and will assign from a range of [ug]ids. It is
    69  // desirable that snapd assigns [ug]ids that minimally conflict with the system
    70  // and other software (potential conflicts with admin-assigned ranges in
    71  // /etc/subuid and /etc/subgid cannot be avoided, but can be documented as well
    72  // as detected/logged). Overlapping with container managers is non-fatal for
    73  // snapd and the container, but introduces the possibility that a uid in the
    74  // container matches a uid a snap is using, which is undesirable in terms of
    75  // security (eg, DoS via ulimit, same ownership of files between container and
    76  // snap (even if the other's files are otherwise inaccessible), etc).
    77  //
    78  // snapd shall assign [ug]ids from range(s) of 65536 where the lowest value in
    79  // the range has the 16 lower bits all set to zero (initially just one range,
    80  // but snapd can add more as needed).
    81  //
    82  // To avoid [ug]id overlaps, snapd shall only assign [ug]ids >= 524288
    83  // (0x00080000) and <= 983040 (0x000F0000, ie the first 65536 range under LXD's
    84  // minimum where the lower 16 bits are all zeroes). While [ug]ids >= 1001062400
    85  // (0x3BAB0000, the first 65536 range above LXD's maximum where the lower 16
    86  // bits are all zeroes) would also avoid overlap, considering nested containers
    87  // (eg, LXD snap runs a container that runs a container that runs snapd),
    88  // choosing >= 1001062400 would mean that the admin would need to increase the
    89  // LXD id range for these containers for snapd to be allowed to create its
    90  // [ug]ids in the deeply nested containers. The requirements would both be an
    91  // administrative burden and artificially limit the number of deeply nested
    92  // containers the host could have.
    93  //
    94  // Looking at the LSB and distribution defaults for login.defs, we can observe
    95  // uids and gids in the system's initial 65536 range (ie, 0-65536):
    96  //
    97  // - 0-99        LSB-suggested statically assigned range (eg, root, daemon,
    98  //               etc)
    99  // - 0           mandatory 'root' user
   100  // - 100-499     LSB-suggested dynamically assigned range for system users
   101  //               (distributions often prefer a higher range, see below)
   102  // - 500-999     typical distribution default for dynamically assigned range
   103  //               for system users (some distributions use a smaller
   104  //               SYS_[GU]ID_MIN)
   105  // - 1000-60000  typical distribution default for dynamically assigned range
   106  //               for regular users
   107  // - 65535 (-1)  should not be assigned since '-1' might be evaluated as this
   108  //               with set[ug]id* and chown families of functions
   109  // - 65534 (-2)  nobody/nogroup user for NFS/etc [ug]id anonymous squashing
   110  // - 65519-65533 systemd recommended reserved range for site-local anonymous
   111  //               additions, etc
   112  //
   113  // To facilitate potential future use cases within the 65536 range snapd will
   114  // assign from, snapd will only assign from the following subset of ranges
   115  // relative to the range minimum (ie, its 'base' which has the lower 16 bits
   116  // all set to zero):
   117  //
   118  // - 60500-60999 'scope: shared' system-usernames
   119  // - 61000-65519 'scope: private' system-usernames
   120  //
   121  // Since the first [ug]id range must be >= 524288 and <= 983040 (see above) and
   122  // following the above guide for system-usernames [ug]ids within this 65536
   123  // range, the lowest 'scope: shared' user in this range is 584788 (0x0008EC54).
   124  //
   125  // Since this number is within systemd-nspawn's range of 524288-1879048191
   126  // (0x00080000-0x6FFFFFFF), the number's lower 16 bits are not all zeroes so
   127  // systemd-nspawn won't detect this allocation and could potentially assign the
   128  // 65536 range starting at 0x00080000 to a container. snapd will therefore also
   129  // create the 'snapd-range-524288-root' user and group with [ug]id 524288 to
   130  // work within systemd-nspawn's collision detection. This user/group will not
   131  // be assigned to snaps at this time.
   132  //
   133  // In short (phew!), use the following:
   134  //
   135  // $ snappy-debug.id-range 524288 # 0x00080000
   136  // Host range:              524288-589823 (00080000-0008ffff; 0-65535)
   137  // LSB static range:        524288-524387 (00080000-00080063; 0-99)
   138  // Useradd system range:    524788-525287 (000801f4-000803e7; 500-999)
   139  // Useradd regular range:   525288-584288 (000803e8-0008ea60; 1000-60000)
   140  // Snapd system range:      584788-585287 (0008ec54-0008ee47; 60500-60999)
   141  // Snapd private range:     585288-589807 (0008ee48-0008ffef; 61000-65519)
   142  //
   143  // Snapd is of course free to add more ranges (eg, 589824 (0x00090000)) with
   144  // new snapd-range-<base>-root users, or to allocate differently within its
   145  // 65536 range in the future (sequentially assigned [ug]ids are not required),
   146  // but for now start very regimented to avoid as many problems as possible.
   147  //
   148  // References:
   149  // https://forum.snapcraft.io/t/multiple-users-and-groups-in-snaps/
   150  // https://systemd.io/UIDS-GIDS.html
   151  // https://docs.docker.com/engine/security/userns-remap/
   152  // https://github.com/lxc/lxd/blob/master/doc/userns-idmap.md
   153  var SupportedSystemUsernames = map[string]systemUsername{
   154  	"snap_daemon": {Id: 584788},
   155  	"snap_microk8s": {Id: 584789, AllowedSnapIds: []string{
   156  		"EaXqgt1lyCaxKaQCU349mlodBkDCXRcg", // microk8s
   157  	}},
   158  }