[libvirt] [PATCH 2/2] virSecurityManagerMetadataLock: Skip over duplicate paths

Daniel Henrique Barboza danielhb413 at gmail.com
Thu Jul 18 12:52:27 UTC 2019



On 7/18/19 8:30 AM, Michal Privoznik wrote:
> On 7/18/19 11:28 AM, Daniel P. Berrangé wrote:
>> On Thu, Jul 18, 2019 at 11:14:49AM +0200, Michal Privoznik wrote:
>>> If there are two paths on the list that are the same we need to
>>> lock it only once. Because when we try to lock it the second time
>>> then open() fails. And if it didn't, locking it the second time
>>> would fail for sure. After all, it is sufficient to lock all
>>> paths just once satisfy the caller.
>>>
>>> Reported-by: Daniel Henrique Barboza <danielhb413 at gmail.com>
>>> Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
>>> ---
>>>   src/security/security_manager.c | 23 +++++++++++++++++++++--
>>>   1 file changed, 21 insertions(+), 2 deletions(-)
>>
>> Reviewed-by: Daniel P. Berrangé <berrange at redhat.com>
>>
>>
>>>
>>> diff --git a/src/security/security_manager.c 
>>> b/src/security/security_manager.c
>>> index ade2c96141..7c905f0785 100644
>>> --- a/src/security/security_manager.c
>>> +++ b/src/security/security_manager.c
>>> @@ -1294,16 +1294,35 @@ 
>>> virSecurityManagerMetadataLock(virSecurityManagerPtr mgr 
>>> ATTRIBUTE_UNUSED,
>>>        * paths A B and there's another that is trying to lock them
>>>        * in reversed order a deadlock might occur.  But if we sort
>>>        * the paths alphabetically then both processes will try lock
>>> -     * paths in the same order and thus no deadlock can occur. */
>>> +     * paths in the same order and thus no deadlock can occur.
>>> +     * Lastly, it makes searching for duplicate paths below
>>> +     * simpler. */
>>>       qsort(paths, npaths, sizeof(*paths), cmpstringp);
>>>         for (i = 0; i < npaths; i++) {
>>>           const char *p = paths[i];
>>>           struct stat sb;
>>> +        size_t j;
>>>           int retries = 10 * 1000;
>>>           int fd;
>>>   -        if (!p || stat(p, &sb) < 0)
>>> +        if (!p)
>>> +            continue;
>>> +
>>> +        /* If there's a duplicate path on the list, skip it over.
>>> +         * Not only we would fail open()-ing it the second time,
>>> +         * we would deadlock with ourselves trying to lock it the
>>> +         * second time. After all, we've locked it when iterating
>>> +         * over it the first time. */
>>
>> Presumably this deals with the problem at cold boot. Is it possible
>> to hit the same problem when we have cold plugged one device and
>> then later try to hotplug another device using the same resource,
>> or do the SRIOV assignment grouping requirements make the hotplug
>> impossible ?
>
> Okay, so digging deeper I think I know what the problem is. In 
> general, it is of course possible to open a file multiple times, but 
> that is not true for "/dev/vfio/N" which can be opened exactly one 
> time. Indeed, looking into vfio_group_fops_open() in 
> kernel.git/drivers/vfio/vfio.c if a group is already opened, then 
> -EBUSY is returned (what we've seen in the error message). In fact, 
> git log blames v3.11-rc1~46^2~1 which explicitly disallowed multiple 
> open()-s.
>
> So, in theory, our code works, because we open() the files we are 
> chown()-ing and close them immediatelly after. So the problem in which 
> we try to lock /dev/vfio/N multiple times won't happen. However, since 
> qemu already has the device opened, we will fail opening it.
>
> I can see two options here:
>
> 1) ignore this specific error in virSecurityManagerMetadataLock(). 
> This will of course mean that the caller 
> (virSecurityDACTransactionRun()) will chown() the /dev/vfio/N file 
> without a lock, but then again, we have namespaces and there can't be 
> any other domain using the path. And also, we don't really chown() if 
> the file already has the correct owner - which is going to be 99.99% 
> cases unless there would be different seclabels for two PCI devices 
> (do we even allow <seclabel/> for <hostdev/>?).

This option seems better to me because it already establishes an 
exception rule for
files that can be opened only once. For now we found out about 
/dev/vfio/N files,  but
there might be more in the future, and then it is just a matter of 
adding more files
to this exception rule.


Thanks,


DHB

>
> 2) Make virSecurityDACSetHostdevLabel() and 
> virSecurityDACRestoreHostdevLabel() be NO-OP if a domain already/still 
> has a device from the same IOMMU group like the one we're 
> attaching/detaching. If these are NO-OPs then no relabel is done and 
> thus the whole code I'm modifying in 1) is not even called.
>
> I have a preference for 1) because the code will be cleaner IMO.
>
> Michal




More information about the libvir-list mailing list