Friday, December 7, 2018

Get rid of that f..ng "permission denied" error when using -acpitable file=/.. option in libvirt XML guest definition file.

ABSTRACT:

This post relates to how to activate an OEM windows10 when it runs as a kvm guest controlled by libvirt, getting rid of that f..ng "permission denied" you
get using the qemu:arg ... -acpitable command line option within the libvirt XML guest definition file.

WHAT TO DO IF YOU ARE IN HURRY:

Grab your product key out of MSDM ACPI table.
Place your SLIC.bin file in /usr/share/seabios directory and have the XML line to point at it.
<qemu:arg value='-acpitable'/>
<qemu:arg value='file=/usr/share/seabios/SLIC.bin'/>


Run your guest, go to Windows and activate it using the product key you grabbed from MSDM.
Done.

DETAILS:

Let's start from the beginning.
I worked on a Ubuntu hypervisor:
Distributor ID:    Ubuntu
Description:    Ubuntu 18.04.1 LTS
Release:    18.04
Codename:    bionic

Your Windows's OEM activation key is stored on your hardware BIOS in a particular ACPI table named "MSDM". OEM product keys are no more provided as stikers attached to your hardware so we do have to grab it out of that table. The ACPI BIOS tables are all mapped into /sys/firmware/ACPI/tables.
Within a terminal issue the following command:
sudo strings /sys/firmware/acpi/tables/MSDM | grep .*-.*-.*-.*-.*
This will just print your activation (product) key. Save it somewhere as you'll need it later on..

If you try to activate windows just using this key it won't work. One thing is still missing.

You need the digital signature the manufacturer of your PC has got from Microsoft for the Windows OEM licencing and that signature is stored within another ACPI table named "SLIC".
Indeed we do need our Windows OS to be able to access that electronic signature at "activation time".
The only way available to achieve that is to make the SLIC table visible in the guest's BIOS where Windows can then look for and find it.
Qemu allows to achieve this with the command line option "-acpitable file=/path/to/your/SLICtable". Simple. Oh noo, not so simple!

First problem: how do I pass that command line option to qemu considering we are using libvirt?
Fortunately the libvirt developers have foreseen this need and added a provision to add some magic lines in the guest XML definition file useful just for passing qemu specific command line options.
WARNING: only recent (refer to the post date) versions of libvirt support this possibility. Do not expect this to work on older versions of libvirt.

So, assuming your guest is named Wintest, you must edit the XML definition file with the command:
"virsh edit Wintest". Once you have got into the file,
you have to replace the very first line:
<domain type='kvm'>
with:
<domain type='kvm' id='18' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
Then go to the end of the file, locate the last two lines that should look like this:
</devices>
</domain>

and replace them with:
</devices>
<qemu:commandline>
<qemu:arg value='-smbios'/>
<qemu:arg value='type=0,vendor=HP,version=N51,date=04/27/2016,release=1.24'/>
<qemu:arg value='-smbios'/>
<qemu:arg value='type=1,manufacturer=HP,product=HPZ240TowerWorkstation,version=Z240,serial=CZCXXXYYYY,uuid=02B6B0F6-36C5-11E6-9C43-BC0000FA0000,sku=J9C10ES#ABZ,family=103C_53335X'/>
<qemu:arg value='-acpitable'/>
<qemu:arg value='file=/usr/share/seabios/SLIC.bin'/>
</qemu:commandline>
</domain>

The information about your product (vendor, version. uuid, sku etc.) can be obtained with the following commands:
"dmidecode -t 0" and "dmidecode -t 1".
Just copy and paste the relevant information from the output of these commands replacing field by field what you see in the example above (they are the info of my HP Z240 workstation).
I think that the most important one is the UUID; I wouldn't try to change it.

Second problem: how can I get the /usr/share/seabios/SLIC.bin file?
Easy enough you can do that by the following command:
"sudo cat /sys/firmware/acpi/tables/MSDM > /usr/share/seabios/SLIC.bin".

Up to now may be you alreay knew what to do, because the info I've provided up to here can be found on the Net. But following the tips I've found online I dropped in the insane "permissione denied" problem. Whenever I tryed to start my guest I got:
"qemuProcessReportLogError:1914 : internal error: process exited while connecting to monitor: qemu-system-x86_64: -acpitable file=/sys/firmware/acpi/tables/SLIC: can't open file /sys/firmware/acpi/tables/SLIC: Permission denied".

The trick that drove me crazy was that UNLESS YOU PUT THE SLIC.BIN FILE IN /USR/SHARE/SEABIOS/ you'll get stuck with that f..ng "permission denied" error.
File permissions have nothing to do with it. I tried to put the file even in /tmp with 777 permissions and ... still got the "permission denied"..

CONCLUSION

The culprit being "apparmor".
In fact libvirtd is confined within an apparmor profile (libvirt-) while qemu is confined in a different one (libvirt-qemu).
Looking at /etc/apparmor.d/abstractions/libvirt-qemu I realized the the SLIC.bin file HAS to stay within the qemu apparmor realm and that /usr/share/seabios is an directory available to qemu and, frankly speaking, there is no more appropriate place where to put it in...

Done that, you can run your guest, boot win10, go to the activation window, select "change your product key" and type the product key you grabbed from MSDM.
And voilĂ . Done.

I hope this tip will help you save some of your time.
 

Take care.
Emanuele.