Skip to content

exit: validate cid. - #53

Open
jankaluza wants to merge 2 commits into
containers:mainfrom
jankaluza:h5
Open

exit: validate cid.#53
jankaluza wants to merge 2 commits into
containers:mainfrom
jankaluza:h5

Conversation

@jankaluza

Copy link
Copy Markdown
Member

Reject only empty, ., .., /, and NUL so exit_dir writes cannot escape while still accepting previously valid container IDs.

Reject only empty, `.`, `..`, `/`, and NUL so exit_dir writes
cannot escape while still accepting previously valid container IDs.

Signed-off-by: Jan Kaluza <jkaluza@redhat.com>
@packit-as-a-service

Copy link
Copy Markdown

Ephemeral COPR build failed.

Comment thread src/exit.rs Outdated
/// allow escaping `exit_dir` or confusing path APIs. Other characters (including
/// `+`, `:`, and non-ASCII) are accepted so historically valid container IDs keep
/// working.
fn is_safe_container_id(cid: &str) -> bool {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is perfectly fine.
Just one thing to consider if the cid is used in multiple places is the newtype/Make Illegal States Unrepresentable idiom, i.e. creating a wrapper type for Cid and making sure that if you are able to construct it, it is a valid ID.

Something like (there are many traits that can be implemented):

pub struct Cid(String);

use std::str::FromStr;
impl FromStr for Cid {
    type Err = conmon::error::ConmonError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        // Would be inlined.
        if !is_safe_container_id(cid) {
            return Err(ConmonError::new("invalid cid");
        }
        Ok(Cid(s.to_string()))
    }
}

See:

I'll be glad to rewrite it in that style in a new PR, if I'm being too annoying:)

Comment thread src/exit.rs Outdated
/// `+`, `:`, and non-ASCII) are accepted so historically valid container IDs keep
/// working.
fn is_safe_container_id(cid: &str) -> bool {
!cid.is_empty() && cid != "." && cid != ".." && !cid.contains('/') && !cid.contains('\0')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I noticed is that the CommonCfg implements Default and it the cid field defaults to an invalid ID (the empty string).

Comment thread src/exit.rs
}

#[test]
fn write_exit_files_does_not_escape_exit_dir() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be extra safe, write_exit_files could use Path::starts_with or similar to validate that the path doesn't escape the directory. Not that it's needed currently.

@simek-m simek-m left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks good and the tests cover a lot, only a stylistic comment as usual:) LGTM.

Invalid container IDs are unrepresentable in CommonCfg and
write_exit_files(). They are validated at startup.

Signed-off-by: Jan Kaluza <jkaluza@redhat.com>
@simek-m

simek-m commented Sep 1, 2026

Copy link
Copy Markdown

One thing regarding the newtype I forgot - in a perfect world, it should be in its own module to enforce the validation, see https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=9fa00c7f638311a8068636663be657f8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants