Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/stm: Avoid use-after-free issues with crtc and plane

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/u366i76e3qhh3ra5oxrtngjtm2u5lterkekcz6y2jkndhuxzli@diujon4h7qwb/

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@ispras.ru
Signed-off-by: Raphael Gallais-Pou <raphael.gallais-pou@foss.st.com>

authored by

Katya Orlova and committed by
Raphael Gallais-Pou
19dd9780 fd39730c

+20 -56
+2 -1
drivers/gpu/drm/stm/drv.c
··· 25 25 #include <drm/drm_module.h> 26 26 #include <drm/drm_probe_helper.h> 27 27 #include <drm/drm_vblank.h> 28 + #include <drm/drm_managed.h> 28 29 29 30 #include "ltdc.h" 30 31 ··· 76 75 77 76 DRM_DEBUG("%s\n", __func__); 78 77 79 - ldev = devm_kzalloc(ddev->dev, sizeof(*ldev), GFP_KERNEL); 78 + ldev = drmm_kzalloc(ddev, sizeof(*ldev), GFP_KERNEL); 80 79 if (!ldev) 81 80 return -ENOMEM; 82 81
+18 -55
drivers/gpu/drm/stm/ltdc.c
··· 36 36 #include <drm/drm_probe_helper.h> 37 37 #include <drm/drm_simple_kms_helper.h> 38 38 #include <drm/drm_vblank.h> 39 + #include <drm/drm_managed.h> 39 40 40 41 #include <video/videomode.h> 41 42 ··· 1200 1199 } 1201 1200 1202 1201 static const struct drm_crtc_funcs ltdc_crtc_funcs = { 1203 - .destroy = drm_crtc_cleanup, 1204 1202 .set_config = drm_atomic_helper_set_config, 1205 1203 .page_flip = drm_atomic_helper_page_flip, 1206 1204 .reset = drm_atomic_helper_crtc_reset, ··· 1212 1212 }; 1213 1213 1214 1214 static const struct drm_crtc_funcs ltdc_crtc_with_crc_support_funcs = { 1215 - .destroy = drm_crtc_cleanup, 1216 1215 .set_config = drm_atomic_helper_set_config, 1217 1216 .page_flip = drm_atomic_helper_page_flip, 1218 1217 .reset = drm_atomic_helper_crtc_reset, ··· 1544 1545 static const struct drm_plane_funcs ltdc_plane_funcs = { 1545 1546 .update_plane = drm_atomic_helper_update_plane, 1546 1547 .disable_plane = drm_atomic_helper_disable_plane, 1547 - .destroy = drm_plane_cleanup, 1548 1548 .reset = drm_atomic_helper_plane_reset, 1549 1549 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 1550 1550 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, ··· 1570 1572 const u64 *modifiers = ltdc_format_modifiers; 1571 1573 u32 lofs = index * LAY_OFS; 1572 1574 u32 val; 1573 - int ret; 1574 1575 1575 1576 /* Allocate the biggest size according to supported color formats */ 1576 1577 formats = devm_kzalloc(dev, (ldev->caps.pix_fmt_nb + ··· 1612 1615 } 1613 1616 } 1614 1617 1615 - plane = devm_kzalloc(dev, sizeof(*plane), GFP_KERNEL); 1616 - if (!plane) 1617 - return NULL; 1618 - 1619 - ret = drm_universal_plane_init(ddev, plane, possible_crtcs, 1620 - &ltdc_plane_funcs, formats, nb_fmt, 1621 - modifiers, type, NULL); 1622 - if (ret < 0) 1618 + plane = drmm_universal_plane_alloc(ddev, struct drm_plane, dev, 1619 + possible_crtcs, &ltdc_plane_funcs, formats, 1620 + nb_fmt, modifiers, type, NULL); 1621 + if (IS_ERR(plane)) 1623 1622 return NULL; 1624 1623 1625 1624 if (ldev->caps.ycbcr_input) { ··· 1636 1643 DRM_DEBUG_DRIVER("plane:%d created\n", plane->base.id); 1637 1644 1638 1645 return plane; 1639 - } 1640 - 1641 - static void ltdc_plane_destroy_all(struct drm_device *ddev) 1642 - { 1643 - struct drm_plane *plane, *plane_temp; 1644 - 1645 - list_for_each_entry_safe(plane, plane_temp, 1646 - &ddev->mode_config.plane_list, head) 1647 - drm_plane_cleanup(plane); 1648 1646 } 1649 1647 1650 1648 static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) ··· 1663 1679 1664 1680 /* Init CRTC according to its hardware features */ 1665 1681 if (ldev->caps.crc) 1666 - ret = drm_crtc_init_with_planes(ddev, crtc, primary, NULL, 1667 - &ltdc_crtc_with_crc_support_funcs, NULL); 1682 + ret = drmm_crtc_init_with_planes(ddev, crtc, primary, NULL, 1683 + &ltdc_crtc_with_crc_support_funcs, NULL); 1668 1684 else 1669 - ret = drm_crtc_init_with_planes(ddev, crtc, primary, NULL, 1670 - &ltdc_crtc_funcs, NULL); 1685 + ret = drmm_crtc_init_with_planes(ddev, crtc, primary, NULL, 1686 + &ltdc_crtc_funcs, NULL); 1671 1687 if (ret) { 1672 1688 DRM_ERROR("Can not initialize CRTC\n"); 1673 - goto cleanup; 1689 + return ret; 1674 1690 } 1675 1691 1676 1692 drm_crtc_helper_add(crtc, &ltdc_crtc_helper_funcs); ··· 1684 1700 for (i = 1; i < ldev->caps.nb_layers; i++) { 1685 1701 overlay = ltdc_plane_create(ddev, DRM_PLANE_TYPE_OVERLAY, i); 1686 1702 if (!overlay) { 1687 - ret = -ENOMEM; 1688 1703 DRM_ERROR("Can not create overlay plane %d\n", i); 1689 - goto cleanup; 1704 + return -ENOMEM; 1690 1705 } 1691 1706 if (ldev->caps.dynamic_zorder) 1692 1707 drm_plane_create_zpos_property(overlay, i, 0, ldev->caps.nb_layers - 1); ··· 1698 1715 } 1699 1716 1700 1717 return 0; 1701 - 1702 - cleanup: 1703 - ltdc_plane_destroy_all(ddev); 1704 - return ret; 1705 1718 } 1706 1719 1707 1720 static void ltdc_encoder_disable(struct drm_encoder *encoder) ··· 1757 1778 struct drm_encoder *encoder; 1758 1779 int ret; 1759 1780 1760 - encoder = devm_kzalloc(ddev->dev, sizeof(*encoder), GFP_KERNEL); 1761 - if (!encoder) 1762 - return -ENOMEM; 1781 + encoder = drmm_simple_encoder_alloc(ddev, struct drm_encoder, dev, 1782 + DRM_MODE_ENCODER_DPI); 1783 + if (IS_ERR(encoder)) 1784 + return PTR_ERR(encoder); 1763 1785 1764 1786 encoder->possible_crtcs = CRTC_MASK; 1765 1787 encoder->possible_clones = 0; /* No cloning support */ 1766 1788 1767 - drm_simple_encoder_init(ddev, encoder, DRM_MODE_ENCODER_DPI); 1768 - 1769 1789 drm_encoder_helper_add(encoder, &ltdc_encoder_helper_funcs); 1770 1790 1771 1791 ret = drm_bridge_attach(encoder, bridge, NULL, 0); 1772 - if (ret) { 1773 - if (ret != -EPROBE_DEFER) 1774 - drm_encoder_cleanup(encoder); 1792 + if (ret) 1775 1793 return ret; 1776 - } 1777 1794 1778 1795 DRM_DEBUG_DRIVER("Bridge encoder:%d created\n", encoder->base.id); 1779 1796 ··· 1939 1964 goto err; 1940 1965 1941 1966 if (panel) { 1942 - bridge = drm_panel_bridge_add_typed(panel, 1943 - DRM_MODE_CONNECTOR_DPI); 1967 + bridge = drmm_panel_bridge_add(ddev, panel); 1944 1968 if (IS_ERR(bridge)) { 1945 1969 DRM_ERROR("panel-bridge endpoint %d\n", i); 1946 1970 ret = PTR_ERR(bridge); ··· 2021 2047 } 2022 2048 } 2023 2049 2024 - crtc = devm_kzalloc(dev, sizeof(*crtc), GFP_KERNEL); 2050 + crtc = drmm_kzalloc(ddev, sizeof(*crtc), GFP_KERNEL); 2025 2051 if (!crtc) { 2026 2052 DRM_ERROR("Failed to allocate crtc\n"); 2027 2053 ret = -ENOMEM; ··· 2048 2074 2049 2075 return 0; 2050 2076 err: 2051 - for (i = 0; i < nb_endpoints; i++) 2052 - drm_of_panel_bridge_remove(ddev->dev->of_node, 0, i); 2053 - 2054 2077 clk_disable_unprepare(ldev->pixel_clk); 2055 2078 2056 2079 return ret; ··· 2055 2084 2056 2085 void ltdc_unload(struct drm_device *ddev) 2057 2086 { 2058 - struct device *dev = ddev->dev; 2059 - int nb_endpoints, i; 2060 - 2061 2087 DRM_DEBUG_DRIVER("\n"); 2062 - 2063 - nb_endpoints = of_graph_get_endpoint_count(dev->of_node); 2064 - 2065 - for (i = 0; i < nb_endpoints; i++) 2066 - drm_of_panel_bridge_remove(ddev->dev->of_node, 0, i); 2067 2088 2068 2089 pm_runtime_disable(ddev->dev); 2069 2090 }