diff --git a/build_library/build_image_util.sh b/build_library/build_image_util.sh index d0ed76f318..bc0b6cc756 100755 --- a/build_library/build_image_util.sh +++ b/build_library/build_image_util.sh @@ -744,11 +744,34 @@ finish_image() { done # Record directories installed to the state partition. # Explicitly ignore entries covered by existing configs. - local tmp_ignore=$(awk '/^[dDfFL]/ {print "--ignore=" $2}' \ - "${root_fs_dir}"/usr/lib/tmpfiles.d/*.conf) + local ignores=() allowed_users=() allowed_groups=() + mapfile -t ignores < <(awk '/^[dDfFL]/ {print "--ignore=" $2}' \ + "${root_fs_dir}"/usr/lib/tmpfiles.d/*.conf) + # Also ignore directories owned by users/groups not in /etc/passwd + # or /etc/group. This is for setting up needed directories in very + # early boot phase (initrd-setup-root). Our source of truth for + # allowed users and groups are users and groups copied by the + # flatcar-tmpfiles script. + + # The grep, sed and tr below basically turn a line like: + # COPY_USERS="root|core" + # into: + # --allow-user=root + # --allow-user=core + mapfile -t allowed_users < <(grep '^COPY_USERS=' "${root_fs_dir}/sbin/flatcar-tmpfiles" | sed -e 's/.*="\([^"]*\)"/\1/' | tr '|' '\n' | sed -e 's/^/--allow-user=/') + mapfile -t allowed_users < <(grep '^COPY_GROUPS=' "${root_fs_dir}/sbin/flatcar-tmpfiles" | sed -e 's/.*="\([^"]*\)"/\1/' | tr '|' '\n' | sed -e 's/^/--allow-group=/') sudo "${BUILD_LIBRARY_DIR}/gen_tmpfiles.py" --root="${root_fs_dir}" \ --output="${root_fs_dir}/usr/lib/tmpfiles.d/base_image_var.conf" \ - ${tmp_ignore} "${root_fs_dir}/var" + "${ignores[@]}" "${allowed_users[@]}" "${allowed_groups[@]}" "${root_fs_dir}/var" + + # Now record the rest of the directories installed to the state + # partition. We go through tmpfiles again to also ignore the entries + # from the just generated base_image_var.conf. + mapfile -t ignores < <(awk '/^[dDfFL]/ {print "--ignore=" $2}' \ + "${root_fs_dir}"/usr/lib/tmpfiles.d/*.conf) + sudo "${BUILD_LIBRARY_DIR}/gen_tmpfiles.py" --root="${root_fs_dir}" \ + --output="${root_fs_dir}/usr/lib/tmpfiles.d/base_image_var_late.conf" \ + "${ignores[@]}" "${root_fs_dir}/var" # Only configure bootloaders if there is a boot partition if mountpoint -q "${root_fs_dir}"/boot; then diff --git a/build_library/gen_tmpfiles.py b/build_library/gen_tmpfiles.py index a4b4134ba1..15958bedbf 100755 --- a/build_library/gen_tmpfiles.py +++ b/build_library/gen_tmpfiles.py @@ -21,8 +21,15 @@ def main(): parser.add_option('--output', help='Write output to the given file') parser.add_option('--ignore', action='append', default=[], help='Ignore one or more paths (use multiple times)') + parser.add_option('--allow-user', action='append', default=[], + help='Allow entries owned by this user only (use multiple times for multiple users)') + parser.add_option('--allow-group', action='append', default=[], + help='Allow entries owned by this group only (use multiple times for multiple groups)') opts, args = parser.parse_args() + allowed_users = set(opts.allow_user) + allowed_groups = set(opts.allow_group) + if opts.root: opts.root = os.path.abspath(opts.root) @@ -59,7 +66,7 @@ def main(): stripped = path if stripped in opts.ignore: - continue + continue info = os.stat(path) assert stat.S_ISDIR(info.st_mode) @@ -67,10 +74,14 @@ def main(): try: owner = pwd.getpwuid(info.st_uid).pw_name + if allowed_users and owner not in allowed_users: + continue except KeyError: owner = str(info.st_uid) try: group = grp.getgrgid(info.st_gid).gr_name + if allowed_groups and group not in allowed_groups: + continue except KeyError: group = str(info.st_gid)