diff --git a/src/agent/rustjail/src/container.rs b/src/agent/rustjail/src/container.rs index e4ac711e7d..afee028408 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 58e85c482f..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<()> { @@ -68,7 +86,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)?; @@ -109,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!(); @@ -121,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") {