From 05ff4415772bbf32a12a5cf49ba869beb4d70101 Mon Sep 17 00:00:00 2001 From: Ruize Tang <1466040111@qq.com> Date: Mon, 25 Nov 2024 11:44:46 +0800 Subject: [PATCH] Clear `DF` flag during signal handling to conform to x86-64 calling convention --- kernel/src/process/signal/mod.rs | 9 ++++ test/apps/signal_c/Makefile | 4 +- test/apps/signal_c/signal_rflags_df.c | 60 +++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 test/apps/signal_c/signal_rflags_df.c diff --git a/kernel/src/process/signal/mod.rs b/kernel/src/process/signal/mod.rs index 9ae1d0ad..87e905df 100644 --- a/kernel/src/process/signal/mod.rs +++ b/kernel/src/process/signal/mod.rs @@ -218,6 +218,15 @@ pub fn handle_user_signal( } else { user_ctx.set_arguments(sig_num, 0, 0); } + // CPU architecture-dependent logic + cfg_if::cfg_if! { + if #[cfg(target_arch = "x86_64")] { + // Clear `DF` flag for C function entry to conform to x86-64 calling convention. + // Bit 10 is the DF flag. + const X86_RFLAGS_DF: usize = 1 << 10; + user_ctx.general_regs_mut().rflags &= !X86_RFLAGS_DF; + } + } Ok(()) } diff --git a/test/apps/signal_c/Makefile b/test/apps/signal_c/Makefile index cd19ae20..d2ee9780 100644 --- a/test/apps/signal_c/Makefile +++ b/test/apps/signal_c/Makefile @@ -2,4 +2,6 @@ include ../test_common.mk -EXTRA_C_FLAGS := -static +# Removed `-static` to enable dynamic linking. +# Refer to "signal_rflags_df.c" for details on how dynamic linking affects DF flag testing. +EXTRA_C_FLAGS := diff --git a/test/apps/signal_c/signal_rflags_df.c b/test/apps/signal_c/signal_rflags_df.c new file mode 100644 index 00000000..9207b396 --- /dev/null +++ b/test/apps/signal_c/signal_rflags_df.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MPL-2.0 + +#include +#include +#include +#include +#include +#include + +volatile sig_atomic_t signaled = 0; // Volatile to avoid optimization issues + +void read_df_flag_and_assert(int expect) +{ + unsigned long rflags; + asm volatile("pushfq\n\t" // Push the RFLAGS register onto the stack + "popq %0\n\t" // Pop it into a variable + : "=r"(rflags)); // Output constraint + int df = (rflags >> 10) & 1; // The DF flag is the 10th bit of RFLAGS + assert(df == expect); +} + +void sigint_handler(int signum) +{ + read_df_flag_and_assert(0); + signaled = 1; // Update volatile variable to notify main +} + +// A regression test for the DF flag bug fixed in https://github.com/asterinas/asterinas/pull/1638. +// Also checks PR #1637 when dynamically linked. If calling a function from a shared library mapped +// via mmap triggers a page fault and #1637 is not fixed, it may cause kernel panic. +int main() +{ + // Check DF flag in main before setting it + read_df_flag_and_assert(0); + asm volatile("std"); // Set DF flag + read_df_flag_and_assert(1); + + // Set up the SIGINT signal handler + struct sigaction sa; + sa.sa_handler = sigint_handler; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(SIGINT, &sa, NULL); + + // Send SIGINT to itself + if (kill(getpid(), SIGINT) != 0) { + perror("kill"); + _exit(EXIT_FAILURE); + } + + // Wait for the signal handler to update the variable + while (!signaled) { + // Spin until the signal is handled + } + + // Check DF flag in main after signal handling + read_df_flag_and_assert(1); + + _exit(0); // Exit immediately without cleanup because DF is set +}