From: Daan De Meyer Date: Mon, 27 Mar 2023 08:55:16 +0000 (+0200) Subject: Add --acl option X-Git-Tag: v15~274 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8fea18a6115e6be1f3b64461c6a20a86a4acc6da;p=thirdparty%2Fmkosi.git Add --acl option Let's make the usage of ACLs opt-in since they leak into the final image if the directory output is used. We move the call to print_output_size() so its executed inside the user namespace, which is required because we might not have permissions to read some of the image's directories outside the user namespace. --- diff --git a/mkosi.md b/mkosi.md index 9e008fbfa..24f072021 100644 --- a/mkosi.md +++ b/mkosi.md @@ -861,6 +861,11 @@ a boolean argument: either "1", "yes", or "true" to enable, or "0", OEM string. This will only be picked up by systemd-boot/systemd-stub versions newer than or equal to v254. +`Acl=`, `--acl=` + +: If specified, ACLs will be set on any generated root filesystem directories that + allow the user running mkosi to remove them without needing privileges. + ### Commandline-only Options Those settings cannot be configured in the configuration files. diff --git a/mkosi/__init__.py b/mkosi/__init__.py index 4b534fbdd..01ef45c82 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -1008,7 +1008,10 @@ def calculate_bmap(state: MkosiState) -> None: run(cmdline) -def acl_toggle_remove(root: Path, uid: int, *, allow: bool) -> None: +def acl_toggle_remove(config: MkosiConfig, root: Path, uid: int, *, allow: bool) -> None: + if not config.acl: + return + ret = run( [ "setfacl", @@ -1032,12 +1035,12 @@ def save_cache(state: MkosiState) -> None: with complete_step("Installing cache copies"): unlink_try_hard(final) shutil.move(state.root, final) - acl_toggle_remove(final, state.uid, allow=True) + acl_toggle_remove(state.config, final, state.uid, allow=True) if state.config.build_script: unlink_try_hard(build) shutil.move(state.build_overlay, build) - acl_toggle_remove(build, state.uid, allow=True) + acl_toggle_remove(state.config, build, state.uid, allow=True) def dir_size(path: PathString) -> int: @@ -1953,6 +1956,12 @@ def create_parser() -> ArgumentParserMkosi: default=[], help="Append extra entries to the kernel command line when booting the image", ) + group.add_argument( + "--acl", + metavar="BOOL", + action=BooleanAction, + help="Set ACLs on generated directories to permit the user running mkosi to remove them", + ) group = parser.add_argument_group("Additional configuration options") group.add_argument( @@ -3070,10 +3079,10 @@ def reuse_cache_tree(state: MkosiState) -> bool: with complete_step("Copying cached trees"): copy_path(final, state.root) - acl_toggle_remove(state.root, state.uid, allow=False) + acl_toggle_remove(state.config, state.root, state.uid, allow=False) if state.config.build_script: copy_path(build, state.build_overlay) - acl_toggle_remove(state.build_overlay, state.uid, allow=False) + acl_toggle_remove(state.config, state.build_overlay, state.uid, allow=False) return True @@ -3327,7 +3336,7 @@ def build_stuff(uid: int, gid: int, config: MkosiConfig) -> None: save_manifest(state, manifest) if state.config.cache_path: - acl_toggle_remove(state.config.cache_path, state.uid, allow=True) + acl_toggle_remove(state.config, state.config.cache_path, state.uid, allow=True) for p in state.config.output_paths(): if state.staging.joinpath(p.name).exists(): @@ -3335,7 +3344,7 @@ def build_stuff(uid: int, gid: int, config: MkosiConfig) -> None: if p != state.config.output or state.config.output_format != OutputFormat.directory: os.chown(p, state.uid, state.gid) else: - acl_toggle_remove(p, uid, allow=True) + acl_toggle_remove(state.config, p, uid, allow=True) if p in (state.config.output, state.config.output_split_kernel): compress_output(state.config, p, uid=state.uid, gid=state.gid) @@ -3345,6 +3354,8 @@ def build_stuff(uid: int, gid: int, config: MkosiConfig) -> None: if p.name.startswith(state.config.output.name): compress_output(state.config, p, uid=state.uid, gid=state.gid) + print_output_size(config) + def check_root() -> None: if os.getuid() != 0: @@ -3431,13 +3442,13 @@ def run_shell(config: MkosiConfig) -> None: uid, _ = current_user_uid_gid() if config.output_format == OutputFormat.directory: - acl_toggle_remove(config.output, uid, allow=False) + acl_toggle_remove(config, config.output, uid, allow=False) try: run(cmdline, stdout=sys.stdout) finally: if config.output_format == OutputFormat.directory: - acl_toggle_remove(config.output, uid, allow=True) + acl_toggle_remove(config, config.output, uid, allow=True) def find_qemu_binary(config: MkosiConfig) -> str: @@ -3872,7 +3883,12 @@ def run_verb(raw: argparse.Namespace) -> None: check_outputs(config) if needs_build(config) or config.verb == Verb.clean: - unlink_output(config) + def target() -> None: + if os.getuid() != 0: + become_root() + unlink_output(config) + + fork_and_wait(target) if needs_build(config): def target() -> None: @@ -3889,8 +3905,6 @@ def run_verb(raw: argparse.Namespace) -> None: if config.auto_bump: bump_image_version(config) - print_output_size(config) - with suppress_stacktrace(): if config.verb in (Verb.shell, Verb.boot): run_shell(config) diff --git a/mkosi/backend.py b/mkosi/backend.py index dfbdef633..94233e425 100644 --- a/mkosi/backend.py +++ b/mkosi/backend.py @@ -307,6 +307,7 @@ class MkosiConfig: workspace_dir: Optional[Path] initrds: list[Path] kernel_command_line_extra: list[str] + acl: bool # QEMU-specific options qemu_headless: bool