Refuse inexact production selector authorities
This commit is contained in:
parent
bc04112c77
commit
4cf7a5e595
2 changed files with 230 additions and 34 deletions
|
|
@ -87,6 +87,7 @@ impl PreparedLowerStore {
|
|||
Err(error) => return Err(error.into()),
|
||||
}
|
||||
let root = open_directory_at(&storage_root, Path::new("prepared-lower"))?;
|
||||
require_owned_directory(&root)?;
|
||||
Self::initialize_retained(root, catalog)
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +102,8 @@ impl PreparedLowerStore {
|
|||
Ok(()) | Err(rustix::io::Errno::EXIST) => {}
|
||||
Err(error) => return Err(error.into()),
|
||||
}
|
||||
open_directory_at(&store.root, Path::new(name))?;
|
||||
let directory = open_directory_at(&store.root, Path::new(name))?;
|
||||
require_owned_directory(&directory)?;
|
||||
}
|
||||
open_lock_at(&store.root)?;
|
||||
Ok(store)
|
||||
|
|
@ -472,6 +474,14 @@ impl PreparedLowerStore {
|
|||
}
|
||||
}
|
||||
|
||||
fn require_owned_directory(directory: &File) -> Result<()> {
|
||||
let stat = rustix::fs::fstat(directory)?;
|
||||
if stat.st_uid != rustix::process::getuid().as_raw() || stat.st_mode & 0o7777 != 0o700 {
|
||||
bail!("fixed prepared-lower directory must be owned by the invoking user with mode 0700");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct Identities {
|
||||
artifact_id: PreparedArtifactId,
|
||||
source: SourceIdentity,
|
||||
|
|
@ -685,3 +695,20 @@ fn hex(bytes: &[u8]) -> String {
|
|||
fn secure_resolve() -> ResolveFlags {
|
||||
ResolveFlags::BENEATH | ResolveFlags::NO_SYMLINKS | ResolveFlags::NO_MAGICLINKS
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod fixed_directory_tests {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn prepared_lower_root_requires_invoking_owner_and_exact_private_mode() {
|
||||
let directory = tempfile::tempdir().unwrap();
|
||||
std::fs::set_permissions(directory.path(), std::fs::Permissions::from_mode(0o777)).unwrap();
|
||||
let root = File::open(directory.path()).unwrap();
|
||||
assert!(require_owned_directory(&root).is_err());
|
||||
std::fs::set_permissions(directory.path(), std::fs::Permissions::from_mode(0o700)).unwrap();
|
||||
assert!(require_owned_directory(&root).is_ok());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -355,15 +355,14 @@ impl LayoutWriter {
|
|||
staging_id,
|
||||
} => {
|
||||
let storage = File::from(storage_root.open_authority()?);
|
||||
create_directory(&storage, "image-transports")?;
|
||||
let parent = Arc::new(open_directory(&storage, Path::new("image-transports"))?);
|
||||
let parent = Arc::new(create_directory(&storage, "image-transports")?);
|
||||
let name = hex(&staging_id);
|
||||
mkdirat(&parent, name.as_str(), Mode::from_raw_mode(0o700))?;
|
||||
let root = Arc::new(open_directory(&parent, Path::new(&name))?);
|
||||
require_owned_directory(&root)?;
|
||||
let stat = fstat(&root)?;
|
||||
create_directory(&root, "blobs")?;
|
||||
let blobs = open_directory(&root, Path::new("blobs"))?;
|
||||
create_directory(&blobs, "sha256")?;
|
||||
let blobs = create_directory(&root, "blobs")?;
|
||||
drop(create_directory(&blobs, "sha256")?);
|
||||
write_relative_atomic(
|
||||
&root,
|
||||
Path::new("oci-layout"),
|
||||
|
|
@ -522,12 +521,21 @@ impl LayoutWriter {
|
|||
}
|
||||
}
|
||||
|
||||
fn create_directory(parent: &File, path: &str) -> Result<()> {
|
||||
fn create_directory(parent: &File, path: &str) -> Result<File> {
|
||||
match mkdirat(parent, path, Mode::from_raw_mode(0o700)) {
|
||||
Ok(()) | Err(rustix::io::Errno::EXIST) => {}
|
||||
Err(error) => return Err(error.into()),
|
||||
}
|
||||
drop(open_directory(parent, Path::new(path))?);
|
||||
let directory = open_directory(parent, Path::new(path))?;
|
||||
require_owned_directory(&directory)?;
|
||||
Ok(directory)
|
||||
}
|
||||
|
||||
fn require_owned_directory(directory: &File) -> Result<()> {
|
||||
let stat = fstat(directory)?;
|
||||
if stat.st_uid != rustix::process::getuid().as_raw() || stat.st_mode & 0o7777 != 0o700 {
|
||||
bail!("fixed image-transport directory must be owned by the invoking user with mode 0700");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -695,11 +703,30 @@ fn hex(bytes: &[u8]) -> String {
|
|||
mod tests {
|
||||
use std::io::{Read, Write};
|
||||
use std::net::TcpListener;
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
use oci_client::client::ClientProtocol;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn preexisting_transport_parents_require_exact_private_mode() {
|
||||
for name in ["image-transports", "blobs", "sha256"] {
|
||||
let tree = tempfile::tempdir().unwrap();
|
||||
std::fs::create_dir(tree.path().join(name)).unwrap();
|
||||
std::fs::set_permissions(
|
||||
tree.path().join(name),
|
||||
std::fs::Permissions::from_mode(0o777),
|
||||
)
|
||||
.unwrap();
|
||||
let parent = File::open(tree.path()).unwrap();
|
||||
assert!(
|
||||
create_directory(&parent, name).is_err(),
|
||||
"accepted wrong mode for {name}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn refuses_mismatched_and_incomplete_platforms() {
|
||||
assert!(
|
||||
|
|
|
|||
Loading…
Reference in a new issue