From: Katya Orlova e.orlova@ispras.ru
stable inclusion from stable-v6.6.55 commit 0a1741d10da29aa84955ef89ae9a03c4b6038657 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/IAYRAF CVE: CVE-2024-49992
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... 8657
--------------------------------
[ Upstream commit 19dd9780b7ac673be95bf6fd6892a184c9db611f ]
ltdc_load() calls functions drm_crtc_init_with_planes(), drm_universal_plane_init() and drm_encoder_init(). These functions should not be called with parameters allocated with devm_kzalloc() to avoid use-after-free issues [1].
Use allocations managed by the DRM framework.
Found by Linux Verification Center (linuxtesting.org).
[1] https://lore.kernel.org/lkml/u366i76e3qhh3ra5oxrtngjtm2u5lterkekcz6y2jkndhux...
Signed-off-by: Katya Orlova e.orlova@ispras.ru Acked-by: Raphaƫl Gallais-Pou raphael.gallais-pou@foss.st.com Link: https://patchwork.freedesktop.org/patch/msgid/20240216125040.8968-1-e.orlova... Signed-off-by: Raphael Gallais-Pou raphael.gallais-pou@foss.st.com Signed-off-by: Sasha Levin sashal@kernel.org
Conflicts: drivers/gpu/drm/stm/drv.c drivers/gpu/drm/stm/ltdc.c [ context conflicts. ] Signed-off-by: Zhang Kunbo zhangkunbo@huawei.com --- drivers/gpu/drm/stm/drv.c | 3 +- drivers/gpu/drm/stm/ltdc.c | 73 ++++++++++---------------------------- 2 files changed, 20 insertions(+), 56 deletions(-)
diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c index 411103f013e2..76dbc5eeb7f7 100644 --- a/drivers/gpu/drm/stm/drv.c +++ b/drivers/gpu/drm/stm/drv.c @@ -23,6 +23,7 @@ #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> +#include <drm/drm_managed.h>
#include "ltdc.h"
@@ -73,7 +74,7 @@ static int drv_load(struct drm_device *ddev)
DRM_DEBUG("%s\n", __func__);
- ldev = devm_kzalloc(ddev->dev, sizeof(*ldev), GFP_KERNEL); + ldev = drmm_kzalloc(ddev, sizeof(*ldev), GFP_KERNEL); if (!ldev) return -ENOMEM;
diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index 8bc86368069b..4ec540951af8 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -32,6 +32,7 @@ #include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> +#include <drm/drm_managed.h>
#include <video/videomode.h>
@@ -917,7 +918,6 @@ static int ltdc_crtc_verify_crc_source(struct drm_crtc *crtc, }
static const struct drm_crtc_funcs ltdc_crtc_funcs = { - .destroy = drm_crtc_cleanup, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, .reset = drm_atomic_helper_crtc_reset, @@ -930,7 +930,6 @@ static const struct drm_crtc_funcs ltdc_crtc_funcs = { };
static const struct drm_crtc_funcs ltdc_crtc_with_crc_support_funcs = { - .destroy = drm_crtc_cleanup, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, .reset = drm_atomic_helper_crtc_reset, @@ -1130,7 +1129,6 @@ static bool ltdc_plane_format_mod_supported(struct drm_plane *plane, static const struct drm_plane_funcs ltdc_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = drm_plane_cleanup, .reset = drm_atomic_helper_plane_reset, .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, @@ -1156,7 +1154,6 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, u32 formats[NB_PF * 2]; u32 drm_fmt, drm_fmt_no_alpha; const u64 *modifiers = ltdc_format_modifiers; - int ret;
/* Get supported pixel formats */ for (i = 0; i < NB_PF; i++) { @@ -1178,14 +1175,10 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, formats[nb_fmt++] = drm_fmt_no_alpha; }
- plane = devm_kzalloc(dev, sizeof(*plane), GFP_KERNEL); - if (!plane) - return NULL; - - ret = drm_universal_plane_init(ddev, plane, possible_crtcs, - <dc_plane_funcs, formats, nb_fmt, - modifiers, type, NULL); - if (ret < 0) + plane = drmm_universal_plane_alloc(ddev, struct drm_plane, dev, + possible_crtcs, <dc_plane_funcs, formats, + nb_fmt, modifiers, type, NULL); + if (IS_ERR(plane)) return NULL;
drm_plane_helper_add(plane, <dc_plane_helper_funcs); @@ -1195,15 +1188,6 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, return plane; }
-static void ltdc_plane_destroy_all(struct drm_device *ddev) -{ - struct drm_plane *plane, *plane_temp; - - list_for_each_entry_safe(plane, plane_temp, - &ddev->mode_config.plane_list, head) - drm_plane_cleanup(plane); -} - static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) { struct ltdc_device *ldev = ddev->dev_private; @@ -1219,14 +1203,14 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc)
/* Init CRTC according to its hardware features */ if (ldev->caps.crc) - ret = drm_crtc_init_with_planes(ddev, crtc, primary, NULL, - <dc_crtc_with_crc_support_funcs, NULL); + ret = drmm_crtc_init_with_planes(ddev, crtc, primary, NULL, + <dc_crtc_with_crc_support_funcs, NULL); else - ret = drm_crtc_init_with_planes(ddev, crtc, primary, NULL, - <dc_crtc_funcs, NULL); + ret = drmm_crtc_init_with_planes(ddev, crtc, primary, NULL, + <dc_crtc_funcs, NULL); if (ret) { DRM_ERROR("Can not initialize CRTC\n"); - goto cleanup; + return ret; }
drm_crtc_helper_add(crtc, <dc_crtc_helper_funcs); @@ -1240,17 +1224,12 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) for (i = 1; i < ldev->caps.nb_layers; i++) { overlay = ltdc_plane_create(ddev, DRM_PLANE_TYPE_OVERLAY); if (!overlay) { - ret = -ENOMEM; DRM_ERROR("Can not create overlay plane %d\n", i); - goto cleanup; + return -ENOMEM; } }
return 0; - -cleanup: - ltdc_plane_destroy_all(ddev); - return ret; }
/* @@ -1314,23 +1293,19 @@ static int ltdc_encoder_init(struct drm_device *ddev, struct drm_bridge *bridge) struct drm_encoder *encoder; int ret;
- encoder = devm_kzalloc(ddev->dev, sizeof(*encoder), GFP_KERNEL); - if (!encoder) - return -ENOMEM; + encoder = drmm_simple_encoder_alloc(ddev, struct drm_encoder, dev, + DRM_MODE_ENCODER_DPI); + if (IS_ERR(encoder)) + return PTR_ERR(encoder);
encoder->possible_crtcs = CRTC_MASK; encoder->possible_clones = 0; /* No cloning support */
- drm_encoder_init(ddev, encoder, <dc_encoder_funcs, - DRM_MODE_ENCODER_DPI, NULL); - drm_encoder_helper_add(encoder, <dc_encoder_helper_funcs);
ret = drm_bridge_attach(encoder, bridge, NULL, 0); - if (ret) { - drm_encoder_cleanup(encoder); + if (ret) return -EINVAL; - }
DRM_DEBUG_DRIVER("Bridge encoder:%d created\n", encoder->base.id);
@@ -1473,8 +1448,7 @@ int ltdc_load(struct drm_device *ddev) goto err;
if (panel) { - bridge = drm_panel_bridge_add_typed(panel, - DRM_MODE_CONNECTOR_DPI); + bridge = drmm_panel_bridge_add(ddev, panel); if (IS_ERR(bridge)) { DRM_ERROR("panel-bridge endpoint %d\n", i); ret = PTR_ERR(bridge); @@ -1539,7 +1513,7 @@ int ltdc_load(struct drm_device *ddev)
}
- crtc = devm_kzalloc(dev, sizeof(*crtc), GFP_KERNEL); + crtc = drmm_kzalloc(ddev, sizeof(*crtc), GFP_KERNEL); if (!crtc) { DRM_ERROR("Failed to allocate crtc\n"); ret = -ENOMEM; @@ -1571,9 +1545,6 @@ int ltdc_load(struct drm_device *ddev)
return 0; err: - for (i = 0; i < nb_endpoints; i++) - drm_of_panel_bridge_remove(ddev->dev->of_node, 0, i); - clk_disable_unprepare(ldev->pixel_clk);
return ret; @@ -1581,16 +1552,8 @@ int ltdc_load(struct drm_device *ddev)
void ltdc_unload(struct drm_device *ddev) { - struct device *dev = ddev->dev; - int nb_endpoints, i; - DRM_DEBUG_DRIVER("\n");
- nb_endpoints = of_graph_get_endpoint_count(dev->of_node); - - for (i = 0; i < nb_endpoints; i++) - drm_of_panel_bridge_remove(ddev->dev->of_node, 0, i); - pm_runtime_disable(ddev->dev); }