diff options
| author | Hermes Agent <hermes@localhost> | 2026-08-12 04:26:44 +0000 |
|---|---|---|
| committer | Hermes Agent <hermes@localhost> | 2026-08-12 04:26:44 +0000 |
| commit | ca9e5044a1678a3ff33f13582bd6498632113c3e (patch) | |
| tree | eeb4cd51faa52510ffe7f0bf27d3cf9dcd9b241d /src/rootfs.rs | |
| parent | 39a23d9035ab99191e305db3a55a8df1606f63b3 (diff) | |
Prevent rootfs copy from following symlinks
Diffstat (limited to 'src/rootfs.rs')
| -rw-r--r-- | src/rootfs.rs | 16 |
1 files changed, 14 insertions, 2 deletions
diff --git a/src/rootfs.rs b/src/rootfs.rs index 9246aa8..ea7d87b 100644 --- a/src/rootfs.rs +++ b/src/rootfs.rs @@ -173,8 +173,7 @@ fn copy_entry( if let Some(parent) = output.parent() { fs::create_dir_all(parent)?; } - fs::copy(source, &output) - .with_context(|| format!("copy {} to {}", source.display(), output.display()))?; + replace_with_file(source, &output)?; fs::set_permissions(&output, metadata.permissions())?; manifest.record(destination); } else { @@ -213,6 +212,19 @@ fn enable_service(rootfs: &Path, service: &ServiceName, manifest: &mut MutationM Ok(()) } +fn replace_with_file(source: &Path, output: &Path) -> Result<()> { + match fs::symlink_metadata(output) { + Ok(metadata) if metadata.file_type().is_dir() => { + bail!("cannot replace directory with file: {}", output.display()); + } + Ok(_) => fs::remove_file(output).with_context(|| format!("replace {}", output.display()))?, + Err(error) if error.kind() == std::io::ErrorKind::NotFound => {} + Err(error) => return Err(error).with_context(|| format!("inspect {}", output.display())), + } + fs::copy(source, output).with_context(|| format!("copy {} to {}", source.display(), output.display()))?; + Ok(()) +} + fn replace_with_symlink(target: &Path, output: &Path) -> Result<()> { match fs::symlink_metadata(output) { Ok(metadata) if metadata.file_type().is_dir() => { |