diff --git a/src/agent/src/rpc.rs b/src/agent/src/rpc.rs index c7d60f1e6b..12cfcd853c 100644 --- a/src/agent/src/rpc.rs +++ b/src/agent/src/rpc.rs @@ -80,6 +80,23 @@ pub struct AgentService { sandbox: Arc>, } +// A container ID must match this regex: +// +// ^[a-zA-Z0-9][a-zA-Z0-9_.-]+$ +// +fn verify_cid(id: &str) -> Result<()> { + let valid = id.len() > 1 + && id.chars().next().unwrap().is_alphanumeric() + && id + .chars() + .all(|c| (c.is_alphanumeric() || ['.', '-', '_'].contains(&c))); + + match valid { + true => Ok(()), + false => Err(anyhow!("invalid container ID: {:?}", id)), + } +} + impl AgentService { async fn do_create_container( &self, @@ -87,6 +104,8 @@ impl AgentService { ) -> Result<()> { let cid = req.container_id.clone(); + let _ = verify_cid(&cid)?; + let mut oci_spec = req.OCI.clone(); let use_sandbox_pidns = req.get_sandbox_pidns(); @@ -1773,4 +1792,231 @@ mod tests { assert!(result.is_err(), "expected add arp neighbors to fail"); } + + #[tokio::test] + async fn test_verify_cid() { + #[derive(Debug)] + struct TestData<'a> { + id: &'a str, + expect_error: bool, + } + + let tests = &[ + TestData { + // Cannot be blank + id: "", + expect_error: true, + }, + TestData { + // Cannot be a space + id: " ", + expect_error: true, + }, + TestData { + // Must start with an alphanumeric + id: ".", + expect_error: true, + }, + TestData { + // Must start with an alphanumeric + id: "-", + expect_error: true, + }, + TestData { + // Must start with an alphanumeric + id: "_", + expect_error: true, + }, + TestData { + // Must start with an alphanumeric + id: " a", + expect_error: true, + }, + TestData { + // Must start with an alphanumeric + id: ".a", + expect_error: true, + }, + TestData { + // Must start with an alphanumeric + id: "-a", + expect_error: true, + }, + TestData { + // Must start with an alphanumeric + id: "_a", + expect_error: true, + }, + TestData { + // Must start with an alphanumeric + id: "..", + expect_error: true, + }, + TestData { + // Too short + id: "a", + expect_error: true, + }, + TestData { + // Too short + id: "z", + expect_error: true, + }, + TestData { + // Too short + id: "A", + expect_error: true, + }, + TestData { + // Too short + id: "Z", + expect_error: true, + }, + TestData { + // Too short + id: "0", + expect_error: true, + }, + TestData { + // Too short + id: "9", + expect_error: true, + }, + TestData { + // Must start with an alphanumeric + id: "-1", + expect_error: true, + }, + TestData { + id: "/", + expect_error: true, + }, + TestData { + id: "a/", + expect_error: true, + }, + TestData { + id: "a/../", + expect_error: true, + }, + TestData { + id: "../a", + expect_error: true, + }, + TestData { + id: "../../a", + expect_error: true, + }, + TestData { + id: "../../../a", + expect_error: true, + }, + TestData { + id: "foo/../bar", + expect_error: true, + }, + TestData { + id: "foo bar", + expect_error: true, + }, + TestData { + id: "a.", + expect_error: false, + }, + TestData { + id: "a..", + expect_error: false, + }, + TestData { + id: "aa", + expect_error: false, + }, + TestData { + id: "aa.", + expect_error: false, + }, + TestData { + id: "hello..world", + expect_error: false, + }, + TestData { + id: "hello/../world", + expect_error: true, + }, + TestData { + id: "aa1245124sadfasdfgasdga.", + expect_error: false, + }, + TestData { + id: "aAzZ0123456789_.-", + expect_error: false, + }, + TestData { + id: "abcdefghijklmnopqrstuvwxyz0123456789.-_", + expect_error: false, + }, + TestData { + id: "0123456789abcdefghijklmnopqrstuvwxyz.-_", + expect_error: false, + }, + TestData { + id: " abcdefghijklmnopqrstuvwxyz0123456789.-_", + expect_error: true, + }, + TestData { + id: ".abcdefghijklmnopqrstuvwxyz0123456789.-_", + expect_error: true, + }, + TestData { + id: "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_", + expect_error: false, + }, + TestData { + id: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.-_", + expect_error: false, + }, + TestData { + id: " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_", + expect_error: true, + }, + TestData { + id: ".ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_", + expect_error: true, + }, + TestData { + id: "/a/b/c", + expect_error: true, + }, + TestData { + id: "a/b/c", + expect_error: true, + }, + TestData { + id: "foo/../../../etc/passwd", + expect_error: true, + }, + TestData { + id: "../../../../../../etc/motd", + expect_error: true, + }, + TestData { + id: "/etc/passwd", + expect_error: true, + }, + ]; + + for (i, d) in tests.iter().enumerate() { + let msg = format!("test[{}]: {:?}", i, d); + + let result = verify_cid(d.id); + + let msg = format!("{}, result: {:?}", msg, result); + + if result.is_ok() { + assert!(!d.expect_error, msg); + } else { + assert!(d.expect_error, msg); + } + } + } }