Hi folks, [I'm writing this on Colin's suggestion, to introduce more people to the discussion and hopefully get some new ideas how to solve the problem. Apologies for the length.]
The problem: when packages have files owned by a user or group that are part of the package contents ("owned files" for short), and the uid/gid is allocated dynamically [1], the uid/gid can change between builds of an image from that package ("uid/gid drift") and then in a deployment, after an upgrade, the numeric uid/gid that is stored in the local system database might be different then the numer used in the image, causing files to be owned by the wrong user/group. This was a known problem for rpm-ostree systems, and was handled ad-hoc when problems were reported, but is becoming a bigger problem for bootc systems. There are a few options possible: avoid using any "owned files" in packages, use tmpfiles.d to adjust ownership dynamically, switch back to soft-static uid/gid assignments, completely change how we do deployments, stop upgrading image-based deployments… We need to do _something_, but it's not clear at this point what the best course of action is. ** Details of the problem ** I know the summary above is dense. Let's go through an example: - Package opencryptoki defines group pkcs11. This group uses "dynamic allocation", i.e. the specific numeric gid is selected when the package is installed, taking the first unused number. - The package has a file in the %files payload owned by the group: %attr(,,pkcs11) /etc/opencryptoki/strength.conf - When an rpm-ostree or bootc image is built with this package, the accounts are created in the local user/group database and some numeric uids/gids are selected, for example 999. The filesystem stores ownership as numbers, so that gid is used for /etc/opencryptoki/strength.conf in the filesystem. - The user makes a deployment using this image; in the local installation the gid is used for /etc/opencryptoki/strength.conf. - A new version of the rpm-ostree or bootc image is built, but this time numeric uids/gids are different, e.g. we get 998 for pkcs11. - The user upgrades, and the file in the image is owned by a gid that maps to a different group in the local database or to no group and is listed as unowned. Note that the package installation order is deterministic and stable. So when we rebuild an image with the same package set, we're always going to get the same numeric uids/gids. But we can get different assignments if the package installation order changes, for example because of some dependency change, or more/less packages are installed, or when one of the packages defines a new user/group. In general, we can expect the uid/gid assignments to change regularly. The consequences of such wrong ownership can vary: in the most benign case this is just a cosmetic issue in 'ls' output. The case that is actually reported by users is when the service fails to start because it cannot access some file. But then there's also some silent group of cases where the wrong ownership creates a security vulnerability or an information leak. This problem exists primarily in "image-based" deployments. In traditional "package-based" deployments, uids/gids might be assigned differently between systems, but on a given installation, the uid/gid assignment remains stable. The problem only appears when the local user database is wiped between image builds. This problem is now primarily visible for rpm-ostree and bootc, but would appear also for any image-based system where the image is built "remotely" (with a independent user/group database, even if the build happens on the same machine), and the creation of local system accounts is allowed. One example is ParticleOs [6], where this issues is solved by _not_ allowing any "owned files" in the image and using tmpfiles.d snippets instead. "Owned files" also create a problem for image *building*, if this is done unprivileged. Mkosi [7] makes 'chown' a noop during unprivileged image builds, which means that "owned files" in the image don't work, files end up being owned by root. ** UID/GID assignment strategies ** See [1] for a longer discussion, but the tl;dr is that we used to assign uids/gids statically, but moved to dynamic assignment about 15 years ago. The uid/gid range for system accounts is limited, nowadays 1-999, in the past 1-499, but we still support upgraded systems with the old range. Above that range, we have "user accounts", starting at 1000 (or 500 on old systems). Soft-static uids/gids are taken from the bottom of this range, while dynamic uids/gids are taken from the top. Accounts can be created by packages, but also by the local admins. See [3] for the list of current assignments. The "soft" part in soft-static is because we never override a uid/gid that was assigned locally. Thus if the local admin either used a uid/gid for a different purpose, or created the user/group with a different uid/gid than our allocation, we honour that. The soft-static allocations are needed for the case where the assignment is shared between systems. In the past this was used with some file sharing protocols like nfs/ceph/gluster, where some files owned by the system user or group would be shared on the network. But nowadays the is mostly used for the initrd: files in /dev or /run are owned by various groups to provide unprivelged access, and then after the transition to the host system, those file systems are moved over, so we need to maitain stability of uids/gids. In F42+ we have changed the user creation *mechanism* from traditional scriptlets which called useradd/groupadd/usermod/groupmod/gpasswd to declarative sysusers.d files, which are then executed by calling systemd-sysusers [4]. This changes the mechanism, but doesn't change the problem with uid/gid drift. systemd-sysusers intentionally implements the same soft-static and dynamic allocation strategies described in [1]. Arguably, the biggest change is increased visibility. We have 372 unique names in sysusers files in packages in Fedora rawhide (for users or groups), and 163 static allocations in setup. ** Potential solutions ** Please note that for the problem to manifest, two conditions are necessary: the uid/gid must use dynamic allocation, and the package must have "owned files". (Files owned by the user/group but created after installation are not a problem.) Thus the first solution is not to have any owned files. This is the recommended approach. It also aligns nicely with the "hermetic /usr" initiative, where packages only contain files under /usr. Those files must be treated as immutable, and it doesn't make sense for them not to be publicly readable, so naturally they are not owned. It also aligns nicely with unprivileged builds. (rpm-ostree/bootc docs recommend systemd's DynamicUser=true. Those users are created at runtime with no fixed uid/gid assignement and packages which use such users cannot have any owned files. This obviously solves the problem too.) A second "solution" is to keep files "unowned", i.e. owned by root in the package payload, but chown them at runtime after installation. This can be implemented fairly easily using tmpfiles.d. But it's actually quite a bit of work and bother to do correctly. The initial ownership must be by root, so that the file does not appear with a "wrong" uid/gid after initial installation. Then the ownership needs to be adjusted before the service is started, i.e. the service must be ordered after a systemd-tmpfiles run. We call systemd-tmpfiles via a filetrigger, so normally the case where the package is installed on a running system would be handled correctly, i.e. the files would be correctly owned after dnf finishes. But this is still fairly fragile. The third solution is to use soft-static assignment. The most recent example of a package where this was added for the purposes of rpm-ostree is polkit. In principle we have some space: there aren't that many packages with owned files, so we could add static assignments for those packages. Apart from the problem of potentially exhausting the available range, soft-static assignments are not great also because they require bureaucracy and coordination between different setup and various maintainers. This would be a big change to the existing policy and would require quite a bit of work to implement and would be of no benefit to users of package-based systems. Upgraded systems would not get the new assignments, so we would not be able to rely on the new static allocations. Nevertheless, even if we were to switch to soft-static allocations for packages, soft-static assignment cannot cover users created by non-distro packages and outside of packages. With bootc, it is easy for a user to create some user or group in the image (via 'RUN groupadd -r foo' or by installing some 3rd-party package). So this becomes a bigger problem then previously, see [5]. In fact, we'd probably need to convert _all_ distro packages to soft-static allocation, so that those uids/gids are taken from the bottom of the range, to keep the top of the range clear for unassigned allocations by users using bootc. Even then, users would need to carefully maintain the order of operations in their image definitions to avoid uid/gid drift. In the past I suggested some solution where the user/group database would be kept betwen rpm-ostree builds. We might have been hard but feasible for rpm-ostree, where builds were done in our infra, but it's not even feasible for bootc, with many uncoordinated definitions. We could also consider some bigger changes, like not using numeric uids/gids for bootc images, and making the assignment only during installation, similarly to how rpm does this… At this point, I think the approach of combining the first two solutions, i.e. minimizing the number of "owned files" and judiciously using tmpfiles.d to adjust ownership at runtime is a feasible and relatively painless option. To solve the problems for rpm-ostree/bootc, we'd need to make this into an official policy and adjust some packages. Comments/ideas? [1] https://docs.fedoraproject.org/en-US/packaging-guidelines/UsersAndGroups/#_dynamic_allocation [2] https://github.com/uapi-group/specifications/issues/76 [3] https://src.fedoraproject.org/rpms/setup/blob/rawhide/f/uidgid [4] https://fedoraproject.org/wiki/Changes/RPMSuportForSystemdSysusers [5] https://issues.redhat.com/browse/RHEL-77146 [6] https://github.com/systemd/particleos [7] https://github.com/systemd/mkosi -- _______________________________________________ devel mailing list -- devel@lists.fedoraproject.org To unsubscribe send an email to devel-le...@lists.fedoraproject.org Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/ List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines List Archives: https://lists.fedoraproject.org/archives/list/devel@lists.fedoraproject.org Do not reply to spam, report it: https://pagure.io/fedora-infrastructure/new_issue