From c66b56683beb63b34f98d418f3f3e13b0aa2097e Mon Sep 17 00:00:00 2001 From: Manabu Sugimoto Date: Wed, 3 Nov 2021 21:38:15 +0900 Subject: [PATCH 1/2] agent: Ignore unknown seccomp system calls If Kata agent cannot resolve the system calls given by seccomp profiles, the agent ignores the system calls and continues to run without an error. Fixes: #2957 Signed-off-by: Manabu Sugimoto --- src/agent/rustjail/src/seccomp.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/agent/rustjail/src/seccomp.rs b/src/agent/rustjail/src/seccomp.rs index 58e85c482f..75d938f25e 100644 --- a/src/agent/rustjail/src/seccomp.rs +++ b/src/agent/rustjail/src/seccomp.rs @@ -68,7 +68,14 @@ pub fn init_seccomp(scmp: &LinuxSeccomp) -> Result<()> { } for name in &syscall.names { - let syscall_num = get_syscall_from_name(name, None)?; + let syscall_num = match get_syscall_from_name(name, None) { + Ok(num) => num, + Err(_) => { + // If we cannot resolve the given system call, we assume it is not supported + // by the kernel. Hence, we skip it without generating an error. + continue; + } + }; if syscall.args.is_empty() { filter.add_rule(action, syscall_num, None)?; From 7b35615191939ea302fd7321b0f4f5f018719b70 Mon Sep 17 00:00:00 2001 From: Manabu Sugimoto Date: Fri, 5 Nov 2021 21:00:03 +0900 Subject: [PATCH 2/2] agent: Log unknown seccomp system calls Kata agent logs unknown system calls given by seccomp profiles in advance before the log file descriptor closes. Fixes: #2957 Signed-off-by: Manabu Sugimoto --- src/agent/rustjail/src/container.rs | 8 ++ src/agent/rustjail/src/seccomp.rs | 158 ++++++++++++++++------------ 2 files changed, 101 insertions(+), 65 deletions(-) diff --git a/src/agent/rustjail/src/container.rs b/src/agent/rustjail/src/container.rs index 03ad662872..62d23fe5db 100644 --- a/src/agent/rustjail/src/container.rs +++ b/src/agent/rustjail/src/container.rs @@ -600,6 +600,14 @@ fn do_init_child(cwfd: RawFd) -> Result<()> { capctl::prctl::set_no_new_privs().map_err(|_| anyhow!("cannot set no new privileges"))?; } + // Log unknown seccomp system calls in advance before the log file descriptor closes. + #[cfg(feature = "seccomp")] + if let Some(ref scmp) = linux.seccomp { + if let Some(syscalls) = seccomp::get_unknown_syscalls(scmp) { + log_child!(cfd_log, "unknown seccomp system calls: {:?}", syscalls); + } + } + // Without NoNewPrivileges, we need to set seccomp // before dropping capabilities because the calling thread // must have the CAP_SYS_ADMIN. diff --git a/src/agent/rustjail/src/seccomp.rs b/src/agent/rustjail/src/seccomp.rs index 75d938f25e..3496a45d8a 100644 --- a/src/agent/rustjail/src/seccomp.rs +++ b/src/agent/rustjail/src/seccomp.rs @@ -39,6 +39,24 @@ fn get_rule_conditions(args: &[LinuxSeccompArg]) -> Result> Ok(conditions) } +pub fn get_unknown_syscalls(scmp: &LinuxSeccomp) -> Option> { + let mut unknown_syscalls: Vec = Vec::new(); + + for syscall in &scmp.syscalls { + for name in &syscall.names { + if get_syscall_from_name(name, None).is_err() { + unknown_syscalls.push(name.to_string()); + } + } + } + + if unknown_syscalls.is_empty() { + None + } else { + Some(unknown_syscalls) + } +} + // init_seccomp creates a seccomp filter and loads it for the current process // including all the child processes. pub fn init_seccomp(scmp: &LinuxSeccomp) -> Result<()> { @@ -116,6 +134,72 @@ mod tests { }; } + const TEST_DATA: &str = r#"{ + "defaultAction": "SCMP_ACT_ALLOW", + "architectures": [ + ], + "flags": [ + "SECCOMP_FILTER_FLAG_LOG" + ], + "syscalls": [ + { + "names": [ + "dup3", + "invalid_syscall1", + "invalid_syscall2" + ], + "action": "SCMP_ACT_ERRNO" + }, + { + "names": [ + "process_vm_readv" + ], + "action": "SCMP_ACT_ERRNO", + "errnoRet": 111, + "args": [ + { + "index": 0, + "value": 10, + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "process_vm_readv" + ], + "action": "SCMP_ACT_ERRNO", + "errnoRet": 111, + "args": [ + { + "index": 0, + "value": 20, + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "process_vm_readv" + ], + "action": "SCMP_ACT_ERRNO", + "errnoRet": 222, + "args": [ + { + "index": 0, + "value": 30, + "op": "SCMP_CMP_EQ" + }, + { + "index": 2, + "value": 40, + "op": "SCMP_CMP_EQ" + } + ] + } + ] + }"#; + #[test] fn test_get_filter_attr_from_flag() { skip_if_not_root!(); @@ -128,75 +212,19 @@ mod tests { assert_eq!(get_filter_attr_from_flag("ERROR").is_err(), true); } + #[test] + fn test_get_unknown_syscalls() { + let scmp: oci::LinuxSeccomp = serde_json::from_str(TEST_DATA).unwrap(); + let syscalls = get_unknown_syscalls(&scmp).unwrap(); + + assert_eq!(syscalls, vec!["invalid_syscall1", "invalid_syscall2"]); + } + #[test] fn test_init_seccomp() { skip_if_not_root!(); - let data = r#"{ - "defaultAction": "SCMP_ACT_ALLOW", - "architectures": [ - ], - "flags": [ - "SECCOMP_FILTER_FLAG_LOG" - ], - "syscalls": [ - { - "names": [ - "dup3" - ], - "action": "SCMP_ACT_ERRNO" - }, - { - "names": [ - "process_vm_readv" - ], - "action": "SCMP_ACT_ERRNO", - "errnoRet": 111, - "args": [ - { - "index": 0, - "value": 10, - "op": "SCMP_CMP_EQ" - } - ] - }, - { - "names": [ - "process_vm_readv" - ], - "action": "SCMP_ACT_ERRNO", - "errnoRet": 111, - "args": [ - { - "index": 0, - "value": 20, - "op": "SCMP_CMP_EQ" - } - ] - }, - { - "names": [ - "process_vm_readv" - ], - "action": "SCMP_ACT_ERRNO", - "errnoRet": 222, - "args": [ - { - "index": 0, - "value": 30, - "op": "SCMP_CMP_EQ" - }, - { - "index": 2, - "value": 40, - "op": "SCMP_CMP_EQ" - } - ] - } - ] - }"#; - - let mut scmp: oci::LinuxSeccomp = serde_json::from_str(data).unwrap(); + let mut scmp: oci::LinuxSeccomp = serde_json::from_str(TEST_DATA).unwrap(); let mut arch: Vec; if cfg!(target_endian = "little") {