[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: [libvirt] Investigation and possible fix of 1361592 - apparmor profiles do not include backing files

On Wed, Aug 15, 2018 at 20:56:35 +0300, Povilas Kanapickas wrote:
> Hi,


> I've looked into why apparmor profiles do not contain exceptions for
> backing files of images which later leads to permission errors due to
> apparmor containment. As of newest libvirt git master, only the first
> level backing image is included, the subsequent images are omitted.
> Below is my investigation of why this issue happens. It is based on
> libvirt git master as of 2018-08-15 (e3e48d7cb82d58). The possible fix
> is easy, but I don't have the background how to write tests for it, so
> it's best that someone who knows the project well completes the fix
> In my case I have the following file hierarchy:
>  - image-master.qcow2 (has backing file image-backing-1.qcow2)
>  - image-backing-1.qcow2 (has backing file image-backing-2.qcow2
>  - image-backing-2.qcow2
> The apparmor profiles are created by the virt-aa-helper tool. The
> get_files function (src/security/virt-aa-helper.c:949) creates a list of
> files that need to be accessed by the virtual machine. The call to
> virDomainDiskDefForeachPath() is responsible for creating the list of
> files required to access each disk given the disk metadata.
> The disk->src argument contains the source file. The expected file
> hierarchy would be this:
> disk->src->path == path/to/image-master.qcow2
> disk->src->backingStore->path == path/to/image-backing-1.qcow2
> disk->src->backingStore->backingStore->path == path/to/image-backing-2.qcow2
> Unfortunately only the first two levels are present and
> disk->src->backingStore->backingStore points to a dummy object.

Yes, this is expected behaviour according to your analysis below.

> The backing store details are filled in virStorageFileGetMetadata()
> call. It calls into virStorageFileGetMetadataRecurse
> (src/util/virstoragefile.c:4789) which will collect metadata for a
> single image and recurse into itself for backing files.
> For us, the following part of virStorageFileGetMetadataRecurse is
> important (simplified for brevity):
> ```
> virStorageFileGetMetadataInternal(src, ..., &backingFormat);
> if (src->backingStoreRaw) {
>     backingStore = ...
>     if (backingFormat == VIR_STORAGE_FILE_AUTO)
>         backingStore->format = VIR_STORAGE_FILE_RAW; [1]
>     else if (backingFormat == VIR_STORAGE_FILE_AUTO_SAFE)
>         backingStore->format = VIR_STORAGE_FILE_AUTO;
>     else
>         backingStore->format = backingFormat;
>     virStorageFileGetMetadataRecurse(backingStore, ...) [2]
> }
> ```
> The crux of the issue seems that the call to
> virStorageFileGetMetadataInternal() for the image-master.qcow2 image
> will set the `backingFormat` return value to VIR_STORAGE_FILE_AUTO. The

This means that the image-master.qcow2 image does NOT have the backing
format recorded in the metadata and thus we select the automatic format.

The automatic format is insecure though. A mailicious VM could write a
qcow2 header into an otherwise raw file and then the hypervisor would
happily open that file for you as a backing image.

We've swithched off automatic image probing a long time ago and actually
removed all the corresponding code some time ago.

> code responsible is in qcowXGetBackingStore
> (src/util/virstoragefile.c:491) called via
> `fileTypeInfo[meta->format].getBackingStore(...)` at
> src/util/virstoragefile.c:1042.
> It backingFormat is then downgraded to VIR_STORAGE_FILE_RAW at
> src/util/virstoragefile.c:4854 ([1] above). This causes the next recurse
> call to virStorageFileGetMetadataRecurse() ([2] above) to not
> investigate the backing images at all in
> virStorageFileGetMetadataInternal() as
> fileTypeInfo[VIR_STORAGE_FILE_RAW].getBackingStore will be NULL.

This is correct and desired behaviour if the user does not configure the
backing store format explicitly.

> The possible solution is to return VIR_STORAGE_FILE_AUTO_SAFE from
> qcowXGetBackingStore.  It probably does not make much sense to prevent
> probing of qcow2 backing images as we probe the first level of backing
> images anyway, so that return value only affect second and subsequent

The first level is probed as the user has to declare the format in the
XML file and thus we can use that as a authorized value.

In that case we open the file as qcow2 and read the 'backing_file' and
'backing_format' headers.

The 'backing_format' header is then used as an authoritative format for
the subsequent layers.

If the image is missing that value we use AUTO and stop probing there
due to the reasons above.

> levels of backing images. Looking into the implementation of
> qcowXGetBackingStore it also does not seem that it performs any
> operations that are unsafe by design.

I don't think there's a good enough reason to relax this check and I did
not even think about the security implications.

The issue does not happen if you use images which were used somehow in
the libvirt VM lifecycle since the snapshot operation as we use
explicitly specified format everywhere.

> Currently VIR_STORAGE_FILE_AUTO is used only in qedGetBackingStore and
> it does not seem that probing of qcow images is unsafe enough
> What do the developers think about this? Could someone complete the fix
> with tests or advise me about the testing frameworks if there's not
> enough time?

To fix this you should record the backing format [1] into your overlay
image. If we'd relax the code we'd face the regression in the security
fix we've done.

[1] qemu-img creage -f qcow2 -F qcow2 -b backing-qcow2 overlay.qcow2

-F option specifies the format of the backing file

Attachment: signature.asc
Description: PGP signature

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]