diff --git a/changelog.d/2988.fixed.md b/changelog.d/2988.fixed.md new file mode 100644 index 00000000000..95b7074d056 --- /dev/null +++ b/changelog.d/2988.fixed.md @@ -0,0 +1 @@ +Fixed panic when Go >=1.23.3 verifies pidfd support on Linux. \ No newline at end of file diff --git a/mirrord/layer/src/go/linux_x64.rs b/mirrord/layer/src/go/linux_x64.rs index dcabdeee4b7..5acaceb13b2 100644 --- a/mirrord/layer/src/go/linux_x64.rs +++ b/mirrord/layer/src/go/linux_x64.rs @@ -393,6 +393,10 @@ unsafe extern "C" fn c_abi_syscall_handler( #[naked] unsafe extern "C" fn go_syscall_new_detour() { naked_asm!( + "cmp rax, 60", // SYS_EXIT + "je 4f", + "cmp rax, 231", // SYS_EXIT_GROUP + "je 4f", // Save rdi in r10 "mov r10, rdi", // Save r9 in r11 @@ -489,7 +493,14 @@ unsafe extern "C" fn go_syscall_new_detour() { "mov rcx, 0x0", "xorps xmm15, xmm15", "mov r14, QWORD PTR FS:[0xfffffff8]", - "ret" + "ret", + // just execute syscall instruction + // This is for SYS_EXIT and SYS_EXIT_GROUP only - we know for sure that it's safe to just + // let it happen. Running our code is an unnecessary risk due to switching between + // stacks. See issue https://github.com/metalbear-co/mirrord/issues/2988. + "4:", + "mov rdx, rdi", + "syscall", ) } diff --git a/mirrord/layer/tests/apps/issue2988/go.mod b/mirrord/layer/tests/apps/issue2988/go.mod new file mode 100644 index 00000000000..23dfcec9c48 --- /dev/null +++ b/mirrord/layer/tests/apps/issue2988/go.mod @@ -0,0 +1,3 @@ +module issue2988 + +go 1.23.4 diff --git a/mirrord/layer/tests/apps/issue2988/main.go b/mirrord/layer/tests/apps/issue2988/main.go new file mode 100644 index 00000000000..b2d78724dc3 --- /dev/null +++ b/mirrord/layer/tests/apps/issue2988/main.go @@ -0,0 +1,13 @@ +package main + +import ( + _ "net" + "os" +) + +func main() { + _, err := os.FindProcess(os.Getpid()) + if err != nil { + panic(err) + } +} diff --git a/mirrord/layer/tests/common/mod.rs b/mirrord/layer/tests/common/mod.rs index 819dce2fe14..22945790e4b 100644 --- a/mirrord/layer/tests/common/mod.rs +++ b/mirrord/layer/tests/common/mod.rs @@ -784,6 +784,8 @@ pub enum Application { }, // For running applications with the executable and arguments determined at runtime. DynamicApp(String, Vec), + // Go app that only checks whether Linux pidfd syscalls are supported. + Go23Issue2988, } impl Application { @@ -958,6 +960,7 @@ impl Application { Application::RustIssue2204 => String::from("tests/apps/issue2204/target/issue2204"), Application::Go23Open { .. } => String::from("tests/apps/open_go/23.go_test_app"), Application::DynamicApp(exe, _) => exe.clone(), + Application::Go23Issue2988 => String::from("tests/apps/issue2988/23.go_test_app"), } } @@ -1081,7 +1084,8 @@ impl Application { | Application::CIssue2178 | Application::RustIssue2204 | Application::RustRebind0 - | Application::RustIssue2438 => vec![], + | Application::RustIssue2438 + | Application::Go23Issue2988 => vec![], Application::RustOutgoingUdp => ["--udp", RUST_OUTGOING_LOCAL, RUST_OUTGOING_PEERS] .into_iter() .map(Into::into) @@ -1175,7 +1179,8 @@ impl Application { | Application::NodeIssue2807 | Application::RustRebind0 | Application::Go23Open { .. } - | Application::DynamicApp(..) => unimplemented!("shouldn't get here"), + | Application::DynamicApp(..) + | Application::Go23Issue2988 => unimplemented!("shouldn't get here"), Application::PythonSelfConnect => 1337, Application::RustIssue2058 => 1234, } diff --git a/mirrord/layer/tests/issue2988.rs b/mirrord/layer/tests/issue2988.rs new file mode 100644 index 00000000000..bce474c7fb0 --- /dev/null +++ b/mirrord/layer/tests/issue2988.rs @@ -0,0 +1,23 @@ +#![feature(assert_matches)] +#![warn(clippy::indexing_slicing)] +use std::{path::Path, time::Duration}; + +use rstest::rstest; + +mod common; + +pub use common::*; + +/// Verify that issue [#2988](https://github.com/metalbear-co/mirrord/issues/2988) is fixed. +#[rstest] +#[tokio::test] +#[timeout(Duration::from_secs(60))] +async fn test_issue2988( + #[values(Application::Go23Issue2988)] application: Application, + dylib_path: &Path, +) { + let (mut test_process, _intproxy) = application + .start_process_with_layer(dylib_path, vec![], None) + .await; + test_process.wait_assert_success().await; +}