[PATCH v1 01/34] virDevMapperGetTargetsImpl: Close /dev/mapper/control in the end

Michal Privoznik mprivozn at redhat.com
Wed Jul 22 12:14:38 UTC 2020


On 7/22/20 12:46 PM, Daniel P. Berrangé wrote:
> On Wed, Jul 22, 2020 at 11:39:55AM +0200, Michal Privoznik wrote:
>> When building domain's private /dev in a namespace, libdevmapper
>> is consulted for getting full dependency tree of domain's disks.
>> The reason is that for a multipath devices all dependent devices
>> must be created in the namespace and allowed in CGroups.
>>
>> However, this approach is very fragile as building of namespace
>> happens in the forked off child process, after mass close of FDs
>> and just before dropping privileges and execing QEMU. And it so
>> happens that when calling libdevmapper APIs, one of them opens
>> /dev/mapper/control and saves the FD into a global variable. The
>> FD is kept open until the lib is unlinked or dm_lib_release() is
>> called explicitly. We are doing neither.
>>
>> This is not a problem when calling the function from libvirtd
>> (when setting up CGroups), but it is a problem when called from
>> the pre-exec hook because we leak the FD into QEMU.
>>
>> Fixes: a30078cb832646177defd256e77c632905f1e6d0
>> Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1858260
>>
>> Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
>> ---
>>   src/util/virdevmapper.c | 1 +
>>   1 file changed, 1 insertion(+)
>>
>> diff --git a/src/util/virdevmapper.c b/src/util/virdevmapper.c
>> index 40a82285f9..1c216fb6c1 100644
>> --- a/src/util/virdevmapper.c
>> +++ b/src/util/virdevmapper.c
>> @@ -156,6 +156,7 @@ virDevMapperGetTargetsImpl(const char *path,
>>       virStringListFree(recursiveDevPaths);
>>       virStringListFree(devPaths);
>>       dm_task_destroy(dmt);
>> +    dm_lib_release();
>>       return ret;
>>   }
> 
> Hmm, this function isn't threadsafe though, so I'm kind of worried about
> us breaking parallel callers.
> 
> For that matter dm_task_run isn't thread safe when it opens the
> FD in the first place either AFAICT.
> 
> This libdevice-mapper.so looks like a bit of a disaster in general, as
> I can't see mutexes acquired anywhere in the public APIs and it has a
> load of static global variables including this FD :-(
> 
> We could put mutex locking around our own virDevMapperGetTargetsImpl
> if we blindly assume nothing else we call may secretly be using
> libdevice-mapper too.
> 
> Makes me wonder though if there's any way we can obtain the info we need
> without touching libdevice-mapper.so at all.

This is sort of resolved in the rest of the series. If we drop this 
patch then after patch 17 which moves populating /dev with domain disks 
into libvirtd rather than forked child, we don't need to call 
dm_lib_release(). But opening will still be unsafe, yes.

Well, looks like devmapper is doing a single ioctl (if I don't count 
VERSION):

ioctl(3</dev/mapper/control>, DM_VERSION, {version=4.0.0, 
data_size=16384, flags=DM_EXISTS_FLAG} => {version=4.42.0, 
data_size=16384, flags=DM_EXISTS_FLAG}) = 0
ioctl(3</dev/mapper/control>, DM_TABLE_DEPS, {version=4.0.0, 
data_size=16384, data_start=312, name="myusb", flags=DM_EXISTS_FLAG} => 
{version=4.42.0, data_size=328, data_start=312, dev=makedev(0xfd, 0x1), 
name="myusb", uuid="CRYPT-LUKS1-12fa3b2b646d43eb82ffd8f671515f93-myusb", 
target_count=1, open_count=0, event_nr=0, 
flags=DM_EXISTS_FLAG|DM_ACTIVE_PRESENT_FLAG, ...}) = 0

so maybe we can use ioctl() ourselves and drop libdevmapper completely?

Michal




More information about the libvir-list mailing list