summaryrefslogtreecommitdiffstats
path: root/drivers/acpi/acpica/exsystem.c
diff options
context:
space:
mode:
authorKumar Kartikeya Dwivedi <memxor@gmail.com>2026-09-04 10:43:19 +0200
committerAlexei Starovoitov <ast@kernel.org>2026-09-04 07:58:36 -0700
commit6668ed271eaefaa63e686bdfbedaeb7b8e492722 (patch)
tree58e8288fead484f6755ad0815fc74c3742663761 /drivers/acpi/acpica/exsystem.c
downloadlinux-stable-6668ed271eaefaa63e686bdfbedaeb7b8e492722.tar.gz
linux-stable-6668ed271eaefaa63e686bdfbedaeb7b8e492722.zip
selftests/bpf: Reject graph kptr use after RCU unlockgrafted
Add a sleepable verifier test that loads a graph-node local kptr in an explicit RCU read-side critical section, then passes its node to bpf_rbtree_remove() after the section ends. Before the verifier fix, the stale NON_OWN_REF flag makes the node look like a live borrowed reference and the program is accepted. After the fix, the pointer is demoted without NON_OWN_REF and the graph kfunc argument is rejected. Also exercise a graph kptr loaded while a spin lock provides implicit RCU protection. The pointer must be invalidated when the lock is released, which guards the required ordering between non-owning-reference invalidation and RCU demotion. Update the existing fault-protected load test state description. The post-unlock pointer no longer carries NON_OWN_REF, but remains readable because the load is rewritten to use BPF_PROBE_MEM. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Link: https://lore.kernel.org/r/20260904084325.52250-7-memxor@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'drivers/acpi/acpica/exsystem.c')
-rw-r--r--drivers/acpi/acpica/exsystem.c280
1 files changed, 280 insertions, 0 deletions
diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c
new file mode 100644
index 000000000..41d6f8f7a
--- /dev/null
+++ b/drivers/acpi/acpica/exsystem.c
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/******************************************************************************
+ *
+ * Module Name: exsystem - Interface to OS services
+ *
+ * Copyright (C) 2000 - 2026, Intel Corp.
+ *
+ *****************************************************************************/
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acinterp.h"
+
+#define _COMPONENT ACPI_EXECUTER
+ACPI_MODULE_NAME("exsystem")
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_system_wait_semaphore
+ *
+ * PARAMETERS: semaphore - Semaphore to wait on
+ * timeout - Max time to wait
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Implements a semaphore wait with a check to see if the
+ * semaphore is available immediately. If it is not, the
+ * interpreter is released before waiting.
+ *
+ ******************************************************************************/
+acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(ex_system_wait_semaphore);
+
+ status = acpi_os_wait_semaphore(semaphore, 1, ACPI_DO_NOT_WAIT);
+ if (ACPI_SUCCESS(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ if (status == AE_TIME) {
+
+ /* We must wait, so unlock the interpreter */
+
+ acpi_ex_exit_interpreter();
+ status = acpi_os_wait_semaphore(semaphore, 1, timeout);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "*** Thread awake after blocking, %s\n",
+ acpi_format_exception(status)));
+
+ /* Reacquire the interpreter */
+
+ acpi_ex_enter_interpreter();
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_system_wait_mutex
+ *
+ * PARAMETERS: mutex - Mutex to wait on
+ * timeout - Max time to wait
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Implements a mutex wait with a check to see if the
+ * mutex is available immediately. If it is not, the
+ * interpreter is released before waiting.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(ex_system_wait_mutex);
+
+ status = acpi_os_acquire_mutex(mutex, ACPI_DO_NOT_WAIT);
+ if (ACPI_SUCCESS(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ if (status == AE_TIME) {
+
+ /* We must wait, so unlock the interpreter */
+
+ acpi_ex_exit_interpreter();
+ status = acpi_os_acquire_mutex(mutex, timeout);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "*** Thread awake after blocking, %s\n",
+ acpi_format_exception(status)));
+
+ /* Reacquire the interpreter */
+
+ acpi_ex_enter_interpreter();
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_system_do_stall
+ *
+ * PARAMETERS: how_long_us - The amount of time to stall,
+ * in microseconds
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Suspend running thread for specified amount of time.
+ * Note: ACPI specification requires that Stall() does not
+ * relinquish the processor, and delays longer than 100 usec
+ * should use Sleep() instead. We allow stalls up to 255 usec
+ * for compatibility with other interpreters and existing BIOSs.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ex_system_do_stall(u32 how_long_us)
+{
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_ENTRY();
+
+ if (how_long_us > 255) {
+ /*
+ * Longer than 255 microseconds, this is an error
+ *
+ * (ACPI specifies 100 usec as max, but this gives some slack in
+ * order to support existing BIOSs)
+ */
+ ACPI_ERROR_ONCE((AE_INFO,
+ "Time parameter is too large (%u)",
+ how_long_us));
+ status = AE_AML_OPERAND_VALUE;
+ } else {
+ if (how_long_us > 100) {
+ ACPI_WARNING_ONCE((AE_INFO,
+ "Time parameter %u us > 100 us violating ACPI spec, please fix the firmware.",
+ how_long_us));
+ }
+ acpi_os_stall(how_long_us);
+ }
+
+ return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_system_do_sleep
+ *
+ * PARAMETERS: how_long_ms - The amount of time to sleep,
+ * in milliseconds
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Sleep the running thread for specified amount of time.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ex_system_do_sleep(u64 how_long_ms)
+{
+ ACPI_FUNCTION_ENTRY();
+
+ /* Since this thread will sleep, we must release the interpreter */
+
+ acpi_ex_exit_interpreter();
+
+ /*
+ * For compatibility with other ACPI implementations and to prevent
+ * accidental deep sleeps, limit the sleep time to something reasonable.
+ */
+ if (how_long_ms > ACPI_MAX_SLEEP) {
+ how_long_ms = ACPI_MAX_SLEEP;
+ }
+
+ acpi_os_sleep(how_long_ms);
+
+ /* And now we must get the interpreter again */
+
+ acpi_ex_enter_interpreter();
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_system_signal_event
+ *
+ * PARAMETERS: obj_desc - The object descriptor for this op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Provides an access point to perform synchronization operations
+ * within the AML.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ex_system_signal_event(union acpi_operand_object * obj_desc)
+{
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE(ex_system_signal_event);
+
+ if (obj_desc) {
+ status =
+ acpi_os_signal_semaphore(obj_desc->event.os_semaphore, 1);
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_system_wait_event
+ *
+ * PARAMETERS: time_desc - The 'time to delay' object descriptor
+ * obj_desc - The object descriptor for this op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Provides an access point to perform synchronization operations
+ * within the AML. This operation is a request to wait for an
+ * event.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_system_wait_event(union acpi_operand_object *time_desc,
+ union acpi_operand_object *obj_desc)
+{
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE(ex_system_wait_event);
+
+ if (obj_desc) {
+ status =
+ acpi_ex_system_wait_semaphore(obj_desc->event.os_semaphore,
+ (u16) time_desc->integer.
+ value);
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_system_reset_event
+ *
+ * PARAMETERS: obj_desc - The object descriptor for this op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Reset an event to a known state.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ex_system_reset_event(union acpi_operand_object *obj_desc)
+{
+ acpi_status status = AE_OK;
+ acpi_semaphore temp_semaphore;
+
+ ACPI_FUNCTION_ENTRY();
+
+ /*
+ * We are going to simply delete the existing semaphore and
+ * create a new one!
+ */
+ status =
+ acpi_os_create_semaphore(ACPI_NO_UNIT_LIMIT, 0, &temp_semaphore);
+ if (ACPI_SUCCESS(status)) {
+ (void)acpi_os_delete_semaphore(obj_desc->event.os_semaphore);
+ obj_desc->event.os_semaphore = temp_semaphore;
+ }
+
+ return (status);
+}