On 1/14/26 20:39, Erik Huelsmann wrote:
> Hi Michal,
> 
> Thank you for your super quick response - including patches, no less!
> 
>>> Several months ago, I ran into issue #135 which says that Qemu under
>>> AppArmor can't access LVM volume disks.
> 
>> The problem here is, that AppArmor driver in libvirt generates the
>> profile in qemuSecurityGenLabel() phase. Long story short, starting up a
>> libvirt domain is broken down into several steps. One of them is
>> qemuProcessPrepareDomain() where domain XML is filled with (parts of)
>> live data. In this specific case, disk source is translated (from
>> storage pool/vol to a filepath). But it's not just that, various other
>> paths are generated (e.g. socket paths, render nodes for graphics,
>> etc.).
> 
> Thanks for this context. Yes, I was unaware of that situation and
> completely focussed at the volume paths. Taking the extra paths into
> account complicates the matter.
> 
>> Then, the next step is qemuProcessPrepareHost() where those files from
>> previous step are created, their seclabels are (possibly) set. This has
>> a caveat though.
> 
>> Initially, libvirt cared about SELinux only (leave traditional uid/gid
>> perms (we call them DAC) aside for a brief moment). Here. an unique
>> seclabel is generated in the domain prepare phase, so that any helper
>> process that's used to create files in host prepare phase can run under
>> that label (and thus be restricted).
> 
>> AppArmor does not work this way. So when an aforementioned helper
>> process wants to run (say /usr/bin/swtpm_setup) it already needs profile
>> to be defined. As "obvious" workaround, AppArmor generates the profile
>> in seclabel generation phase. But by that time path are not populated!
> 
> I saw your patches. From the patches I concluded that the security
> policy is strictly applicable to Qemu (apparently). That greatly
> simplifies the solution space, but with your proposed patches, I see
> that the learning curve would have been too steep for me to be able to
> come up with a solution this simple.

Yeah, learning curve is a bit steep, libvirt's a large project after all.

> 
>> IMO, quick and dirty fix would be to generate seclabels at the end of
>> qemuProcessPrepareDomain() instead of beginning (see below). The only
>> downside of this is that seclabels won't be available upfront, e.g. if
>> we want to copy them into a device specific seclabel (we do NOT do that
>> though).
>> diff --git i/src/qemu/qemu_process.c w/src/qemu/qemu_process.c
>> index a53bb40783..00b9a732f3 100644
>> --- i/src/qemu/qemu_process.c
>> +++ w/src/qemu/qemu_process.c
>> @@ -7024,15 +7024,6 @@ qemuProcessPrepareDomain(virQEMUDriver *driver,
>>          return -1;
>>
>>      if (!(flags & VIR_QEMU_PROCESS_START_PRETEND)) {
>> -        /* If you are using a SecurityDriver with dynamic labelling,
>> -           then generate a security label for isolation */
>> -        VIR_DEBUG("Generating domain security label (if required)");
>> -        if (qemuSecurityGenLabel(driver->securityManager, vm->def) < 0) {
>> -            virDomainAuditSecurityLabel(vm, false);
>> -            return -1;
>> -        }
>> -        virDomainAuditSecurityLabel(vm, true);
>> -
>>          if (qemuProcessPrepareDomainNUMAPlacement(vm) < 0)
>>              return -1;
>>      }
>> @@ -7154,6 +7145,17 @@ qemuProcessPrepareDomain(virQEMUDriver *driver,
>>          }
>>      }
>>
>> +    /* Keep this as the very last step because AppArmor already generates
>> +     * profile at this point. IOW, we need all the paths filled in. */
>> +    if (!(flags & VIR_QEMU_PROCESS_START_PRETEND)) {
>> +        VIR_DEBUG("Generating domain security label (if required)");
>> +        if (qemuSecurityGenLabel(driver->securityManager, vm->def) < 0) {
>> +            virDomainAuditSecurityLabel(vm, false);
>> +            return -1;
>> +        }
>> +        virDomainAuditSecurityLabel(vm, true);
>> +    }
>> +
>>      return 0;
>>  }
>>
>>
>>
>> Another alternative is to move profile generation into its separate
>> step. So then we'd have:
>>
>> qemuProcessPrepareDomain():
>>   1) gen seclabel /* here only SELinux/DAC drivers would do something 
>> useful. For AppArmor it'd be a NOP. */
>>   2) generate all the paths
>>   3) write profile /* only AppArmor would act upon, for SELinux and AppArmor 
>> it'd be nop. */
>>
>> Let me see if that'd would fix the issue.
> 
> From the fact that you submitted the patches, I think I understand the
> change above didn't work.

It did, but I'm not sure about all the implications of it. I mean, if
there's something, hidden under a dozen of function calls from
qemuProcessPrepareDomain() that expects seclabel to be generated, then
moving the generation at the end is no good.

> Is there anything I can do to help this
> patch set?

You can test the patch set and if it works you can reply to the cover
letter with your Tested-by tag.

Michal

Reply via email to