2
* AppArmor security driver for libvirt
3
* Copyright (C) 2011 Red Hat, Inc.
4
* Copyright (C) 2009-2010 Canonical Ltd.
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
12
* Jamie Strandboge <jamie@canonical.com>
13
* Based on security_selinux.c by James Morris <jmorris@namei.org>
15
* AppArmor security driver.
20
#include <sys/types.h>
23
#include <sys/apparmor.h>
30
#include "security_apparmor.h"
33
#include "virterror_internal.h"
34
#include "datatypes.h"
39
#include "configmake.h"
43
#define VIR_FROM_THIS VIR_FROM_SECURITY
44
#define SECURITY_APPARMOR_VOID_DOI "0"
45
#define SECURITY_APPARMOR_NAME "apparmor"
46
#define VIRT_AA_HELPER LIBEXECDIR "/virt-aa-helper"
48
/* Data structure to pass to *FileIterate so we have everything we need */
50
virSecurityManagerPtr mgr;
55
* profile_status returns '-1' on error, '0' if loaded
57
* If check_enforcing is set to '1', then returns '-1' on error, '0' if
58
* loaded in complain mode, and '1' if loaded in enforcing mode.
61
profile_status(const char *str, const int check_enforcing)
68
/* create string that is '<str> \0' for accurate matching */
69
if (virAsprintf(&tmp, "%s ", str) == -1) {
74
if (check_enforcing != 0) {
75
/* create string that is '<str> (enforce)\0' for accurate matching */
76
if (virAsprintf(&etmp, "%s (enforce)", str) == -1) {
83
if (virFileReadAll(APPARMOR_PROFILES_PATH, MAX_FILE_LEN, &content) < 0) {
84
virReportSystemError(errno,
85
_("Failed to read AppArmor profiles list "
86
"\'%s\'"), APPARMOR_PROFILES_PATH);
90
if (strstr(content, tmp) != NULL)
92
if (check_enforcing != 0) {
93
if (rc == 0 && strstr(content, etmp) != NULL)
94
rc = 1; /* return '1' if loaded and enforcing */
106
profile_loaded(const char *str)
108
return profile_status(str, 0);
112
* profile_status_file returns '-1' on error, '0' if file on disk is in
113
* complain mode and '1' if file on disk is in enforcing mode
116
profile_status_file(const char *str)
118
char *profile = NULL;
119
char *content = NULL;
124
if (virAsprintf(&profile, "%s/%s", APPARMOR_DIR "/libvirt", str) == -1) {
129
if (!virFileExists(profile))
132
if ((len = virFileReadAll(profile, MAX_FILE_LEN, &content)) < 0) {
133
virReportSystemError(errno,
134
_("Failed to read \'%s\'"), profile);
138
/* create string that is ' <str> flags=(complain)\0' */
139
if (virAsprintf(&tmp, " %s flags=(complain)", str) == -1) {
144
if (strstr(content, tmp) != NULL)
158
* load (add) a profile. Will create one if necessary
161
load_profile(virSecurityManagerPtr mgr,
171
const char *probe = virSecurityManagerGetAllowDiskFormatProbing(mgr)
174
xml = virDomainDefFormat(vm->def, VIR_DOMAIN_XML_SECURE);
178
if (profile_status_file(profile) >= 0)
181
cmd = virCommandNewArgList(VIRT_AA_HELPER, "-p", probe,
182
create ? "-c" : "-r",
183
"-u", profile, NULL);
186
virCommandAddArgList(cmd, "-F", fn, NULL);
188
virCommandAddArgList(cmd, "-f", fn, NULL);
192
virCommandSetInputBuffer(cmd, xml);
193
rc = virCommandRun(cmd, NULL);
202
remove_profile(const char *profile)
205
const char * const argv[] = {
206
VIRT_AA_HELPER, "-R", "-u", profile, NULL
209
if (virRun(argv, NULL) == 0)
216
get_profile_name(virDomainObjPtr vm)
218
char uuidstr[VIR_UUID_STRING_BUFLEN];
221
virUUIDFormat(vm->def->uuid, uuidstr);
222
if (virAsprintf(&name, "%s%s", AA_PREFIX, uuidstr) < 0) {
230
/* returns -1 on error or profile for libvirtd is unconfined, 0 if complain
231
* mode and 1 if enforcing. This is required because at present you cannot
232
* aa_change_profile() from a process that is unconfined.
238
char *libvirt_daemon = NULL;
240
if (virFileResolveLink("/proc/self/exe", &libvirt_daemon) < 0) {
241
virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
242
"%s", _("could not find libvirtd"));
246
if (access(APPARMOR_PROFILES_PATH, R_OK) != 0)
249
rc = profile_status(libvirt_daemon, 1);
252
VIR_FREE(libvirt_daemon);
256
/* reload the profile, adding read/write file specified by fn if it is not
260
reload_profile(virSecurityManagerPtr mgr,
265
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
267
char *profile_name = NULL;
269
if (secdef->norelabel)
272
if ((profile_name = get_profile_name(vm)) == NULL)
275
/* Update the profile only if it is loaded */
276
if (profile_loaded(secdef->imagelabel) >= 0) {
277
if (load_profile(mgr, secdef->imagelabel, vm, fn, append) < 0) {
278
virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
279
_("cannot update AppArmor profile "
288
VIR_FREE(profile_name);
294
AppArmorSetSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED,
295
const char *file, void *opaque)
297
struct SDPDOP *ptr = opaque;
298
virDomainObjPtr vm = ptr->vm;
300
if (reload_profile(ptr->mgr, vm, file, true) < 0) {
301
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
302
virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
303
_("cannot update AppArmor profile "
312
AppArmorSetSecurityPCILabel(pciDevice *dev ATTRIBUTE_UNUSED,
313
const char *file, void *opaque)
315
struct SDPDOP *ptr = opaque;
316
virDomainObjPtr vm = ptr->vm;
318
if (reload_profile(ptr->mgr, vm, file, true) < 0) {
319
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
320
virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
321
_("cannot update AppArmor profile "
329
/* Called on libvirtd startup to see if AppArmor is available */
331
AppArmorSecurityManagerProbe(void)
333
char *template = NULL;
334
int rc = SECURITY_DRIVER_DISABLE;
336
if (use_apparmor() < 0)
339
/* see if template file exists */
340
if (virAsprintf(&template, "%s/TEMPLATE",
341
APPARMOR_DIR "/libvirt") == -1) {
346
if (!virFileExists(template)) {
347
virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
348
_("template \'%s\' does not exist"), template);
351
rc = SECURITY_DRIVER_ENABLE;
359
/* Security driver initialization. DOI is for 'Domain of Interpretation' and is
360
* currently not used.
363
AppArmorSecurityManagerOpen(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
369
AppArmorSecurityManagerClose(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
375
AppArmorSecurityManagerGetModel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
377
return SECURITY_APPARMOR_NAME;
381
AppArmorSecurityManagerGetDOI(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
383
return SECURITY_APPARMOR_VOID_DOI;
387
/* Currently called in qemudStartVMDaemon to setup a 'label'. We look for and
388
* use a profile based on the UUID, otherwise create one based on a template.
389
* Keep in mind that this is called on 'start' with RestoreSecurityLabel being
390
* called on shutdown.
393
AppArmorGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
397
char *profile_name = NULL;
399
if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC)
402
if (vm->def->seclabel.baselabel) {
403
virSecurityReportError(VIR_ERR_CONFIG_UNSUPPORTED,
404
"%s", _("Cannot set a base label with AppArmour"));
408
if ((vm->def->seclabel.label) ||
409
(vm->def->seclabel.model) || (vm->def->seclabel.imagelabel)) {
410
virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
412
_("security label already defined for VM"));
416
if ((profile_name = get_profile_name(vm)) == NULL)
419
vm->def->seclabel.label = strndup(profile_name, strlen(profile_name));
420
if (!vm->def->seclabel.label) {
425
/* set imagelabel the same as label (but we won't use it) */
426
vm->def->seclabel.imagelabel = strndup(profile_name,
427
strlen(profile_name));
428
if (!vm->def->seclabel.imagelabel) {
433
vm->def->seclabel.model = strdup(SECURITY_APPARMOR_NAME);
434
if (!vm->def->seclabel.model) {
439
/* Now that we have a label, load the profile into the kernel. */
440
if (load_profile(mgr, vm->def->seclabel.label, vm, NULL, false) < 0) {
441
virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
442
_("cannot load AppArmor profile "
443
"\'%s\'"), vm->def->seclabel.label);
451
VIR_FREE(vm->def->seclabel.label);
452
VIR_FREE(vm->def->seclabel.imagelabel);
453
VIR_FREE(vm->def->seclabel.model);
456
VIR_FREE(profile_name);
462
AppArmorSetSecurityAllLabel(virSecurityManagerPtr mgr,
463
virDomainObjPtr vm, const char *stdin_path)
465
if (vm->def->seclabel.norelabel)
468
/* Reload the profile if stdin_path is specified. Note that
469
GenSecurityLabel() will have already been run. */
471
return reload_profile(mgr, vm, stdin_path, true);
476
/* Seen with 'virsh dominfo <vm>'. This function only called if the VM is
480
AppArmorGetSecurityProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
482
virSecurityLabelPtr sec)
485
char *profile_name = NULL;
487
if ((profile_name = get_profile_name(vm)) == NULL)
490
if (virStrcpy(sec->label, profile_name,
491
VIR_SECURITY_LABEL_BUFLEN) == NULL) {
492
virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
493
"%s", _("error copying profile name"));
497
if ((sec->enforcing = profile_status(profile_name, 1)) < 0) {
498
virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
499
"%s", _("error calling profile_status()"));
505
VIR_FREE(profile_name);
510
/* Called on VM shutdown and destroy. See AppArmorGenSecurityLabel (above) for
511
* more details. Currently called via qemudShutdownVMDaemon.
514
AppArmorReleaseSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
517
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
519
VIR_FREE(secdef->model);
520
VIR_FREE(secdef->label);
521
VIR_FREE(secdef->imagelabel);
528
AppArmorRestoreSecurityAllLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
530
int migrated ATTRIBUTE_UNUSED)
532
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
535
if (secdef->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
536
if ((rc = remove_profile(secdef->label)) != 0) {
537
virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
538
_("could not remove profile for \'%s\'"),
545
/* Called via virCommand hook. Output goes to
546
* LOCALSTATEDIR/log/libvirt/qemu/<vm name>.log
549
AppArmorSetSecurityProcessLabel(virSecurityManagerPtr mgr, virDomainObjPtr vm)
551
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
553
char *profile_name = NULL;
555
if ((profile_name = get_profile_name(vm)) == NULL)
558
if (STRNEQ(virSecurityManagerGetModel(mgr), secdef->model)) {
559
virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
560
_("security label driver mismatch: "
561
"\'%s\' model configured for domain, but "
562
"hypervisor driver is \'%s\'."),
563
secdef->model, virSecurityManagerGetModel(mgr));
564
if (use_apparmor() > 0)
568
if (aa_change_profile(profile_name) < 0) {
569
virSecurityReportError(VIR_ERR_INTERNAL_ERROR, "%s",
570
_("error calling aa_change_profile()"));
576
VIR_FREE(profile_name);
582
AppArmorSetSecurityDaemonSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
583
virDomainObjPtr vm ATTRIBUTE_UNUSED)
589
AppArmorSetSecuritySocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
590
virDomainObjPtr vm ATTRIBUTE_UNUSED)
596
AppArmorClearSecuritySocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
597
virDomainObjPtr vm ATTRIBUTE_UNUSED)
603
/* Called when hotplugging */
605
AppArmorRestoreSecurityImageLabel(virSecurityManagerPtr mgr,
607
virDomainDiskDefPtr disk ATTRIBUTE_UNUSED)
609
return reload_profile(mgr, vm, NULL, false);
612
/* Called when hotplugging */
614
AppArmorSetSecurityImageLabel(virSecurityManagerPtr mgr,
615
virDomainObjPtr vm, virDomainDiskDefPtr disk)
617
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
621
if (secdef->norelabel)
624
if (!disk->src || disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK)
627
if (secdef->imagelabel) {
628
/* if the device doesn't exist, error out */
629
if (!virFileExists(disk->src)) {
630
virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
631
_("\'%s\' does not exist"), disk->src);
635
if ((profile_name = get_profile_name(vm)) == NULL)
638
/* update the profile only if it is loaded */
639
if (profile_loaded(secdef->imagelabel) >= 0) {
640
if (load_profile(mgr, secdef->imagelabel, vm, disk->src,
642
virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
643
_("cannot update AppArmor profile "
653
VIR_FREE(profile_name);
659
AppArmorSecurityVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
662
const virSecurityLabelDefPtr secdef = &def->seclabel;
664
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) {
665
if (use_apparmor() < 0 || profile_status(secdef->label, 0) < 0) {
666
virSecurityReportError(VIR_ERR_XML_ERROR,
667
_("Invalid security label \'%s\'"),
676
AppArmorReserveSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
677
virDomainObjPtr vm ATTRIBUTE_UNUSED)
679
/* NOOP. Nothing to reserve with AppArmor */
684
AppArmorSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
686
virDomainHostdevDefPtr dev)
689
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
693
if (secdef->norelabel)
696
if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
699
if (profile_loaded(secdef->imagelabel) < 0)
702
if (VIR_ALLOC(ptr) < 0)
707
switch (dev->source.subsys.type) {
708
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
709
usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus,
710
dev->source.subsys.u.usb.device);
715
ret = usbDeviceFileIterate(usb, AppArmorSetSecurityUSBLabel, ptr);
720
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
721
pciDevice *pci = pciGetDevice(dev->source.subsys.u.pci.domain,
722
dev->source.subsys.u.pci.bus,
723
dev->source.subsys.u.pci.slot,
724
dev->source.subsys.u.pci.function);
729
ret = pciDeviceFileIterate(pci, AppArmorSetSecurityPCILabel, ptr);
746
AppArmorRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr,
748
virDomainHostdevDefPtr dev ATTRIBUTE_UNUSED)
751
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
752
if (secdef->norelabel)
755
return reload_profile(mgr, vm, NULL, false);
759
AppArmorSetSavedStateLabel(virSecurityManagerPtr mgr,
761
const char *savefile)
763
return reload_profile(mgr, vm, savefile, true);
768
AppArmorRestoreSavedStateLabel(virSecurityManagerPtr mgr,
770
const char *savefile ATTRIBUTE_UNUSED)
772
return reload_profile(mgr, vm, NULL, false);
776
AppArmorSetImageFDLabel(virSecurityManagerPtr mgr,
782
char *fd_path = NULL;
784
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
786
if (secdef->imagelabel == NULL)
789
if (virAsprintf(&proc, "/proc/self/fd/%d", fd) == -1) {
794
if (virFileResolveLink(proc, &fd_path) < 0) {
795
/* it's a deleted file, presumably. Ignore? */
796
VIR_WARN("could not find path for descriptor %s, skipping", proc);
800
return reload_profile(mgr, vm, fd_path, true);
803
virSecurityDriver virAppArmorSecurityDriver = {
805
SECURITY_APPARMOR_NAME,
806
AppArmorSecurityManagerProbe,
807
AppArmorSecurityManagerOpen,
808
AppArmorSecurityManagerClose,
810
AppArmorSecurityManagerGetModel,
811
AppArmorSecurityManagerGetDOI,
813
AppArmorSecurityVerify,
815
AppArmorSetSecurityImageLabel,
816
AppArmorRestoreSecurityImageLabel,
818
AppArmorSetSecurityDaemonSocketLabel,
819
AppArmorSetSecuritySocketLabel,
820
AppArmorClearSecuritySocketLabel,
822
AppArmorGenSecurityLabel,
823
AppArmorReserveSecurityLabel,
824
AppArmorReleaseSecurityLabel,
826
AppArmorGetSecurityProcessLabel,
827
AppArmorSetSecurityProcessLabel,
829
AppArmorSetSecurityAllLabel,
830
AppArmorRestoreSecurityAllLabel,
832
AppArmorSetSecurityHostdevLabel,
833
AppArmorRestoreSecurityHostdevLabel,
835
AppArmorSetSavedStateLabel,
836
AppArmorRestoreSavedStateLabel,
838
AppArmorSetImageFDLabel,