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/gpu/host1x/mipi.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/gpu/host1x/mipi.c')
| -rw-r--r-- | drivers/gpu/host1x/mipi.c | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/drivers/gpu/host1x/mipi.c b/drivers/gpu/host1x/mipi.c new file mode 100644 index 000000000..988681423 --- /dev/null +++ b/drivers/gpu/host1x/mipi.c @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 NVIDIA Corporation + * Copyright (C) 2025 Svyatoslav Ryhel <clamor95@gmail.com> + */ + +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/tegra-mipi-cal.h> + +/* only need to support one provider */ +static struct { + struct device_node *np; + const struct tegra_mipi_ops *ops; +} provider; + +/** + * tegra_mipi_enable - Enable the Tegra MIPI calibration device. + * @device: Handle to the Tegra MIPI calibration device. + * + * This calls the enable sequence for the Tegra MIPI calibration device. + * + * Returns 0 on success or a negative error code on failure. + */ +int tegra_mipi_enable(struct tegra_mipi_device *device) +{ + if (device->ops->enable) + return device->ops->enable(device); + + return 0; +} +EXPORT_SYMBOL(tegra_mipi_enable); + +/** + * tegra_mipi_disable - Disable the Tegra MIPI calibration device. + * @device: Handle to the Tegra MIPI calibration device. + * + * This calls the disable sequence for the Tegra MIPI calibration device. + * + * Returns 0 on success or a negative error code on failure. + */ +int tegra_mipi_disable(struct tegra_mipi_device *device) +{ + if (device->ops->disable) + return device->ops->disable(device); + + return 0; +} +EXPORT_SYMBOL(tegra_mipi_disable); + +/** + * tegra_mipi_start_calibration - Start the Tegra MIPI calibration sequence. + * @device: Handle to the Tegra MIPI calibration device. + * + * This initiates the calibration of CSI/DSI interfaces via the Tegra MIPI + * calibration device. + * + * Returns 0 on success or a negative error code on failure. + */ +int tegra_mipi_start_calibration(struct tegra_mipi_device *device) +{ + if (device->ops->start_calibration) + return device->ops->start_calibration(device); + + return 0; +} +EXPORT_SYMBOL(tegra_mipi_start_calibration); + +/** + * tegra_mipi_finish_calibration - Finish the Tegra MIPI calibration sequence. + * @device: Handle to the Tegra MIPI calibration device. + * + * This completes the calibration of CSI/DSI interfaces via the Tegra MIPI + * calibration device. + * + * Returns 0 on success or a negative error code on failure. + */ +int tegra_mipi_finish_calibration(struct tegra_mipi_device *device) +{ + if (device->ops->finish_calibration) + return device->ops->finish_calibration(device); + + return 0; +} +EXPORT_SYMBOL(tegra_mipi_finish_calibration); + +/** + * tegra_mipi_request - Request a Tegra MIPI calibration device. + * @device: Handle of the device requesting the MIPI calibration function. + * @np: Device node pointer of the device requesting the MIPI calibration + * function. + * + * This function requests a reference to a Tegra MIPI calibration device. + * + * Returns a pointer to the Tegra MIPI calibration device on success, + * or an ERR_PTR-encoded error code on failure. + */ +struct tegra_mipi_device *tegra_mipi_request(struct device *device, + struct device_node *np) +{ + struct tegra_mipi_device *mipidev; + struct of_phandle_args args; + int err; + + err = of_parse_phandle_with_args(np, "nvidia,mipi-calibrate", + "#nvidia,mipi-calibrate-cells", 0, + &args); + if (err < 0) + return ERR_PTR(err); + + if (provider.np != args.np) { + err = -ENODEV; + goto out; + } + + mipidev = kzalloc_obj(*mipidev); + if (!mipidev) { + err = -ENOMEM; + goto out; + } + + mipidev->pdev = of_find_device_by_node(args.np); + if (!mipidev->pdev) { + err = -ENODEV; + goto free; + } + + of_node_put(args.np); + + mipidev->ops = provider.ops; + mipidev->pads = args.args[0]; + + return mipidev; + +free: + kfree(mipidev); +out: + of_node_put(args.np); + return ERR_PTR(err); +} +EXPORT_SYMBOL(tegra_mipi_request); + +/** + * tegra_mipi_free - Free a Tegra MIPI calibration device. + * @mipidev: Handle to the Tegra MIPI calibration device. + * + * This function releases a reference to a Tegra MIPI calibration device + * previously requested by tegra_mipi_request(). + */ +void tegra_mipi_free(struct tegra_mipi_device *mipidev) +{ + platform_device_put(mipidev->pdev); + kfree(mipidev); +} +EXPORT_SYMBOL(tegra_mipi_free); + +static void tegra_mipi_remove_provider(void *data) +{ + provider.np = NULL; + provider.ops = NULL; +} + +/** + * devm_tegra_mipi_add_provider - Managed registration of a Tegra MIPI + * calibration function provider. + * @device: Handle to the device providing the MIPI calibration function. + * @np: Device node pointer of the device providing the MIPI calibration + * function. + * @ops: Operations supported by the MIPI calibration device. + * + * This registers a device that provides MIPI calibration functions. + * For Tegra20 and Tegra30, this is the CSI block, while Tegra114 and + * newer SoC generations have a dedicated hardware block for these + * functions. + * + * Returns 0 on success or a negative error code on failure. + */ +int devm_tegra_mipi_add_provider(struct device *device, struct device_node *np, + const struct tegra_mipi_ops *ops) +{ + if (provider.np) + return -EBUSY; + + provider.np = np; + provider.ops = ops; + + return devm_add_action_or_reset(device, tegra_mipi_remove_provider, NULL); +} +EXPORT_SYMBOL(devm_tegra_mipi_add_provider); |
