-
Notifications
You must be signed in to change notification settings - Fork 174
store: Centralize composefs directory creation with mode 0700 #2006
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,7 +24,9 @@ use anyhow::{Context, Result}; | |
| use bootc_mount::tempmount::TempMount; | ||
| use camino::Utf8PathBuf; | ||
| use cap_std_ext::cap_std; | ||
| use cap_std_ext::cap_std::fs::{Dir, DirBuilder, DirBuilderExt as _}; | ||
| use cap_std_ext::cap_std::fs::{ | ||
| Dir, DirBuilder, DirBuilderExt as _, Permissions, PermissionsExt as _, | ||
| }; | ||
| use cap_std_ext::dirext::CapStdExtDirExt; | ||
| use fn_error_context::context; | ||
|
|
||
|
|
@@ -51,8 +53,29 @@ pub const SYSROOT: &str = "sysroot"; | |
|
|
||
| /// The toplevel composefs directory path | ||
| pub const COMPOSEFS: &str = "composefs"; | ||
| #[allow(dead_code)] | ||
| pub const COMPOSEFS_MODE: Mode = Mode::from_raw_mode(0o700); | ||
|
|
||
| /// The mode for the composefs directory; this is intentionally restrictive | ||
| /// to avoid leaking information. | ||
| pub(crate) const COMPOSEFS_MODE: Mode = Mode::from_raw_mode(0o700); | ||
|
|
||
| /// Ensure the composefs directory exists in the given physical root | ||
| /// with the correct permissions (mode 0700). | ||
| pub(crate) fn ensure_composefs_dir(physical_root: &Dir) -> Result<()> { | ||
| let mut db = DirBuilder::new(); | ||
| db.mode(COMPOSEFS_MODE.as_raw_mode()); | ||
| physical_root | ||
| .ensure_dir_with(COMPOSEFS, &db) | ||
| .context("Creating composefs directory")?; | ||
| // Always update permissions, in case the directory pre-existed | ||
cgwalters marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // with incorrect mode (e.g. from an older version of bootc). | ||
| physical_root | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor nit but I'd prefer if we only called Also important: At some point in the future we will need to properly handle "physically" readonly rootfs (think ISO), so we don't want to introduce new places where we unconditionally try writes.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These things can be followups |
||
| .set_permissions( | ||
| COMPOSEFS, | ||
| Permissions::from_mode(COMPOSEFS_MODE.as_raw_mode()), | ||
| ) | ||
| .context("Setting composefs directory permissions")?; | ||
| Ok(()) | ||
| } | ||
|
|
||
| /// The path to the bootc root directory, relative to the physical | ||
| /// system root | ||
|
|
@@ -399,9 +422,7 @@ impl Storage { | |
| return Ok(Arc::clone(composefs)); | ||
| } | ||
|
|
||
| let mut db = DirBuilder::new(); | ||
| db.mode(COMPOSEFS_MODE.as_raw_mode()); | ||
| self.physical_root.ensure_dir_with(COMPOSEFS, &db)?; | ||
| ensure_composefs_dir(&self.physical_root)?; | ||
|
|
||
| // Bootstrap verity off of the ostree state. In practice this means disabled by | ||
| // default right now. | ||
|
|
@@ -430,3 +451,62 @@ impl Storage { | |
| .context("update_timestamps") | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| /// The raw mode returned by metadata includes file type bits (S_IFDIR, | ||
| /// etc.) in addition to permission bits. This constant masks to only | ||
| /// the permission bits (owner/group/other rwx). | ||
| const PERMS: Mode = Mode::from_raw_mode(0o777); | ||
|
|
||
| #[test] | ||
| fn test_ensure_composefs_dir_mode() -> Result<()> { | ||
| use cap_std_ext::cap_primitives::fs::PermissionsExt as _; | ||
|
|
||
| let td = cap_std_ext::cap_tempfile::TempDir::new(cap_std::ambient_authority())?; | ||
|
|
||
| let assert_mode = || -> Result<()> { | ||
| let perms = td.metadata(COMPOSEFS)?.permissions(); | ||
| let mode = Mode::from_raw_mode(perms.mode()); | ||
| assert_eq!(mode & PERMS, COMPOSEFS_MODE); | ||
| Ok(()) | ||
| }; | ||
|
|
||
| ensure_composefs_dir(&td)?; | ||
| assert_mode()?; | ||
|
|
||
| // Calling again should be a no-op (ensure is idempotent) | ||
| ensure_composefs_dir(&td)?; | ||
| assert_mode()?; | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_ensure_composefs_dir_fixes_existing() -> Result<()> { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The unit test is fine and cheap, but I think this one also wants to be integration tested. |
||
| use cap_std_ext::cap_primitives::fs::PermissionsExt as _; | ||
|
|
||
| let td = cap_std_ext::cap_tempfile::TempDir::new(cap_std::ambient_authority())?; | ||
|
|
||
| // Create with overly permissive mode (simulating old bootc behavior) | ||
| let mut db = DirBuilder::new(); | ||
| db.mode(0o755); | ||
| td.create_dir_with(COMPOSEFS, &db)?; | ||
|
|
||
| // Verify it starts with wrong permissions | ||
| let perms = td.metadata(COMPOSEFS)?.permissions(); | ||
| let mode = Mode::from_raw_mode(perms.mode()); | ||
| assert_eq!(mode & PERMS, Mode::from_raw_mode(0o755)); | ||
|
|
||
| // ensure_composefs_dir should fix the permissions | ||
| ensure_composefs_dir(&td)?; | ||
|
|
||
| let perms = td.metadata(COMPOSEFS)?.permissions(); | ||
| let mode = Mode::from_raw_mode(perms.mode()); | ||
| assert_eq!(mode & PERMS, COMPOSEFS_MODE); | ||
|
|
||
| Ok(()) | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.