Commit 9da67433 authored by Tomi Valkeinen's avatar Tomi Valkeinen

drm/tidss: fix crash related to accessing freed memory

tidss uses devm_kzalloc to allocate DRM plane, encoder and crtc objects.
This is not correct as the lifetime of those objects should be longer
than the underlying device's.

When unloading tidss module, the devm_kzalloc'ed objects have already
been freed when tidss_release() is called, and the driver will accesses
freed memory possibly causing a crash, a kernel WARN, or other undefined
behavior, and also KASAN will give a bug.
Signed-off-by: default avatarTomi Valkeinen <tomi.valkeinen@ti.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200415092006.26675-1-tomi.valkeinen@ti.comAcked-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 7bfc1fec
...@@ -379,9 +379,17 @@ static struct drm_crtc_state *tidss_crtc_duplicate_state(struct drm_crtc *crtc) ...@@ -379,9 +379,17 @@ static struct drm_crtc_state *tidss_crtc_duplicate_state(struct drm_crtc *crtc)
return &state->base; return &state->base;
} }
static void tidss_crtc_destroy(struct drm_crtc *crtc)
{
struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
drm_crtc_cleanup(crtc);
kfree(tcrtc);
}
static const struct drm_crtc_funcs tidss_crtc_funcs = { static const struct drm_crtc_funcs tidss_crtc_funcs = {
.reset = tidss_crtc_reset, .reset = tidss_crtc_reset,
.destroy = drm_crtc_cleanup, .destroy = tidss_crtc_destroy,
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip, .page_flip = drm_atomic_helper_page_flip,
.atomic_duplicate_state = tidss_crtc_duplicate_state, .atomic_duplicate_state = tidss_crtc_duplicate_state,
...@@ -400,7 +408,7 @@ struct tidss_crtc *tidss_crtc_create(struct tidss_device *tidss, ...@@ -400,7 +408,7 @@ struct tidss_crtc *tidss_crtc_create(struct tidss_device *tidss,
bool has_ctm = tidss->feat->vp_feat.color.has_ctm; bool has_ctm = tidss->feat->vp_feat.color.has_ctm;
int ret; int ret;
tcrtc = devm_kzalloc(tidss->dev, sizeof(*tcrtc), GFP_KERNEL); tcrtc = kzalloc(sizeof(*tcrtc), GFP_KERNEL);
if (!tcrtc) if (!tcrtc)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -411,8 +419,10 @@ struct tidss_crtc *tidss_crtc_create(struct tidss_device *tidss, ...@@ -411,8 +419,10 @@ struct tidss_crtc *tidss_crtc_create(struct tidss_device *tidss,
ret = drm_crtc_init_with_planes(&tidss->ddev, crtc, primary, ret = drm_crtc_init_with_planes(&tidss->ddev, crtc, primary,
NULL, &tidss_crtc_funcs, NULL); NULL, &tidss_crtc_funcs, NULL);
if (ret < 0) if (ret < 0) {
kfree(tcrtc);
return ERR_PTR(ret); return ERR_PTR(ret);
}
drm_crtc_helper_add(crtc, &tidss_crtc_helper_funcs); drm_crtc_helper_add(crtc, &tidss_crtc_helper_funcs);
......
...@@ -55,12 +55,18 @@ static int tidss_encoder_atomic_check(struct drm_encoder *encoder, ...@@ -55,12 +55,18 @@ static int tidss_encoder_atomic_check(struct drm_encoder *encoder,
return 0; return 0;
} }
static void tidss_encoder_destroy(struct drm_encoder *encoder)
{
drm_encoder_cleanup(encoder);
kfree(encoder);
}
static const struct drm_encoder_helper_funcs encoder_helper_funcs = { static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
.atomic_check = tidss_encoder_atomic_check, .atomic_check = tidss_encoder_atomic_check,
}; };
static const struct drm_encoder_funcs encoder_funcs = { static const struct drm_encoder_funcs encoder_funcs = {
.destroy = drm_encoder_cleanup, .destroy = tidss_encoder_destroy,
}; };
struct drm_encoder *tidss_encoder_create(struct tidss_device *tidss, struct drm_encoder *tidss_encoder_create(struct tidss_device *tidss,
...@@ -69,7 +75,7 @@ struct drm_encoder *tidss_encoder_create(struct tidss_device *tidss, ...@@ -69,7 +75,7 @@ struct drm_encoder *tidss_encoder_create(struct tidss_device *tidss,
struct drm_encoder *enc; struct drm_encoder *enc;
int ret; int ret;
enc = devm_kzalloc(tidss->dev, sizeof(*enc), GFP_KERNEL); enc = kzalloc(sizeof(*enc), GFP_KERNEL);
if (!enc) if (!enc)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -77,8 +83,10 @@ struct drm_encoder *tidss_encoder_create(struct tidss_device *tidss, ...@@ -77,8 +83,10 @@ struct drm_encoder *tidss_encoder_create(struct tidss_device *tidss,
ret = drm_encoder_init(&tidss->ddev, enc, &encoder_funcs, ret = drm_encoder_init(&tidss->ddev, enc, &encoder_funcs,
encoder_type, NULL); encoder_type, NULL);
if (ret < 0) if (ret < 0) {
kfree(enc);
return ERR_PTR(ret); return ERR_PTR(ret);
}
drm_encoder_helper_add(enc, &encoder_helper_funcs); drm_encoder_helper_add(enc, &encoder_helper_funcs);
......
...@@ -141,6 +141,14 @@ static void tidss_plane_atomic_disable(struct drm_plane *plane, ...@@ -141,6 +141,14 @@ static void tidss_plane_atomic_disable(struct drm_plane *plane,
dispc_plane_enable(tidss->dispc, tplane->hw_plane_id, false); dispc_plane_enable(tidss->dispc, tplane->hw_plane_id, false);
} }
static void drm_plane_destroy(struct drm_plane *plane)
{
struct tidss_plane *tplane = to_tidss_plane(plane);
drm_plane_cleanup(plane);
kfree(tplane);
}
static const struct drm_plane_helper_funcs tidss_plane_helper_funcs = { static const struct drm_plane_helper_funcs tidss_plane_helper_funcs = {
.atomic_check = tidss_plane_atomic_check, .atomic_check = tidss_plane_atomic_check,
.atomic_update = tidss_plane_atomic_update, .atomic_update = tidss_plane_atomic_update,
...@@ -151,7 +159,7 @@ static const struct drm_plane_funcs tidss_plane_funcs = { ...@@ -151,7 +159,7 @@ static const struct drm_plane_funcs tidss_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane, .update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane, .disable_plane = drm_atomic_helper_disable_plane,
.reset = drm_atomic_helper_plane_reset, .reset = drm_atomic_helper_plane_reset,
.destroy = drm_plane_cleanup, .destroy = drm_plane_destroy,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
}; };
...@@ -175,7 +183,7 @@ struct tidss_plane *tidss_plane_create(struct tidss_device *tidss, ...@@ -175,7 +183,7 @@ struct tidss_plane *tidss_plane_create(struct tidss_device *tidss,
BIT(DRM_MODE_BLEND_COVERAGE)); BIT(DRM_MODE_BLEND_COVERAGE));
int ret; int ret;
tplane = devm_kzalloc(tidss->dev, sizeof(*tplane), GFP_KERNEL); tplane = kzalloc(sizeof(*tplane), GFP_KERNEL);
if (!tplane) if (!tplane)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -190,7 +198,7 @@ struct tidss_plane *tidss_plane_create(struct tidss_device *tidss, ...@@ -190,7 +198,7 @@ struct tidss_plane *tidss_plane_create(struct tidss_device *tidss,
formats, num_formats, formats, num_formats,
NULL, type, NULL); NULL, type, NULL);
if (ret < 0) if (ret < 0)
return ERR_PTR(ret); goto err;
drm_plane_helper_add(&tplane->plane, &tidss_plane_helper_funcs); drm_plane_helper_add(&tplane->plane, &tidss_plane_helper_funcs);
...@@ -203,15 +211,19 @@ struct tidss_plane *tidss_plane_create(struct tidss_device *tidss, ...@@ -203,15 +211,19 @@ struct tidss_plane *tidss_plane_create(struct tidss_device *tidss,
default_encoding, default_encoding,
default_range); default_range);
if (ret) if (ret)
return ERR_PTR(ret); goto err;
ret = drm_plane_create_alpha_property(&tplane->plane); ret = drm_plane_create_alpha_property(&tplane->plane);
if (ret) if (ret)
return ERR_PTR(ret); goto err;
ret = drm_plane_create_blend_mode_property(&tplane->plane, blend_modes); ret = drm_plane_create_blend_mode_property(&tplane->plane, blend_modes);
if (ret) if (ret)
return ERR_PTR(ret); goto err;
return tplane; return tplane;
err:
kfree(tplane);
return ERR_PTR(ret);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment