diff mbox

[v5,05/10] blk-mq: Unregister debugfs attributes earlier

Message ID 20170425203745.19946-6-bart.vanassche@sandisk.com (mailing list archive)
State New, archived
Headers show

Commit Message

Bart Van Assche April 25, 2017, 8:37 p.m. UTC
One of the debugfs attributes allows to run a queue. Since running
a queue after a queue has entered the "dead" state is not allowed
and triggers a use-after-free, unregister the debugfs attributes
before a queue reaches the "dead" state.

Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Reviewed-by: Omar Sandoval <osandov@fb.com>
---
 block/blk-core.c | 5 +++++
 1 file changed, 5 insertions(+)

Comments

Omar Sandoval April 25, 2017, 9:30 p.m. UTC | #1
On Tue, Apr 25, 2017 at 01:37:40PM -0700, Bart Van Assche wrote:
> One of the debugfs attributes allows to run a queue. Since running
> a queue after a queue has entered the "dead" state is not allowed
> and triggers a use-after-free, unregister the debugfs attributes
> before a queue reaches the "dead" state.

Still not happy with this commit message. I'd prefer:

We currently call blk_mq_free_queue() from blk_cleanup_queue() before we
unregister the debugfs attributes for that queue in blk_release_queue().
This leaves a window open during which accessing most of the mq debugfs
attributes would cause a use-after-free. Additionally, the "state"
attribute allows running the queue, which we should not do after the
queue has entered the "dead" state. Fix both of these cases by
unregistering the debugfs attributes before this.

Jens, could you ack that dropping the lock is okay?

> Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
> Reviewed-by: Hannes Reinecke <hare@suse.com>
> Reviewed-by: Omar Sandoval <osandov@fb.com>
> ---
>  block/blk-core.c | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/block/blk-core.c b/block/blk-core.c
> index a49b0830aaaf..33c91a4bee97 100644
> --- a/block/blk-core.c
> +++ b/block/blk-core.c
> @@ -566,6 +566,11 @@ void blk_cleanup_queue(struct request_queue *q)
>  	spin_lock_irq(lock);
>  	if (!q->mq_ops)
>  		__blk_drain_queue(q, true);
> +	spin_unlock_irq(lock);
> +
> +	blk_mq_debugfs_unregister_mq(q);
> +
> +	spin_lock_irq(lock);
>  	queue_flag_set(QUEUE_FLAG_DEAD, q);
>  	spin_unlock_irq(lock);
>  
> -- 
> 2.12.2
>
Jens Axboe April 25, 2017, 9:41 p.m. UTC | #2
On 04/25/2017 02:30 PM, Omar Sandoval wrote:
> On Tue, Apr 25, 2017 at 01:37:40PM -0700, Bart Van Assche wrote:
>> One of the debugfs attributes allows to run a queue. Since running
>> a queue after a queue has entered the "dead" state is not allowed
>> and triggers a use-after-free, unregister the debugfs attributes
>> before a queue reaches the "dead" state.
> 
> Still not happy with this commit message. I'd prefer:
> 
> We currently call blk_mq_free_queue() from blk_cleanup_queue() before we
> unregister the debugfs attributes for that queue in blk_release_queue().
> This leaves a window open during which accessing most of the mq debugfs
> attributes would cause a use-after-free. Additionally, the "state"
> attribute allows running the queue, which we should not do after the
> queue has entered the "dead" state. Fix both of these cases by
> unregistering the debugfs attributes before this.
> 
> Jens, could you ack that dropping the lock is okay?

Looks fine to me. However, I think there's room for improvement here.
Why don't we just make it:

	if (!q->mq_ops) {
		spin_lock_irq(lock);
		__blk_drain_queue(q, true);
	} else {
		blk_mq_debugfs_unregister_mq(q);
		spin_lock_irq(lock);
	}

	queue_flag_set(QUEUE_FLAG_DEAD, q);
	[...]

Would seem much more readable to me, and less dropping/acquiring for
cases where we don't need it.
Bart Van Assche April 25, 2017, 10:24 p.m. UTC | #3
On Tue, 2017-04-25 at 14:30 -0700, Omar Sandoval wrote:
> On Tue, Apr 25, 2017 at 01:37:40PM -0700, Bart Van Assche wrote:
> > One of the debugfs attributes allows to run a queue. Since running
> > a queue after a queue has entered the "dead" state is not allowed
> > and triggers a use-after-free, unregister the debugfs attributes
> > before a queue reaches the "dead" state.
> 
> Still not happy with this commit message. I'd prefer:
> 
> We currently call blk_mq_free_queue() from blk_cleanup_queue() before we
> unregister the debugfs attributes for that queue in blk_release_queue().
> This leaves a window open during which accessing most of the mq debugfs
> attributes would cause a use-after-free. Additionally, the "state"
> attribute allows running the queue, which we should not do after the
> queue has entered the "dead" state. Fix both of these cases by
> unregistering the debugfs attributes before this.

Hello Omar,

That's a very verbose description. How about this?

    Unregister the debugfs attributes before freeing of request queue
    resources starts to avoid that a use-after-free can be triggered
    through one of the debugfs attributes.

Bart.
Jens Axboe April 25, 2017, 10:29 p.m. UTC | #4
On 04/25/2017 03:24 PM, Bart Van Assche wrote:
> On Tue, 2017-04-25 at 14:30 -0700, Omar Sandoval wrote:
>> On Tue, Apr 25, 2017 at 01:37:40PM -0700, Bart Van Assche wrote:
>>> One of the debugfs attributes allows to run a queue. Since running
>>> a queue after a queue has entered the "dead" state is not allowed
>>> and triggers a use-after-free, unregister the debugfs attributes
>>> before a queue reaches the "dead" state.
>>
>> Still not happy with this commit message. I'd prefer:
>>
>> We currently call blk_mq_free_queue() from blk_cleanup_queue() before we
>> unregister the debugfs attributes for that queue in blk_release_queue().
>> This leaves a window open during which accessing most of the mq debugfs
>> attributes would cause a use-after-free. Additionally, the "state"
>> attribute allows running the queue, which we should not do after the
>> queue has entered the "dead" state. Fix both of these cases by
>> unregistering the debugfs attributes before this.
> 
> Hello Omar,
> 
> That's a very verbose description. How about this?
> 
>     Unregister the debugfs attributes before freeing of request queue
>     resources starts to avoid that a use-after-free can be triggered
>     through one of the debugfs attributes.

Personally I find Omar's commit message much cleaner to read, and
more easily understandable. We really don't need to be laconic in
commit messages.
Omar Sandoval April 25, 2017, 10:30 p.m. UTC | #5
On Tue, Apr 25, 2017 at 10:24:48PM +0000, Bart Van Assche wrote:
> On Tue, 2017-04-25 at 14:30 -0700, Omar Sandoval wrote:
> > On Tue, Apr 25, 2017 at 01:37:40PM -0700, Bart Van Assche wrote:
> > > One of the debugfs attributes allows to run a queue. Since running
> > > a queue after a queue has entered the "dead" state is not allowed
> > > and triggers a use-after-free, unregister the debugfs attributes
> > > before a queue reaches the "dead" state.
> > 
> > Still not happy with this commit message. I'd prefer:
> > 
> > We currently call blk_mq_free_queue() from blk_cleanup_queue() before we
> > unregister the debugfs attributes for that queue in blk_release_queue().
> > This leaves a window open during which accessing most of the mq debugfs
> > attributes would cause a use-after-free. Additionally, the "state"
> > attribute allows running the queue, which we should not do after the
> > queue has entered the "dead" state. Fix both of these cases by
> > unregistering the debugfs attributes before this.
> 
> Hello Omar,
> 
> That's a very verbose description. How about this?
> 
>     Unregister the debugfs attributes before freeing of request queue
>     resources starts to avoid that a use-after-free can be triggered
>     through one of the debugfs attributes.
> 
> Bart.

Are you aware that there is nothing wrong with a descriptive commit
message?
Bart Van Assche April 26, 2017, 8:32 p.m. UTC | #6
On Tue, 2017-04-25 at 14:30 -0700, Omar Sandoval wrote:
> Jens, could you ack that dropping the lock is okay?

Hello Omar,

If you have a look at the block layer history then you will see that the
current approach for shutting down block layer queues is an approach that
I had introduced myself. See also commits 3f3299d5c026, 807592a4fafb and
c246e80d8673.

Bart.
Jens Axboe April 26, 2017, 8:37 p.m. UTC | #7
On 04/26/2017 01:32 PM, Bart Van Assche wrote:
> On Tue, 2017-04-25 at 14:30 -0700, Omar Sandoval wrote:
>> Jens, could you ack that dropping the lock is okay?
> 
> Hello Omar,
> 
> If you have a look at the block layer history then you will see that the
> current approach for shutting down block layer queues is an approach that
> I had introduced myself. See also commits 3f3299d5c026, 807592a4fafb and
> c246e80d8673.

Bart, did you see my reply on the topic?
Omar Sandoval April 26, 2017, 8:37 p.m. UTC | #8
On Wed, Apr 26, 2017 at 08:32:31PM +0000, Bart Van Assche wrote:
> On Tue, 2017-04-25 at 14:30 -0700, Omar Sandoval wrote:
> > Jens, could you ack that dropping the lock is okay?
> 
> Hello Omar,
> 
> If you have a look at the block layer history then you will see that the
> current approach for shutting down block layer queues is an approach that
> I had introduced myself. See also commits 3f3299d5c026, 807592a4fafb and
> c246e80d8673.
> 
> Bart.

Thanks for the reference. Jens' suggestion looks the cleanest to me.
Bart Van Assche April 26, 2017, 8:38 p.m. UTC | #9
On Tue, 2017-04-25 at 14:41 -0700, Jens Axboe wrote:
> Looks fine to me. However, I think there's room for improvement here.
> Why don't we just make it:
> 
> 	if (!q->mq_ops) {
> 		spin_lock_irq(lock);
> 		__blk_drain_queue(q, true);
> 	} else {
> 		blk_mq_debugfs_unregister_mq(q);
> 		spin_lock_irq(lock);
> 	}
> 
> 	queue_flag_set(QUEUE_FLAG_DEAD, q);
> 	[...]
> 
> Would seem much more readable to me, and less dropping/acquiring for
> cases where we don't need it.

Hello Jens,

This looks fine to me. I will update the patch.

Bart.
diff mbox

Patch

diff --git a/block/blk-core.c b/block/blk-core.c
index a49b0830aaaf..33c91a4bee97 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -566,6 +566,11 @@  void blk_cleanup_queue(struct request_queue *q)
 	spin_lock_irq(lock);
 	if (!q->mq_ops)
 		__blk_drain_queue(q, true);
+	spin_unlock_irq(lock);
+
+	blk_mq_debugfs_unregister_mq(q);
+
+	spin_lock_irq(lock);
 	queue_flag_set(QUEUE_FLAG_DEAD, q);
 	spin_unlock_irq(lock);