[Devel] [PATCH rh7] ploop: add support for dm-crypted ploops

Maxim Patlasov mpatlasov at virtuozzo.com
Fri Aug 19 10:14:09 PDT 2016


Andrey,


On 08/19/2016 03:44 AM, Andrey Ryabinin wrote:

>
> On 08/19/2016 02:40 AM, Maxim Patlasov wrote:
>> On 08/18/2016 09:49 AM, Andrey Ryabinin wrote:
>>
>>> On 08/18/2016 04:21 AM, Maxim Patlasov wrote:
>>>> Andrey,
>>>>
>>>>
>>>> ploop_freeze() must use __ploop_get_dm_crypt_bdev(), not ploop_get_dm_crypt_bdev()!
>>>>
>>> YUp.
>>>
>>>> Another problem is that the patch does not ensure that plo->dm_crypt_bdev stays the same between PLOOP_IOC_FREEZE/THAW. I could easily get:
>>>>
>>>> [  636.600190] BUG: unable to handle kernel NULL pointer dereference at 0000000000000068
>>>> [  636.600934] IP: [<ffffffff810ac5d3>] up_read+0x13/0x30
>>>> [  636.601446] PGD 222f5a067 PUD 224bc6067 PMD 0
>>>> [  636.601915] Oops: 0002 [#1] SMP
>>>> ...
>>>>
>>>> [  636.623264] Call Trace:
>>>> [  636.623597]  [<ffffffff811fd346>] drop_super+0x16/0x30
>>>> [  636.624104]  [<ffffffff81237010>] freeze_bdev+0x60/0xe0
>>>> [  636.624627]  [<ffffffffa0541a3e>] ploop_ioctl+0x2b8e/0x2c80 [ploop]
>>>> [  636.625237]  [<ffffffff811acb44>] ? handle_mm_fault+0x5b4/0xf50
>>>> [  636.625822]  [<ffffffff812d41ef>] blkdev_ioctl+0x2df/0x770
>>>> [  636.626439]  [<ffffffff812365d1>] block_ioctl+0x41/0x50
>>>> [  636.627162]  [<ffffffff8120d515>] do_vfs_ioctl+0x255/0x4f0
>>>> [  636.627827]  [<ffffffff8120d804>] SyS_ioctl+0x54/0xa0
>>>>
>>>> due to this problem.
>>> I don't see direct relation between this crash and changing plo->dm_crypt_bdev in between freeze/thaw.
>> In ideal world freeze+thaw+freeze+thaw must change bd_fsfreeze_count like this: 0 --> 1 --> 0 --> 1 --> 0. But if plo->dm_crypt_bdev changes in between, the first increment may be applied to one bdev, then decrement to another bdev, then the second increment again to the first bdev.
>>
>>> The way I read this
>>>
>>> struct super_block *freeze_bdev(struct block_device *bdev)
>>> ...
>>>      if (++bdev->bd_fsfreeze_count > 1) {
>>>
>>>          sb = get_super(bdev);  // this returned NULL, so we don't have active super block on this device.
>>>          drop_super(sb); // NULL ptr deref
>>>          mutex_unlock(&bdev->bd_fsfreeze_mutex);
>>>          return sb;
>>>      
>>>
>>> AFAIU, this can happen if we call freeze_bdev() twice on block device which doesn't have mounted fs.
>>> Isn't this a bug in freeze_bdev()?
>> No. The bug is to call freeze_bdev second time if the first time it returned sb == NULL.
>>
> Disagreed. This would mean that all callers supposed to synchronize freeze_bdev()/thaw_bdev() sequence.
> Otherwise we can get:
>
> CPU 0:					CPU1:
> 	freeze_bdev() //return NULL
> 					freeze_bdev() //NULL-ptr deref
> 					thaw_bdev()
> 	thaw_bdev()
>
> So, how do you propose to fix that case? If freeze_bdev() on CPU1 is illegal, that would mean that every freeze_bdev()...thaw_bdev() should
> be in critical section, iow surrounded by some per-bdev lock. While comment near freeze_bdev() says that it totally ok if multiple freeze
> request arrive simultaneously.

Makes sense. Will you send the patch upstream?

>
> Note, that this patch is also still affected by this bug, e.g.:
> 	1) cryptsetup open /dev/ploop0p1 test
> 	2) freeze ploop
> 	3) dmsetup suspend test //suspend calls lock_fs()->freeze_bdev() -> NULL ptr deref
>
>
> So the only sane way to fix this is to add NULL check before drop_super().

"freeze ploop" might "thaw" immediately if !sb. Yeah, this is racy, but 
the chances of such a race are negligibly slim. On the other hand, your 
fix for freeze_bdev() is so simple and straightforward, that I'd vote 
for that (even if the fix is rejected upstream for some reasons).
Thanks,
Maxim


More information about the Devel mailing list