mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-04-30 20:54:26 +00:00
agent: add tests for is_signal_handled function
Add test coverage for is_signal_handled function in rpc.rs. Includes refactors to make the function testable and handle additional cases. Fixes #3939 Signed-off-by: Braden Rayhorn <bradenrayhorn@fastmail.com>
This commit is contained in:
parent
698e45f403
commit
c3776b1792
@ -407,7 +407,8 @@ impl AgentService {
|
|||||||
// For container initProcess, if it hasn't installed handler for "SIGTERM" signal,
|
// For container initProcess, if it hasn't installed handler for "SIGTERM" signal,
|
||||||
// it will ignore the "SIGTERM" signal sent to it, thus send it "SIGKILL" signal
|
// it will ignore the "SIGTERM" signal sent to it, thus send it "SIGKILL" signal
|
||||||
// instead of "SIGTERM" to terminate it.
|
// instead of "SIGTERM" to terminate it.
|
||||||
if p.init && sig == libc::SIGTERM && !is_signal_handled(p.pid, sig as u32) {
|
let proc_status_file = format!("/proc/{}/status", p.pid);
|
||||||
|
if p.init && sig == libc::SIGTERM && !is_signal_handled(&proc_status_file, sig as u32) {
|
||||||
sig = libc::SIGKILL;
|
sig = libc::SIGKILL;
|
||||||
}
|
}
|
||||||
p.signal(sig)?;
|
p.signal(sig)?;
|
||||||
@ -1635,21 +1636,33 @@ fn append_guest_hooks(s: &Sandbox, oci: &mut Spec) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check is the container process installed the
|
// Check if the container process installed the
|
||||||
// handler for specific signal.
|
// handler for specific signal.
|
||||||
fn is_signal_handled(pid: pid_t, signum: u32) -> bool {
|
fn is_signal_handled(proc_status_file: &str, signum: u32) -> bool {
|
||||||
let sig_mask: u64 = 1u64 << (signum - 1);
|
let shift_count: u64 = if signum == 0 {
|
||||||
let file_name = format!("/proc/{}/status", pid);
|
// signum 0 is used to check for process liveness.
|
||||||
|
// Since that signal is not part of the mask in the file, we only need
|
||||||
|
// to know if the file (and therefore) process exists to handle
|
||||||
|
// that signal.
|
||||||
|
return fs::metadata(proc_status_file).is_ok();
|
||||||
|
} else if signum > 64 {
|
||||||
|
// Ensure invalid signum won't break bit shift logic
|
||||||
|
warn!(sl!(), "received invalid signum {}", signum);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
(signum - 1).into()
|
||||||
|
};
|
||||||
|
|
||||||
// Open the file in read-only mode (ignoring errors).
|
// Open the file in read-only mode (ignoring errors).
|
||||||
let file = match File::open(&file_name) {
|
let file = match File::open(proc_status_file) {
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
warn!(sl!(), "failed to open file {}\n", file_name);
|
warn!(sl!(), "failed to open file {}", proc_status_file);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let sig_mask: u64 = 1 << shift_count;
|
||||||
let reader = BufReader::new(file);
|
let reader = BufReader::new(file);
|
||||||
|
|
||||||
// Read the file line by line using the lines() iterator from std::io::BufRead.
|
// Read the file line by line using the lines() iterator from std::io::BufRead.
|
||||||
@ -1657,21 +1670,21 @@ fn is_signal_handled(pid: pid_t, signum: u32) -> bool {
|
|||||||
let line = match line {
|
let line = match line {
|
||||||
Ok(l) => l,
|
Ok(l) => l,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
warn!(sl!(), "failed to read file {}\n", file_name);
|
warn!(sl!(), "failed to read file {}", proc_status_file);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if line.starts_with("SigCgt:") {
|
if line.starts_with("SigCgt:") {
|
||||||
let mask_vec: Vec<&str> = line.split(':').collect();
|
let mask_vec: Vec<&str> = line.split(':').collect();
|
||||||
if mask_vec.len() != 2 {
|
if mask_vec.len() != 2 {
|
||||||
warn!(sl!(), "parse the SigCgt field failed\n");
|
warn!(sl!(), "parse the SigCgt field failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let sig_cgt_str = mask_vec[1];
|
let sig_cgt_str = mask_vec[1];
|
||||||
let sig_cgt_mask = match u64::from_str_radix(sig_cgt_str, 16) {
|
let sig_cgt_mask = match u64::from_str_radix(sig_cgt_str, 16) {
|
||||||
Ok(h) => h,
|
Ok(h) => h,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
warn!(sl!(), "failed to parse the str {} to hex\n", sig_cgt_str);
|
warn!(sl!(), "failed to parse the str {} to hex", sig_cgt_str);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -2305,6 +2318,102 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_is_signal_handled() {
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct TestData<'a> {
|
||||||
|
status_file_data: Option<&'a str>,
|
||||||
|
signum: u32,
|
||||||
|
result: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
let tests = &[
|
||||||
|
TestData {
|
||||||
|
status_file_data: Some(
|
||||||
|
r#"
|
||||||
|
SigBlk:0000000000010000
|
||||||
|
SigCgt:0000000000000001
|
||||||
|
OtherField:other
|
||||||
|
"#,
|
||||||
|
),
|
||||||
|
signum: 1,
|
||||||
|
result: true,
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
status_file_data: Some("SigCgt:000000004b813efb"),
|
||||||
|
signum: 4,
|
||||||
|
result: true,
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
status_file_data: Some("SigCgt:000000004b813efb"),
|
||||||
|
signum: 3,
|
||||||
|
result: false,
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
status_file_data: Some("SigCgt:000000004b813efb"),
|
||||||
|
signum: 65,
|
||||||
|
result: false,
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
status_file_data: Some("SigCgt:000000004b813efb"),
|
||||||
|
signum: 0,
|
||||||
|
result: true,
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
status_file_data: Some("SigCgt:ZZZZZZZZ"),
|
||||||
|
signum: 1,
|
||||||
|
result: false,
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
status_file_data: Some("SigCgt:-1"),
|
||||||
|
signum: 1,
|
||||||
|
result: false,
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
status_file_data: Some("SigCgt"),
|
||||||
|
signum: 1,
|
||||||
|
result: false,
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
status_file_data: Some("any data"),
|
||||||
|
signum: 0,
|
||||||
|
result: true,
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
status_file_data: Some("SigBlk:0000000000000001"),
|
||||||
|
signum: 1,
|
||||||
|
result: false,
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
status_file_data: None,
|
||||||
|
signum: 1,
|
||||||
|
result: false,
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
status_file_data: None,
|
||||||
|
signum: 0,
|
||||||
|
result: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for (i, d) in tests.iter().enumerate() {
|
||||||
|
let msg = format!("test[{}]: {:?}", i, d);
|
||||||
|
|
||||||
|
let dir = tempdir().expect("failed to make tempdir");
|
||||||
|
let proc_status_file_path = dir.path().join("status");
|
||||||
|
|
||||||
|
if let Some(file_data) = d.status_file_data {
|
||||||
|
fs::write(&proc_status_file_path, file_data).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = is_signal_handled(proc_status_file_path.to_str().unwrap(), d.signum);
|
||||||
|
|
||||||
|
let msg = format!("{}, result: {:?}", msg, result);
|
||||||
|
|
||||||
|
assert_eq!(d.result, result, "{}", msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_verify_cid() {
|
async fn test_verify_cid() {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
Loading…
Reference in New Issue
Block a user