Skip to content

Commit ba807c9

Browse files
committed
drm/imx: fix use after free
Component driver structures allocated with devm_kmalloc() in bind() are freed automatically after unbind(). Since the contained drm structures are accessed afterwards in drm_mode_config_cleanup(), move the allocation into probe() to extend the driver structure's lifetime to the lifetime of the device. This should eventually be changed to use drm resource managed allocations with lifetime of the drm device. We also need to ensure that all componets are available during the unbind() so we need to call component_unbind_all() before we free non-devres resources like planes. Note this patch fixes the the use after free bug but introduces a possible boot loop issue. The issue is triggered if the HDMI support is enabled and a component driver always return -EPROBE_DEFER, see discussion [1] for more details. [1] https://lkml.org/lkml/2020/3/24/1467 Fixes: 17b5001 ("imx-drm: convert to componentised device support") Signed-off-by: Philipp Zabel <[email protected]> [m.felsch@pengutronix: fix imx_tve_probe()] [m.felsch@pengutronix: resort component_unbind_all()) [m.felsch@pengutronix: adapt commit message] Signed-off-by: Marco Felsch <[email protected]> Signed-off-by: Philipp Zabel <[email protected]>
1 parent b3a9e3b commit ba807c9

File tree

6 files changed

+52
-32
lines changed

6 files changed

+52
-32
lines changed

drivers/gpu/drm/imx/dw_hdmi-imx.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -209,9 +209,8 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
209209
if (!pdev->dev.of_node)
210210
return -ENODEV;
211211

212-
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
213-
if (!hdmi)
214-
return -ENOMEM;
212+
hdmi = dev_get_drvdata(dev);
213+
memset(hdmi, 0, sizeof(*hdmi));
215214

216215
match = of_match_node(dw_hdmi_imx_dt_ids, pdev->dev.of_node);
217216
plat_data = match->data;
@@ -235,8 +234,6 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
235234
drm_encoder_helper_add(encoder, &dw_hdmi_imx_encoder_helper_funcs);
236235
drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
237236

238-
platform_set_drvdata(pdev, hdmi);
239-
240237
hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
241238

242239
/*
@@ -266,6 +263,14 @@ static const struct component_ops dw_hdmi_imx_ops = {
266263

267264
static int dw_hdmi_imx_probe(struct platform_device *pdev)
268265
{
266+
struct imx_hdmi *hdmi;
267+
268+
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
269+
if (!hdmi)
270+
return -ENOMEM;
271+
272+
platform_set_drvdata(pdev, hdmi);
273+
269274
return component_add(&pdev->dev, &dw_hdmi_imx_ops);
270275
}
271276

drivers/gpu/drm/imx/imx-drm-core.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,9 +275,10 @@ static void imx_drm_unbind(struct device *dev)
275275

276276
drm_kms_helper_poll_fini(drm);
277277

278+
component_unbind_all(drm->dev, drm);
279+
278280
drm_mode_config_cleanup(drm);
279281

280-
component_unbind_all(drm->dev, drm);
281282
dev_set_drvdata(dev, NULL);
282283

283284
drm_dev_put(drm);

drivers/gpu/drm/imx/imx-ldb.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -590,9 +590,8 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
590590
int ret;
591591
int i;
592592

593-
imx_ldb = devm_kzalloc(dev, sizeof(*imx_ldb), GFP_KERNEL);
594-
if (!imx_ldb)
595-
return -ENOMEM;
593+
imx_ldb = dev_get_drvdata(dev);
594+
memset(imx_ldb, 0, sizeof(*imx_ldb));
596595

597596
imx_ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
598597
if (IS_ERR(imx_ldb->regmap)) {
@@ -700,8 +699,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
700699
}
701700
}
702701

703-
dev_set_drvdata(dev, imx_ldb);
704-
705702
return 0;
706703

707704
free_child:
@@ -733,6 +730,14 @@ static const struct component_ops imx_ldb_ops = {
733730

734731
static int imx_ldb_probe(struct platform_device *pdev)
735732
{
733+
struct imx_ldb *imx_ldb;
734+
735+
imx_ldb = devm_kzalloc(&pdev->dev, sizeof(*imx_ldb), GFP_KERNEL);
736+
if (!imx_ldb)
737+
return -ENOMEM;
738+
739+
platform_set_drvdata(pdev, imx_ldb);
740+
736741
return component_add(&pdev->dev, &imx_ldb_ops);
737742
}
738743

drivers/gpu/drm/imx/imx-tve.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -542,9 +542,8 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
542542
int irq;
543543
int ret;
544544

545-
tve = devm_kzalloc(dev, sizeof(*tve), GFP_KERNEL);
546-
if (!tve)
547-
return -ENOMEM;
545+
tve = dev_get_drvdata(dev);
546+
memset(tve, 0, sizeof(*tve));
548547

549548
tve->dev = dev;
550549
spin_lock_init(&tve->lock);
@@ -655,8 +654,6 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
655654
if (ret)
656655
return ret;
657656

658-
dev_set_drvdata(dev, tve);
659-
660657
return 0;
661658
}
662659

@@ -676,6 +673,14 @@ static const struct component_ops imx_tve_ops = {
676673

677674
static int imx_tve_probe(struct platform_device *pdev)
678675
{
676+
struct imx_tve *tve;
677+
678+
tve = devm_kzalloc(&pdev->dev, sizeof(*tve), GFP_KERNEL);
679+
if (!tve)
680+
return -ENOMEM;
681+
682+
platform_set_drvdata(pdev, tve);
683+
679684
return component_add(&pdev->dev, &imx_tve_ops);
680685
}
681686

drivers/gpu/drm/imx/ipuv3-crtc.c

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -438,21 +438,13 @@ static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
438438
struct ipu_client_platformdata *pdata = dev->platform_data;
439439
struct drm_device *drm = data;
440440
struct ipu_crtc *ipu_crtc;
441-
int ret;
442441

443-
ipu_crtc = devm_kzalloc(dev, sizeof(*ipu_crtc), GFP_KERNEL);
444-
if (!ipu_crtc)
445-
return -ENOMEM;
442+
ipu_crtc = dev_get_drvdata(dev);
443+
memset(ipu_crtc, 0, sizeof(*ipu_crtc));
446444

447445
ipu_crtc->dev = dev;
448446

449-
ret = ipu_crtc_init(ipu_crtc, pdata, drm);
450-
if (ret)
451-
return ret;
452-
453-
dev_set_drvdata(dev, ipu_crtc);
454-
455-
return 0;
447+
return ipu_crtc_init(ipu_crtc, pdata, drm);
456448
}
457449

458450
static void ipu_drm_unbind(struct device *dev, struct device *master,
@@ -474,6 +466,7 @@ static const struct component_ops ipu_crtc_ops = {
474466
static int ipu_drm_probe(struct platform_device *pdev)
475467
{
476468
struct device *dev = &pdev->dev;
469+
struct ipu_crtc *ipu_crtc;
477470
int ret;
478471

479472
if (!dev->platform_data)
@@ -483,6 +476,12 @@ static int ipu_drm_probe(struct platform_device *pdev)
483476
if (ret)
484477
return ret;
485478

479+
ipu_crtc = devm_kzalloc(dev, sizeof(*ipu_crtc), GFP_KERNEL);
480+
if (!ipu_crtc)
481+
return -ENOMEM;
482+
483+
dev_set_drvdata(dev, ipu_crtc);
484+
486485
return component_add(dev, &ipu_crtc_ops);
487486
}
488487

drivers/gpu/drm/imx/parallel-display.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -326,9 +326,8 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
326326
u32 bus_format = 0;
327327
const char *fmt;
328328

329-
imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL);
330-
if (!imxpd)
331-
return -ENOMEM;
329+
imxpd = dev_get_drvdata(dev);
330+
memset(imxpd, 0, sizeof(*imxpd));
332331

333332
edidp = of_get_property(np, "edid", &imxpd->edid_len);
334333
if (edidp)
@@ -359,8 +358,6 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
359358
if (ret)
360359
return ret;
361360

362-
dev_set_drvdata(dev, imxpd);
363-
364361
return 0;
365362
}
366363

@@ -382,6 +379,14 @@ static const struct component_ops imx_pd_ops = {
382379

383380
static int imx_pd_probe(struct platform_device *pdev)
384381
{
382+
struct imx_parallel_display *imxpd;
383+
384+
imxpd = devm_kzalloc(&pdev->dev, sizeof(*imxpd), GFP_KERNEL);
385+
if (!imxpd)
386+
return -ENOMEM;
387+
388+
platform_set_drvdata(pdev, imxpd);
389+
385390
return component_add(&pdev->dev, &imx_pd_ops);
386391
}
387392

0 commit comments

Comments
 (0)