diff options
| author | Ali Ahmet Memis <ali@iusegentoo.com> | 2026-08-21 01:45:27 +0000 |
|---|---|---|
| committer | Stafford Horne <shorne@gmail.com> | 2026-08-29 07:32:26 +0100 |
| commit | 78004e9a87f240df03e2f73120d291763c32e0a7 (patch) | |
| tree | 137c22dd795222931b9d2bf2501d37cd766741aa /drivers/acpi/thermal_lib.c | |
| download | linux-stable-78004e9a87f240df03e2f73120d291763c32e0a7.tar.gz linux-stable-78004e9a87f240df03e2f73120d291763c32e0a7.zip | |
openrisc: fix arbitrary kernel memory access via or1k_atomic syscallgrafted
sys_or1k_atomic() (syscall 244 in the "or1k" ABI) takes two user
pointers, v1 and v2, and swaps the words they point to in hand-written
assembly.
l.lwz r29,0(r4)
l.lwz r27,0(r5)
l.sw 0(r4),r27
l.sw 0(r5),r29
The pointers are not checked with access_ok(). The four memory
accesses also have no exception table entries.
A caller passes a kernel address as either pointer, and the syscall
reads from and writes to it directly.
This gives an unprivileged process a kernel read/write primitive. It
overwrites kernel data such as the sys_call_table, gaining code
execution in kernel context.
Check both pointers before entering the critical section. Add fixups
for the four memory accesses so faults on valid but unmapped user
addresses return -EFAULT.
[shorne@gmail.com: fix comment style]
Fixes: 9d02a4283e9c ("OpenRISC: Boot code")
Cc: stable@vger.kernel.org
Signed-off-by: Ali Ahmet Memis <ali@iusegentoo.com>
Signed-off-by: Stafford Horne <shorne@gmail.com>
Diffstat (limited to 'drivers/acpi/thermal_lib.c')
| -rw-r--r-- | drivers/acpi/thermal_lib.c | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/drivers/acpi/thermal_lib.c b/drivers/acpi/thermal_lib.c new file mode 100644 index 000000000..f81591927 --- /dev/null +++ b/drivers/acpi/thermal_lib.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2023 Linaro Limited + * Copyright 2023 Intel Corporation + * + * Library routines for retrieving trip point temperature values from the + * platform firmware via ACPI. + */ +#include <linux/acpi.h> +#include <linux/units.h> +#include <linux/thermal.h> +#include "internal.h" + +/* + * Minimum temperature for full military grade is 218°K (-55°C) and + * max temperature is 448°K (175°C). We can consider those values as + * the boundaries for the [trips] temperature returned by the + * firmware. Any values out of these boundaries may be considered + * bogus and we can assume the firmware has no data to provide. + */ +#define TEMP_MIN_DECIK 2180ULL +#define TEMP_MAX_DECIK 4480ULL + +static int acpi_trip_temp(struct acpi_device *adev, char *obj_name, + int *ret_temp) +{ + unsigned long long temp; + acpi_status status; + + status = acpi_evaluate_integer(adev->handle, obj_name, NULL, &temp); + if (ACPI_FAILURE(status)) { + acpi_handle_debug(adev->handle, "%s evaluation failed\n", obj_name); + return -ENODATA; + } + + if (temp >= TEMP_MIN_DECIK && temp <= TEMP_MAX_DECIK) { + *ret_temp = temp; + } else { + acpi_handle_debug(adev->handle, "%s result %llu out of range\n", + obj_name, temp); + *ret_temp = THERMAL_TEMP_INVALID; + } + + return 0; +} + +int acpi_active_trip_temp(struct acpi_device *adev, int id, int *ret_temp) +{ + char obj_name[] = {'_', 'A', 'C', '0' + id, '\0'}; + + if (id < 0 || id > 9) + return -EINVAL; + + return acpi_trip_temp(adev, obj_name, ret_temp); +} +EXPORT_SYMBOL_NS_GPL(acpi_active_trip_temp, "ACPI_THERMAL"); + +int acpi_passive_trip_temp(struct acpi_device *adev, int *ret_temp) +{ + return acpi_trip_temp(adev, "_PSV", ret_temp); +} +EXPORT_SYMBOL_NS_GPL(acpi_passive_trip_temp, "ACPI_THERMAL"); + +int acpi_hot_trip_temp(struct acpi_device *adev, int *ret_temp) +{ + return acpi_trip_temp(adev, "_HOT", ret_temp); +} +EXPORT_SYMBOL_NS_GPL(acpi_hot_trip_temp, "ACPI_THERMAL"); + +int acpi_critical_trip_temp(struct acpi_device *adev, int *ret_temp) +{ + return acpi_trip_temp(adev, "_CRT", ret_temp); +} +EXPORT_SYMBOL_NS_GPL(acpi_critical_trip_temp, "ACPI_THERMAL"); + +static int thermal_temp(int error, int temp_decik, int *ret_temp) +{ + if (error) + return error; + + if (temp_decik == THERMAL_TEMP_INVALID) + *ret_temp = THERMAL_TEMP_INVALID; + else + *ret_temp = deci_kelvin_to_millicelsius(temp_decik); + + return 0; +} + +/** + * thermal_acpi_active_trip_temp - Retrieve active trip point temperature + * @adev: Target thermal zone ACPI device object. + * @id: Active cooling level (0 - 9). + * @ret_temp: Address to store the retrieved temperature value on success. + * + * Evaluate the _ACx object for the thermal zone represented by @adev to obtain + * the temperature of the active cooling trip point corresponding to the active + * cooling level given by @id. + * + * Return 0 on success or a negative error value on failure. + */ +int thermal_acpi_active_trip_temp(struct acpi_device *adev, int id, int *ret_temp) +{ + int temp_decik = 0; + int ret = acpi_active_trip_temp(adev, id, &temp_decik); + + return thermal_temp(ret, temp_decik, ret_temp); +} +EXPORT_SYMBOL_GPL(thermal_acpi_active_trip_temp); + +/** + * thermal_acpi_passive_trip_temp - Retrieve passive trip point temperature + * @adev: Target thermal zone ACPI device object. + * @ret_temp: Address to store the retrieved temperature value on success. + * + * Evaluate the _PSV object for the thermal zone represented by @adev to obtain + * the temperature of the passive cooling trip point. + * + * Return 0 on success or -ENODATA on failure. + */ +int thermal_acpi_passive_trip_temp(struct acpi_device *adev, int *ret_temp) +{ + int temp_decik = 0; + int ret = acpi_passive_trip_temp(adev, &temp_decik); + + return thermal_temp(ret, temp_decik, ret_temp); +} +EXPORT_SYMBOL_GPL(thermal_acpi_passive_trip_temp); + +/** + * thermal_acpi_hot_trip_temp - Retrieve hot trip point temperature + * @adev: Target thermal zone ACPI device object. + * @ret_temp: Address to store the retrieved temperature value on success. + * + * Evaluate the _HOT object for the thermal zone represented by @adev to obtain + * the temperature of the trip point at which the system is expected to be put + * into the S4 sleep state. + * + * Return 0 on success or -ENODATA on failure. + */ +int thermal_acpi_hot_trip_temp(struct acpi_device *adev, int *ret_temp) +{ + int temp_decik = 0; + int ret = acpi_hot_trip_temp(adev, &temp_decik); + + return thermal_temp(ret, temp_decik, ret_temp); +} +EXPORT_SYMBOL_GPL(thermal_acpi_hot_trip_temp); + +/** + * thermal_acpi_critical_trip_temp - Retrieve critical trip point temperature + * @adev: Target thermal zone ACPI device object. + * @ret_temp: Address to store the retrieved temperature value on success. + * + * Evaluate the _CRT object for the thermal zone represented by @adev to obtain + * the temperature of the critical cooling trip point. + * + * Return 0 on success or -ENODATA on failure. + */ +int thermal_acpi_critical_trip_temp(struct acpi_device *adev, int *ret_temp) +{ + int temp_decik = 0; + int ret = acpi_critical_trip_temp(adev, &temp_decik); + + return thermal_temp(ret, temp_decik, ret_temp); +} +EXPORT_SYMBOL_GPL(thermal_acpi_critical_trip_temp); |
