diff mbox

drm/i915: Fix null pointer dereference in ring cleanup code

Message ID 1414756826-21062-1-git-send-email-John.C.Harrison@Intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

John Harrison Oct. 31, 2014, noon UTC
From: John Harrison <John.C.Harrison@Intel.com>

If a ring failed to initialise for any reason then the error path would try to
clean up all rings including those that had not yet been allocated. The ring
clean up code did a check that the ring was valid before starting its work.
Unfortunately, that was after it had already dereferenced the ring to obtain a
dev_private pointer.

Signed-off-by: John Harrison <John.C.Harrison@Intel.com>
---
 drivers/gpu/drm/i915/intel_lrc.c        |    4 +++-
 drivers/gpu/drm/i915/intel_ringbuffer.c |    7 +++++--
 2 files changed, 8 insertions(+), 3 deletions(-)

Comments

Lespiau, Damien Oct. 31, 2014, 2:52 p.m. UTC | #1
On Fri, Oct 31, 2014 at 12:00:26PM +0000, John.C.Harrison@Intel.com wrote:
> From: John Harrison <John.C.Harrison@Intel.com>
> 
> If a ring failed to initialise for any reason then the error path would try to
> clean up all rings including those that had not yet been allocated. The ring
> clean up code did a check that the ring was valid before starting its work.
> Unfortunately, that was after it had already dereferenced the ring to obtain a
> dev_private pointer.
> 
> Signed-off-by: John Harrison <John.C.Harrison@Intel.com>

This looks good to me.

Reviewed-by: Damien Lespiau <damien.lespiau@intel.com>
Chris Wilson Oct. 31, 2014, 4:07 p.m. UTC | #2
On Fri, Oct 31, 2014 at 02:52:40PM +0000, Damien Lespiau wrote:
> On Fri, Oct 31, 2014 at 12:00:26PM +0000, John.C.Harrison@Intel.com wrote:
> > From: John Harrison <John.C.Harrison@Intel.com>
> > 
> > If a ring failed to initialise for any reason then the error path would try to
> > clean up all rings including those that had not yet been allocated. The ring
> > clean up code did a check that the ring was valid before starting its work.
> > Unfortunately, that was after it had already dereferenced the ring to obtain a
> > dev_private pointer.
> > 
> > Signed-off-by: John Harrison <John.C.Harrison@Intel.com>
> 
> This looks good to me.

Really? These functions(!!!) are only called under controlled conditions...
I would have been happy to see this follow my suggestion I made to fix
this bug months ago.
-Chris
Daniel Vetter Nov. 3, 2014, 12:54 p.m. UTC | #3
On Fri, Oct 31, 2014 at 04:07:35PM +0000, Chris Wilson wrote:
> On Fri, Oct 31, 2014 at 02:52:40PM +0000, Damien Lespiau wrote:
> > On Fri, Oct 31, 2014 at 12:00:26PM +0000, John.C.Harrison@Intel.com wrote:
> > > From: John Harrison <John.C.Harrison@Intel.com>
> > > 
> > > If a ring failed to initialise for any reason then the error path would try to
> > > clean up all rings including those that had not yet been allocated. The ring
> > > clean up code did a check that the ring was valid before starting its work.
> > > Unfortunately, that was after it had already dereferenced the ring to obtain a
> > > dev_private pointer.
> > > 
> > > Signed-off-by: John Harrison <John.C.Harrison@Intel.com>
> > 
> > This looks good to me.
> 
> Really? These functions(!!!) are only called under controlled conditions...
> I would have been happy to see this follow my suggestion I made to fix
> this bug months ago.

Hm, do you mean to shuffle the ring_initialized checks into callers? Or
something else?

John's patch didn't look offensive really, so merged it for now.
-Daniel
Dave Gordon Nov. 3, 2014, 5:16 p.m. UTC | #4
On 31/10/14 14:52, Damien Lespiau wrote:
> On Fri, Oct 31, 2014 at 12:00:26PM +0000, John.C.Harrison@Intel.com wrote:
>> From: John Harrison <John.C.Harrison@Intel.com>
>>
>> If a ring failed to initialise for any reason then the error path would try to
>> clean up all rings including those that had not yet been allocated. The ring
>> clean up code did a check that the ring was valid before starting its work.
>> Unfortunately, that was after it had already dereferenced the ring to obtain a
>> dev_private pointer.
>>
>> Signed-off-by: John Harrison <John.C.Harrison@Intel.com>
> 
> This looks good to me.
> 
> Reviewed-by: Damien Lespiau <damien.lespiau@intel.com>

And simpler than the version I previously posted, as that would have
had to have another test added for each new ring in future hardware.
However I think the description above is slightly misleading, as the
problem wasn't dereferencing "ring" but "ring->dev". "ring" is always
non-NULL (it's the address of a member of an array inside dev_priv),
but the backpointer "ring->dev" is only filled in during ring
initialisation.

.Dave.
Chris Wilson Nov. 3, 2014, 8:39 p.m. UTC | #5
On Mon, Nov 03, 2014 at 01:54:00PM +0100, Daniel Vetter wrote:
> On Fri, Oct 31, 2014 at 04:07:35PM +0000, Chris Wilson wrote:
> > On Fri, Oct 31, 2014 at 02:52:40PM +0000, Damien Lespiau wrote:
> > > On Fri, Oct 31, 2014 at 12:00:26PM +0000, John.C.Harrison@Intel.com wrote:
> > > > From: John Harrison <John.C.Harrison@Intel.com>
> > > > 
> > > > If a ring failed to initialise for any reason then the error path would try to
> > > > clean up all rings including those that had not yet been allocated. The ring
> > > > clean up code did a check that the ring was valid before starting its work.
> > > > Unfortunately, that was after it had already dereferenced the ring to obtain a
> > > > dev_private pointer.
> > > > 
> > > > Signed-off-by: John Harrison <John.C.Harrison@Intel.com>
> > > 
> > > This looks good to me.
> > 
> > Really? These functions(!!!) are only called under controlled conditions...
> > I would have been happy to see this follow my suggestion I made to fix
> > this bug months ago.
> 
> Hm, do you mean to shuffle the ring_initialized checks into callers? Or
> something else?


i915_gem_cleanup_engines()
{
	/* Not the regular for_each_engine so we can cleanup a failed setup */
	for (int i =0 ; i < I915_NUM_ENGINES; i++)
		intel_engine_cleanup(&to_i915(dev)->engine[i]);
}

And that is callable then from an incomplete setup as well as normal
teardown.

And intel_engine_cleanup() need just be:
void intel_engine_cleanup(struct intel_engine_cs *engine)
{
	WARN_ON(engine->last_request);

	if (engine->cleanup)
		engine->cleanup(engine);
}

Remove bugs by removing code, win.
-Chris
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index cd74e5c..76776fa 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -1214,11 +1214,13 @@  static int gen8_emit_request(struct intel_ringbuffer *ringbuf)
  */
 void intel_logical_ring_cleanup(struct intel_engine_cs *ring)
 {
-	struct drm_i915_private *dev_priv = ring->dev->dev_private;
+	struct drm_i915_private *dev_priv;
 
 	if (!intel_ring_initialized(ring))
 		return;
 
+	dev_priv = ring->dev->dev_private;
+
 	intel_logical_ring_stop(ring);
 	WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0);
 	ring->preallocated_lazy_request = NULL;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index a8f72e8..f457146 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1845,12 +1845,15 @@  error:
 
 void intel_cleanup_ring_buffer(struct intel_engine_cs *ring)
 {
-	struct drm_i915_private *dev_priv = to_i915(ring->dev);
-	struct intel_ringbuffer *ringbuf = ring->buffer;
+	struct drm_i915_private *dev_priv;
+	struct intel_ringbuffer *ringbuf;
 
 	if (!intel_ring_initialized(ring))
 		return;
 
+	dev_priv = to_i915(ring->dev);
+	ringbuf = ring->buffer;
+
 	intel_stop_ring_buffer(ring);
 	WARN_ON(!IS_GEN2(ring->dev) && (I915_READ_MODE(ring) & MODE_IDLE) == 0);