1 /*
2  * Copyright (C) 2010-2014 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library.  If not, see
16  * <http://www.gnu.org/licenses/>.
17  *
18  * POSIX DAC security driver
19  */
20 
21 #include <config.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 
26 #ifdef  __FreeBSD__
27 # include <sys/sysctl.h>
28 # include <sys/user.h>
29 #endif
30 
31 #include "security_dac.h"
32 #include "security_util.h"
33 #include "virerror.h"
34 #include "virfile.h"
35 #include "viralloc.h"
36 #include "virlog.h"
37 #include "virmdev.h"
38 #include "virpci.h"
39 #include "virusb.h"
40 #include "virscsi.h"
41 #include "virscsivhost.h"
42 #include "virstoragefile.h"
43 #include "virstring.h"
44 #include "virutil.h"
45 
46 #define VIR_FROM_THIS VIR_FROM_SECURITY
47 
48 VIR_LOG_INIT("security.security_dac");
49 
50 #define SECURITY_DAC_NAME "dac"
51 #define DEV_SEV "/dev/sev"
52 
53 typedef struct _virSecurityDACData virSecurityDACData;
54 struct _virSecurityDACData {
55     uid_t user;
56     gid_t group;
57     gid_t *groups;
58     int ngroups;
59     bool dynamicOwnership;
60     bool mountNamespace;
61     char *baselabel;
62     virSecurityManagerDACChownCallback chownCallback;
63 };
64 
65 typedef struct _virSecurityDACCallbackData virSecurityDACCallbackData;
66 struct _virSecurityDACCallbackData {
67     virSecurityManager *manager;
68     virSecurityLabelDef *secdef;
69 };
70 
71 typedef struct _virSecurityDACChownItem virSecurityDACChownItem;
72 struct _virSecurityDACChownItem {
73     char *path;
74     const virStorageSource *src;
75     uid_t uid;
76     gid_t gid;
77     bool remember; /* Whether owner remembering should be done for @path/@src */
78     bool restore; /* Whether current operation is 'set' or 'restore' */
79 };
80 
81 typedef struct _virSecurityDACChownList virSecurityDACChownList;
82 struct _virSecurityDACChownList {
83     virSecurityManager *manager;
84     virSecurityDACChownItem **items;
85     size_t nItems;
86     bool lock;
87 };
88 
89 
90 virThreadLocal chownList;
91 
92 static void
virSecurityDACChownItemFree(virSecurityDACChownItem * item)93 virSecurityDACChownItemFree(virSecurityDACChownItem *item)
94 {
95     if (!item)
96         return;
97 
98     g_free(item->path);
99     g_free(item);
100 }
101 
102 G_DEFINE_AUTOPTR_CLEANUP_FUNC(virSecurityDACChownItem, virSecurityDACChownItemFree);
103 
104 static int
virSecurityDACChownListAppend(virSecurityDACChownList * list,const char * path,const virStorageSource * src,uid_t uid,gid_t gid,bool remember,bool restore)105 virSecurityDACChownListAppend(virSecurityDACChownList *list,
106                               const char *path,
107                               const virStorageSource *src,
108                               uid_t uid,
109                               gid_t gid,
110                               bool remember,
111                               bool restore)
112 {
113     g_autoptr(virSecurityDACChownItem) item = NULL;
114 
115     item = g_new0(virSecurityDACChownItem, 1);
116 
117     item->path = g_strdup(path);
118     item->src = src;
119     item->uid = uid;
120     item->gid = gid;
121     item->remember = remember;
122     item->restore = restore;
123 
124     VIR_APPEND_ELEMENT(list->items, list->nItems, item);
125 
126     return 0;
127 }
128 
129 static void
virSecurityDACChownListFree(void * opaque)130 virSecurityDACChownListFree(void *opaque)
131 {
132     virSecurityDACChownList *list = opaque;
133     size_t i;
134 
135     if (!list)
136         return;
137 
138     for (i = 0; i < list->nItems; i++)
139         virSecurityDACChownItemFree(list->items[i]);
140     g_free(list->items);
141     virObjectUnref(list->manager);
142     g_free(list);
143 }
144 
145 G_DEFINE_AUTOPTR_CLEANUP_FUNC(virSecurityDACChownList, virSecurityDACChownListFree);
146 
147 
148 /**
149  * virSecurityDACTransactionAppend:
150  * @path: Path to chown
151  * @src: disk source to chown
152  * @uid: user ID
153  * @gid: group ID
154  * @remember: if the original owner should be recorded/recalled
155  * @restore: if current operation is set or restore
156  *
157  * Appends an entry onto transaction list.
158  * The @remember should be true if caller wishes to record/recall
159  * the original owner of @path/@src.
160  * The @restore should be true if the operation is restoring
161  * seclabel and false otherwise.
162  *
163  * Returns: 1 in case of successful append
164  *          0 if there is no transaction enabled
165  *         -1 otherwise.
166  */
167 static int
virSecurityDACTransactionAppend(const char * path,const virStorageSource * src,uid_t uid,gid_t gid,bool remember,bool restore)168 virSecurityDACTransactionAppend(const char *path,
169                                 const virStorageSource *src,
170                                 uid_t uid,
171                                 gid_t gid,
172                                 bool remember,
173                                 bool restore)
174 {
175     virSecurityDACChownList *list = virThreadLocalGet(&chownList);
176     if (!list)
177         return 0;
178 
179     if (virSecurityDACChownListAppend(list, path, src,
180                                       uid, gid, remember, restore) < 0)
181         return -1;
182 
183     return 1;
184 }
185 
186 
187 static int virSecurityDACSetOwnership(virSecurityManager *mgr,
188                                       const virStorageSource *src,
189                                       const char *path,
190                                       uid_t uid,
191                                       gid_t gid,
192                                       bool remember);
193 
194 static int virSecurityDACRestoreFileLabelInternal(virSecurityManager *mgr,
195                                                   const virStorageSource *src,
196                                                   const char *path,
197                                                   bool recall);
198 /**
199  * virSecurityDACTransactionRun:
200  * @pid: process pid
201  * @opaque: opaque data
202  *
203  * This is the callback that runs in the same namespace as the domain we are
204  * relabelling. For given transaction (@opaque) it relabels all the paths on
205  * the list. Depending on security manager configuration it might lock paths
206  * we will relabel.
207  *
208  * Returns: 0 on success
209  *         -1 otherwise.
210  */
211 static int
virSecurityDACTransactionRun(pid_t pid G_GNUC_UNUSED,void * opaque)212 virSecurityDACTransactionRun(pid_t pid G_GNUC_UNUSED,
213                              void *opaque)
214 {
215     virSecurityDACChownList *list = opaque;
216     virSecurityManagerMetadataLockState *state;
217     g_autofree const char **paths = NULL;
218     size_t npaths = 0;
219     size_t i;
220     int rv = 0;
221 
222     if (list->lock) {
223         paths = g_new0(const char *, list->nItems);
224 
225         for (i = 0; i < list->nItems; i++) {
226             virSecurityDACChownItem *item = list->items[i];
227             const char *p = item->path;
228 
229             if (item->remember)
230                 VIR_APPEND_ELEMENT_COPY_INPLACE(paths, npaths, p);
231         }
232 
233         if (!(state = virSecurityManagerMetadataLock(list->manager, paths, npaths)))
234             return -1;
235 
236         for (i = 0; i < list->nItems; i++) {
237             virSecurityDACChownItem *item = list->items[i];
238             size_t j;
239 
240             for (j = 0; j < state->nfds; j++) {
241                 if (STREQ_NULLABLE(item->path, state->paths[j]))
242                     break;
243             }
244 
245             /* If path wasn't locked, don't try to remember its label. */
246             if (j == state->nfds)
247                 item->remember = false;
248         }
249     }
250 
251     for (i = 0; i < list->nItems; i++) {
252         virSecurityDACChownItem *item = list->items[i];
253         const bool remember = item->remember && list->lock;
254 
255         if (!item->restore) {
256             rv = virSecurityDACSetOwnership(list->manager,
257                                             item->src,
258                                             item->path,
259                                             item->uid,
260                                             item->gid,
261                                             remember);
262         } else {
263             rv = virSecurityDACRestoreFileLabelInternal(list->manager,
264                                                         item->src,
265                                                         item->path,
266                                                         remember);
267         }
268 
269         if (rv < 0)
270             break;
271     }
272 
273     for (; rv < 0 && i > 0; i--) {
274         virSecurityDACChownItem *item = list->items[i - 1];
275         const bool remember = item->remember && list->lock;
276 
277         if (!item->restore) {
278             virSecurityDACRestoreFileLabelInternal(list->manager,
279                                                    item->src,
280                                                    item->path,
281                                                    remember);
282         } else {
283             VIR_WARN("Ignoring failed restore attempt on %s",
284                      NULLSTR(item->src ? item->src->path : item->path));
285         }
286     }
287 
288     if (list->lock)
289         virSecurityManagerMetadataUnlock(list->manager, &state);
290 
291     if (rv < 0)
292         return -1;
293 
294     return 0;
295 }
296 
297 
298 /* returns -1 on error, 0 on success */
299 int
virSecurityDACSetUserAndGroup(virSecurityManager * mgr,uid_t user,gid_t group)300 virSecurityDACSetUserAndGroup(virSecurityManager *mgr,
301                               uid_t user,
302                               gid_t group)
303 {
304     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
305     priv->user = user;
306     priv->group = group;
307 
308     priv->baselabel = g_strdup_printf("+%u:+%u", (unsigned int)user,
309                                       (unsigned int)group);
310 
311     return 0;
312 }
313 
314 void
virSecurityDACSetDynamicOwnership(virSecurityManager * mgr,bool dynamicOwnership)315 virSecurityDACSetDynamicOwnership(virSecurityManager *mgr,
316                                   bool dynamicOwnership)
317 {
318     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
319     priv->dynamicOwnership = dynamicOwnership;
320 }
321 
322 void
virSecurityDACSetMountNamespace(virSecurityManager * mgr,bool mountNamespace)323 virSecurityDACSetMountNamespace(virSecurityManager *mgr,
324                                 bool mountNamespace)
325 {
326     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
327     priv->mountNamespace = mountNamespace;
328 }
329 
330 
331 void
virSecurityDACSetChownCallback(virSecurityManager * mgr,virSecurityManagerDACChownCallback chownCallback)332 virSecurityDACSetChownCallback(virSecurityManager *mgr,
333                                virSecurityManagerDACChownCallback chownCallback)
334 {
335     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
336     priv->chownCallback = chownCallback;
337 }
338 
339 /* returns 1 if label isn't found, 0 on success, -1 on error */
340 static int
341 ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
virSecurityDACParseIds(virSecurityLabelDef * seclabel,uid_t * uidPtr,gid_t * gidPtr)342 virSecurityDACParseIds(virSecurityLabelDef *seclabel,
343                        uid_t *uidPtr, gid_t *gidPtr)
344 {
345     if (!seclabel || !seclabel->label)
346         return 1;
347 
348     if (virParseOwnershipIds(seclabel->label, uidPtr, gidPtr) < 0)
349         return -1;
350 
351     return 0;
352 }
353 
354 static int
355 ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
virSecurityDACGetIds(virSecurityLabelDef * seclabel,virSecurityDACData * priv,uid_t * uidPtr,gid_t * gidPtr,gid_t ** groups,int * ngroups)356 virSecurityDACGetIds(virSecurityLabelDef *seclabel,
357                      virSecurityDACData *priv,
358                      uid_t *uidPtr, gid_t *gidPtr,
359                      gid_t **groups, int *ngroups)
360 {
361     int ret;
362 
363     if (groups)
364         *groups = priv ? priv->groups : NULL;
365     if (ngroups)
366         *ngroups = priv ? priv->ngroups : 0;
367 
368     if ((ret = virSecurityDACParseIds(seclabel, uidPtr, gidPtr)) <= 0)
369         return ret;
370 
371     if (!priv) {
372         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
373                        _("DAC seclabel couldn't be determined"));
374         return -1;
375     }
376 
377     *uidPtr = priv->user;
378     *gidPtr = priv->group;
379 
380     return 0;
381 }
382 
383 
384 /* returns 1 if label isn't found, 0 on success, -1 on error */
385 static int
386 ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
virSecurityDACParseImageIds(virSecurityLabelDef * seclabel,uid_t * uidPtr,gid_t * gidPtr)387 virSecurityDACParseImageIds(virSecurityLabelDef *seclabel,
388                             uid_t *uidPtr, gid_t *gidPtr)
389 {
390     if (!seclabel || !seclabel->imagelabel)
391         return 1;
392 
393     if (virParseOwnershipIds(seclabel->imagelabel, uidPtr, gidPtr) < 0)
394         return -1;
395 
396     return 0;
397 }
398 
399 static int
400 ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
virSecurityDACGetImageIds(virSecurityLabelDef * seclabel,virSecurityDACData * priv,uid_t * uidPtr,gid_t * gidPtr)401 virSecurityDACGetImageIds(virSecurityLabelDef *seclabel,
402                           virSecurityDACData *priv,
403                           uid_t *uidPtr, gid_t *gidPtr)
404 {
405     int ret;
406 
407     if ((ret = virSecurityDACParseImageIds(seclabel, uidPtr, gidPtr)) <= 0)
408         return ret;
409 
410     if (!priv) {
411         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
412                        _("DAC imagelabel couldn't be determined"));
413         return -1;
414     }
415 
416     *uidPtr = priv->user;
417     *gidPtr = priv->group;
418 
419     return 0;
420 }
421 
422 /**
423  * virSecurityDACRememberLabel:
424  * @priv: driver's private data
425  * @path: path to the file
426  * @uid: user owning the @path
427  * @gid: group owning the @path
428  *
429  * Remember the owner of @path (represented by @uid:@gid).
430  *
431  * Returns: the @path refcount, or
432  *          -1 on failure
433  */
434 static int
virSecurityDACRememberLabel(virSecurityDACData * priv G_GNUC_UNUSED,const char * path,uid_t uid,gid_t gid)435 virSecurityDACRememberLabel(virSecurityDACData *priv G_GNUC_UNUSED,
436                             const char *path,
437                             uid_t uid,
438                             gid_t gid)
439 {
440     g_autofree char *label = NULL;
441 
442     label = g_strdup_printf("+%u:+%u", (unsigned int)uid, (unsigned int)gid);
443 
444     return virSecuritySetRememberedLabel(SECURITY_DAC_NAME, path, label);
445 }
446 
447 /**
448  * virSecurityDACRecallLabel:
449  * @priv: driver's private data
450  * @path: path to the file
451  * @uid: user owning the @path
452  * @gid: group owning the @path
453  *
454  * Recall the previously recorded owner for the @path. However, it may happen
455  * that @path is still in use (e.g. by another domain). In that case, 1 is
456  * returned and caller should not relabel the @path.
457  *
458  * Returns: 1 if @path is still in use (@uid and @gid not touched)
459  *          0 if @path should be restored (@uid and @gid set)
460  *         -1 on failure (@uid and @gid not touched)
461  */
462 static int
virSecurityDACRecallLabel(virSecurityDACData * priv G_GNUC_UNUSED,const char * path,uid_t * uid,gid_t * gid)463 virSecurityDACRecallLabel(virSecurityDACData *priv G_GNUC_UNUSED,
464                           const char *path,
465                           uid_t *uid,
466                           gid_t *gid)
467 {
468     g_autofree char *label = NULL;
469     int rv;
470 
471     rv = virSecurityGetRememberedLabel(SECURITY_DAC_NAME, path, &label);
472     if (rv < 0)
473         return rv;
474 
475     if (!label)
476         return 1;
477 
478     if (virParseOwnershipIds(label, uid, gid) < 0)
479         return -1;
480 
481     return 0;
482 }
483 
484 static virSecurityDriverStatus
virSecurityDACProbe(const char * virtDriver G_GNUC_UNUSED)485 virSecurityDACProbe(const char *virtDriver G_GNUC_UNUSED)
486 {
487     return SECURITY_DRIVER_ENABLE;
488 }
489 
490 static int
virSecurityDACOpen(virSecurityManager * mgr G_GNUC_UNUSED)491 virSecurityDACOpen(virSecurityManager *mgr G_GNUC_UNUSED)
492 {
493     if (virThreadLocalInit(&chownList,
494                            virSecurityDACChownListFree) < 0) {
495         virReportSystemError(errno, "%s",
496                              _("Unable to initialize thread local variable"));
497         return -1;
498     }
499 
500     return 0;
501 }
502 
503 static int
virSecurityDACClose(virSecurityManager * mgr)504 virSecurityDACClose(virSecurityManager *mgr)
505 {
506     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
507     g_clear_pointer(&priv->groups, g_free);
508     g_clear_pointer(&priv->baselabel, g_free);
509     return 0;
510 }
511 
512 
513 static const char *
virSecurityDACGetModel(virSecurityManager * mgr G_GNUC_UNUSED)514 virSecurityDACGetModel(virSecurityManager *mgr G_GNUC_UNUSED)
515 {
516     return SECURITY_DAC_NAME;
517 }
518 
519 static const char *
virSecurityDACGetDOI(virSecurityManager * mgr G_GNUC_UNUSED)520 virSecurityDACGetDOI(virSecurityManager *mgr G_GNUC_UNUSED)
521 {
522     return "0";
523 }
524 
525 static int
virSecurityDACPreFork(virSecurityManager * mgr)526 virSecurityDACPreFork(virSecurityManager *mgr)
527 {
528     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
529     int ngroups;
530 
531     g_clear_pointer(&priv->groups, g_free);
532     priv->ngroups = 0;
533     if ((ngroups = virGetGroupList(priv->user, priv->group,
534                                    &priv->groups)) < 0)
535         return -1;
536     priv->ngroups = ngroups;
537     return 0;
538 }
539 
540 /**
541  * virSecurityDACTransactionStart:
542  * @mgr: security manager
543  *
544  * Starts a new transaction. In transaction nothing is chown()-ed until
545  * TransactionCommit() is called. This is implemented as a list that is
546  * appended to whenever chown() would be called. Since secdriver APIs
547  * can be called from multiple threads (to work over different domains)
548  * the pointer to the list is stored in thread local variable.
549  *
550  * Returns 0 on success,
551  *        -1 otherwise.
552  */
553 static int
virSecurityDACTransactionStart(virSecurityManager * mgr)554 virSecurityDACTransactionStart(virSecurityManager *mgr)
555 {
556     g_autoptr(virSecurityDACChownList) list = NULL;
557 
558     if (virThreadLocalGet(&chownList)) {
559         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
560                        _("Another relabel transaction is already started"));
561         return -1;
562     }
563 
564     list = g_new0(virSecurityDACChownList, 1);
565 
566     list->manager = virObjectRef(mgr);
567 
568     if (virThreadLocalSet(&chownList, list) < 0) {
569         virReportSystemError(errno, "%s",
570                              _("Unable to set thread local variable"));
571         return -1;
572     }
573     list = NULL;
574 
575     return 0;
576 }
577 
578 /**
579  * virSecurityDACTransactionCommit:
580  * @mgr: security manager
581  * @pid: domain's PID
582  * @lock: lock and unlock paths that are relabeled
583  *
584  * If @pid is not -1 then enter the @pid namespace (usually @pid refers
585  * to a domain) and perform all the chown()-s on the list. If @pid is -1
586  * then the transaction is performed in the namespace of the caller.
587  *
588  * If @lock is true then all the paths that transaction would
589  * touch are locked before and unlocked after it is done so.
590  *
591  * Note that the transaction is also freed, therefore new one has to be
592  * started after successful return from this function. Also it is
593  * considered as error if there's no transaction set and this function
594  * is called.
595  *
596  * Returns: 0 on success,
597  *         -1 otherwise.
598  */
599 static int
virSecurityDACTransactionCommit(virSecurityManager * mgr G_GNUC_UNUSED,pid_t pid,bool lock)600 virSecurityDACTransactionCommit(virSecurityManager *mgr G_GNUC_UNUSED,
601                                 pid_t pid,
602                                 bool lock)
603 {
604     g_autoptr(virSecurityDACChownList) list = NULL;
605     int rc;
606 
607     list = virThreadLocalGet(&chownList);
608     if (!list) {
609         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
610                        _("No transaction is set"));
611         return -1;
612     }
613 
614     if (virThreadLocalSet(&chownList, NULL) < 0) {
615         virReportSystemError(errno, "%s",
616                              _("Unable to clear thread local variable"));
617         return -1;
618     }
619 
620     list->lock = lock;
621 
622     if (pid != -1) {
623         rc = virProcessRunInMountNamespace(pid,
624                                            virSecurityDACTransactionRun,
625                                            list);
626         if (rc < 0) {
627             if (virGetLastErrorCode() == VIR_ERR_SYSTEM_ERROR)
628                 pid = -1;
629             else
630                 return -1;
631         }
632     }
633 
634     if (pid == -1) {
635         if (lock)
636             rc = virProcessRunInFork(virSecurityDACTransactionRun, list);
637         else
638             rc = virSecurityDACTransactionRun(pid, list);
639     }
640 
641     if (rc < 0)
642         return -1;
643 
644     return 0;
645 }
646 
647 /**
648  * virSecurityDACTransactionAbort:
649  * @mgr: security manager
650  *
651  * Cancels and frees any out standing transaction.
652  */
653 static void
virSecurityDACTransactionAbort(virSecurityManager * mgr G_GNUC_UNUSED)654 virSecurityDACTransactionAbort(virSecurityManager *mgr G_GNUC_UNUSED)
655 {
656     g_autoptr(virSecurityDACChownList) list = NULL;
657 
658     list = virThreadLocalGet(&chownList);
659     if (!list)
660         return;
661 
662     if (virThreadLocalSet(&chownList, NULL) < 0)
663         VIR_DEBUG("Unable to clear thread local variable");
664 }
665 
666 
667 static int
virSecurityDACSetOwnershipInternal(const virSecurityDACData * priv,const virStorageSource * src,const char * path,uid_t uid,gid_t gid)668 virSecurityDACSetOwnershipInternal(const virSecurityDACData *priv,
669                                    const virStorageSource *src,
670                                    const char *path,
671                                    uid_t uid,
672                                    gid_t gid)
673 {
674     int rc = 0;
675 
676     /* Be aware that this function might run in a separate process.
677      * Therefore, any driver state changes would be thrown away. */
678 
679     if (src && priv->chownCallback) {
680         rc = priv->chownCallback(src, uid, gid);
681 
682         /* on -2 returned an error was already reported */
683         if (rc == -2)
684             return -1;
685     }
686 
687     if (rc == 0 || rc == -3) {
688         struct stat sb;
689 
690         if (!path)
691             return 0;
692 
693         if (stat(path, &sb) < 0) {
694             virReportSystemError(errno, _("unable to stat: %s"), path);
695             return -1;
696         }
697 
698         if (sb.st_uid == uid && sb.st_gid == gid) {
699             /* nothing to chown */
700             return 0;
701         }
702 
703 #ifdef WIN32
704         rc = -1;
705         errno = ENOSYS;
706 #else /* !WIN32 */
707         rc = chown(path, uid, gid);
708 #endif /* !WIN32 */
709     }
710 
711     if (rc < 0) {
712         if (errno == EOPNOTSUPP || errno == EINVAL) {
713             VIR_INFO("Setting user and group to '%ld:%ld' on '%s' not "
714                      "supported by filesystem",
715                      (long)uid, (long)gid, NULLSTR(path));
716         } else if (errno == EPERM) {
717             VIR_INFO("Setting user and group to '%ld:%ld' on '%s' not "
718                      "permitted",
719                      (long)uid, (long)gid, NULLSTR(path));
720         } else if (errno == EROFS) {
721             VIR_INFO("Setting user and group to '%ld:%ld' on '%s' not "
722                      "possible on readonly filesystem",
723                      (long)uid, (long)gid, NULLSTR(path));
724         } else {
725             virReportSystemError(errno,
726                                  _("unable to set user and group to '%ld:%ld' "
727                                    "on '%s'"),
728                                  (long)uid, (long)gid, NULLSTR(path));
729             return -1;
730         }
731     }
732     return 0;
733 }
734 
735 
736 static int
virSecurityDACSetOwnership(virSecurityManager * mgr,const virStorageSource * src,const char * path,uid_t uid,gid_t gid,bool remember)737 virSecurityDACSetOwnership(virSecurityManager *mgr,
738                            const virStorageSource *src,
739                            const char *path,
740                            uid_t uid,
741                            gid_t gid,
742                            bool remember)
743 {
744     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
745     virErrorPtr origerr;
746     struct stat sb;
747     int refcount;
748     int rc;
749 
750     if (!path && src && src->path &&
751         virStorageSourceIsLocalStorage(src))
752         path = src->path;
753 
754     /* Be aware that this function might run in a separate process.
755      * Therefore, any driver state changes would be thrown away. */
756 
757     if ((rc = virSecurityDACTransactionAppend(path, src,
758                                               uid, gid, remember, false)) < 0)
759         return -1;
760     else if (rc > 0)
761         return 0;
762 
763     if (remember && path) {
764         if (stat(path, &sb) < 0) {
765             virReportSystemError(errno, _("unable to stat: %s"), path);
766             return -1;
767         }
768 
769         refcount = virSecurityDACRememberLabel(priv, path, sb.st_uid, sb.st_gid);
770         if (refcount == -2) {
771             /* Not supported. Don't error though. */
772         } else if (refcount < 0) {
773             return -1;
774         } else if (refcount > 1) {
775             /* Refcount is greater than 1 which means that there
776              * is @refcount domains using the @path. Do not
777              * change the label (as it would almost certainly
778              * cause the other domains to lose access to the
779              * @path). However, the refcounter was incremented in
780              * XATTRs so decrease it. */
781             if (sb.st_uid != uid || sb.st_gid != gid) {
782                 virReportError(VIR_ERR_OPERATION_INVALID,
783                                _("Setting different DAC user or group on %s "
784                                  "which is already in use"), path);
785                 goto error;
786             }
787         }
788     }
789 
790     VIR_INFO("Setting DAC user and group on '%s' to '%ld:%ld'",
791              NULLSTR(src ? src->path : path), (long)uid, (long)gid);
792 
793     if (virSecurityDACSetOwnershipInternal(priv, src, path, uid, gid) < 0)
794         goto error;
795 
796     return 0;
797 
798  error:
799     virErrorPreserveLast(&origerr);
800     /* Try to restore the label. This is done so that XATTRs
801      * are left in the same state as when the control entered
802      * this function. However, if our attempt fails, there's
803      * not much we can do. XATTRs refcounting is fubar'ed and
804      * the only option we have is warn users. */
805     if (virSecurityDACRestoreFileLabelInternal(mgr, src, path, remember) < 0)
806         VIR_WARN("Unable to restore label on '%s'. "
807                  "XATTRs might have been left in inconsistent state.",
808                  NULLSTR(src ? src->path : path));
809 
810     virErrorRestore(&origerr);
811 
812     return -1;
813 }
814 
815 
816 static int
virSecurityDACRestoreFileLabelInternal(virSecurityManager * mgr,const virStorageSource * src,const char * path,bool recall)817 virSecurityDACRestoreFileLabelInternal(virSecurityManager *mgr,
818                                        const virStorageSource *src,
819                                        const char *path,
820                                        bool recall)
821 {
822     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
823     int rv;
824     uid_t uid = 0;  /* By default return to root:root */
825     gid_t gid = 0;
826 
827     if (!path && src && src->path &&
828         virStorageSourceIsLocalStorage(src))
829         path = src->path;
830 
831     /* Be aware that this function might run in a separate process.
832      * Therefore, any driver state changes would be thrown away. */
833 
834     if ((rv = virSecurityDACTransactionAppend(path, src, uid, gid, recall, true)) < 0)
835         return -1;
836     else if (rv > 0)
837         return 0;
838 
839     if (recall && path) {
840         rv = virSecurityDACRecallLabel(priv, path, &uid, &gid);
841         if (rv == -2) {
842             /* Not supported. Don't error though. */
843         } else if (rv < 0) {
844             return -1;
845         } else if (rv > 0) {
846             return 0;
847         }
848     }
849 
850     VIR_INFO("Restoring DAC user and group on '%s' to %ld:%ld",
851              NULLSTR(src ? src->path : path), (long)uid, (long)gid);
852 
853     return virSecurityDACSetOwnershipInternal(priv, src, path, uid, gid);
854 }
855 
856 
857 static int
virSecurityDACRestoreFileLabel(virSecurityManager * mgr,const char * path)858 virSecurityDACRestoreFileLabel(virSecurityManager *mgr,
859                                const char *path)
860 {
861     return virSecurityDACRestoreFileLabelInternal(mgr, NULL, path, true);
862 }
863 
864 
865 static int
virSecurityDACSetImageLabelInternal(virSecurityManager * mgr,virDomainDef * def,virStorageSource * src,virStorageSource * parent,bool isChainTop)866 virSecurityDACSetImageLabelInternal(virSecurityManager *mgr,
867                                     virDomainDef *def,
868                                     virStorageSource *src,
869                                     virStorageSource *parent,
870                                     bool isChainTop)
871 {
872     virSecurityLabelDef *secdef;
873     virSecurityDeviceLabelDef *disk_seclabel;
874     virSecurityDeviceLabelDef *parent_seclabel = NULL;
875     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
876     bool remember;
877     uid_t user;
878     gid_t group;
879 
880     if (!priv->dynamicOwnership)
881         return 0;
882 
883     secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
884     if (secdef && !secdef->relabel)
885         return 0;
886 
887     disk_seclabel = virStorageSourceGetSecurityLabelDef(src, SECURITY_DAC_NAME);
888     parent_seclabel = virStorageSourceGetSecurityLabelDef(parent,
889                                                           SECURITY_DAC_NAME);
890 
891     if (disk_seclabel && (!disk_seclabel->relabel || disk_seclabel->label)) {
892         if (!disk_seclabel->relabel)
893             return 0;
894 
895         if (virParseOwnershipIds(disk_seclabel->label, &user, &group) < 0)
896             return -1;
897     } else if (parent_seclabel &&
898                (!parent_seclabel->relabel || parent_seclabel->label)) {
899         if (!parent_seclabel->relabel)
900             return 0;
901 
902         if (virParseOwnershipIds(parent_seclabel->label, &user, &group) < 0)
903             return -1;
904     } else {
905         if (virSecurityDACGetImageIds(secdef, priv, &user, &group))
906             return -1;
907     }
908 
909     /* This is not very clean. But so far we don't have NVMe
910      * storage pool backend so that its chownCallback would be
911      * called. And this place looks least offensive. */
912     if (src->type == VIR_STORAGE_TYPE_NVME) {
913         const virStorageSourceNVMeDef *nvme = src->nvme;
914         g_autofree char *vfioGroupDev = NULL;
915 
916         if (!(vfioGroupDev = virPCIDeviceAddressGetIOMMUGroupDev(&nvme->pciAddr)))
917             return -1;
918 
919         return virSecurityDACSetOwnership(mgr, NULL, vfioGroupDev, user, group, false);
920     }
921 
922     /* We can't do restore on shared resources safely. Not even
923      * with refcounting implemented in XATTRs because if there
924      * was a domain running with the feature turned off the
925      * refcounter in XATTRs would not reflect the actual number
926      * of times the resource is in use and thus the last restore
927      * on the resource (which actually restores the original
928      * owner) might cut off access to the domain with the feature
929      * disabled.
930      * For disks, a shared resource is the whole backing chain
931      * but the top layer, or read only image, or disk explicitly
932      * marked as shared.
933      */
934     remember = isChainTop && !src->readonly && !src->shared;
935 
936     return virSecurityDACSetOwnership(mgr, src, NULL, user, group, remember);
937 }
938 
939 
940 static int
virSecurityDACSetImageLabelRelative(virSecurityManager * mgr,virDomainDef * def,virStorageSource * src,virStorageSource * parent,virSecurityDomainImageLabelFlags flags)941 virSecurityDACSetImageLabelRelative(virSecurityManager *mgr,
942                                     virDomainDef *def,
943                                     virStorageSource *src,
944                                     virStorageSource *parent,
945                                     virSecurityDomainImageLabelFlags flags)
946 {
947     virStorageSource *n;
948 
949     for (n = src; virStorageSourceIsBacking(n); n = n->backingStore) {
950         const bool isChainTop = flags & VIR_SECURITY_DOMAIN_IMAGE_PARENT_CHAIN_TOP;
951 
952         if (virSecurityDACSetImageLabelInternal(mgr, def, n, parent, isChainTop) < 0)
953             return -1;
954 
955         if (!(flags & VIR_SECURITY_DOMAIN_IMAGE_LABEL_BACKING_CHAIN))
956             break;
957 
958         flags &= ~VIR_SECURITY_DOMAIN_IMAGE_PARENT_CHAIN_TOP;
959     }
960 
961     return 0;
962 }
963 
964 static int
virSecurityDACSetImageLabel(virSecurityManager * mgr,virDomainDef * def,virStorageSource * src,virSecurityDomainImageLabelFlags flags)965 virSecurityDACSetImageLabel(virSecurityManager *mgr,
966                             virDomainDef *def,
967                             virStorageSource *src,
968                             virSecurityDomainImageLabelFlags flags)
969 {
970     return virSecurityDACSetImageLabelRelative(mgr, def, src, src, flags);
971 }
972 
973 static int
virSecurityDACRestoreImageLabelSingle(virSecurityManager * mgr,virDomainDef * def,virStorageSource * src,bool migrated)974 virSecurityDACRestoreImageLabelSingle(virSecurityManager *mgr,
975                                       virDomainDef *def,
976                                       virStorageSource *src,
977                                       bool migrated)
978 {
979     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
980     virSecurityLabelDef *secdef;
981     virSecurityDeviceLabelDef *disk_seclabel;
982 
983     if (!priv->dynamicOwnership)
984         return 0;
985 
986     /* Don't restore labels on readoly/shared disks, because other VMs may
987      * still be accessing these. Alternatively we could iterate over all
988      * running domains and try to figure out if it is in use, but this would
989      * not work for clustered filesystems, since we can't see running VMs using
990      * the file on other nodes. Safest bet is thus to skip the restore step. */
991     if (src->readonly || src->shared)
992         return 0;
993 
994     secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
995     if (secdef && !secdef->relabel)
996         return 0;
997 
998     disk_seclabel = virStorageSourceGetSecurityLabelDef(src,
999                                                         SECURITY_DAC_NAME);
1000     if (disk_seclabel && !disk_seclabel->relabel)
1001         return 0;
1002 
1003     /* If we have a shared FS and are doing migration, we must not change
1004      * ownership, because that kills access on the destination host which is
1005      * sub-optimal for the guest VM's I/O attempts :-) */
1006     if (migrated) {
1007         int rc = 1;
1008 
1009         if (virStorageSourceIsLocalStorage(src)) {
1010             if (!src->path)
1011                 return 0;
1012 
1013             if ((rc = virFileIsSharedFS(src->path)) < 0)
1014                 return -1;
1015         }
1016 
1017         if (rc == 1) {
1018             VIR_DEBUG("Skipping image label restore on %s because FS is shared",
1019                       src->path);
1020             return 0;
1021         }
1022     }
1023 
1024     /* This is not very clean. But so far we don't have NVMe
1025      * storage pool backend so that its chownCallback would be
1026      * called. And this place looks least offensive. */
1027     if (src->type == VIR_STORAGE_TYPE_NVME) {
1028         const virStorageSourceNVMeDef *nvme = src->nvme;
1029         g_autofree char *vfioGroupDev = NULL;
1030 
1031         if (!(vfioGroupDev = virPCIDeviceAddressGetIOMMUGroupDev(&nvme->pciAddr)))
1032             return -1;
1033 
1034         /* Ideally, we would check if there is not another PCI
1035          * device within domain def that is in the same IOMMU
1036          * group. But we're not doing that for hostdevs yet. */
1037 
1038         return virSecurityDACRestoreFileLabelInternal(mgr, NULL, vfioGroupDev, false);
1039     }
1040 
1041     return virSecurityDACRestoreFileLabelInternal(mgr, src, NULL, true);
1042 }
1043 
1044 
1045 static int
virSecurityDACRestoreImageLabelInt(virSecurityManager * mgr,virDomainDef * def,virStorageSource * src,bool migrated)1046 virSecurityDACRestoreImageLabelInt(virSecurityManager *mgr,
1047                                    virDomainDef *def,
1048                                    virStorageSource *src,
1049                                    bool migrated)
1050 {
1051     if (virSecurityDACRestoreImageLabelSingle(mgr, def, src, migrated) < 0)
1052         return -1;
1053 
1054     return 0;
1055 }
1056 
1057 
1058 static int
virSecurityDACRestoreImageLabel(virSecurityManager * mgr,virDomainDef * def,virStorageSource * src,virSecurityDomainImageLabelFlags flags G_GNUC_UNUSED)1059 virSecurityDACRestoreImageLabel(virSecurityManager *mgr,
1060                                 virDomainDef *def,
1061                                 virStorageSource *src,
1062                                 virSecurityDomainImageLabelFlags flags G_GNUC_UNUSED)
1063 {
1064     return virSecurityDACRestoreImageLabelInt(mgr, def, src, false);
1065 }
1066 
1067 
1068 struct virSecurityDACMoveImageMetadataData {
1069     virSecurityManager *mgr;
1070     const char *src;
1071     const char *dst;
1072 };
1073 
1074 
1075 static int
virSecurityDACMoveImageMetadataHelper(pid_t pid G_GNUC_UNUSED,void * opaque)1076 virSecurityDACMoveImageMetadataHelper(pid_t pid G_GNUC_UNUSED,
1077                                       void *opaque)
1078 {
1079     struct virSecurityDACMoveImageMetadataData *data = opaque;
1080     const char *paths[2] = { data->src, data->dst };
1081     virSecurityManagerMetadataLockState *state;
1082     int ret;
1083 
1084     if (!(state = virSecurityManagerMetadataLock(data->mgr, paths, G_N_ELEMENTS(paths))))
1085         return -1;
1086 
1087     ret = virSecurityMoveRememberedLabel(SECURITY_DAC_NAME, data->src, data->dst);
1088     virSecurityManagerMetadataUnlock(data->mgr, &state);
1089 
1090     if (ret == -2) {
1091         /* Libvirt built without XATTRS */
1092         ret = 0;
1093     }
1094 
1095     return ret;
1096 }
1097 
1098 
1099 static int
virSecurityDACMoveImageMetadata(virSecurityManager * mgr,pid_t pid,virStorageSource * src,virStorageSource * dst)1100 virSecurityDACMoveImageMetadata(virSecurityManager *mgr,
1101                                 pid_t pid,
1102                                 virStorageSource *src,
1103                                 virStorageSource *dst)
1104 {
1105     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
1106     struct virSecurityDACMoveImageMetadataData data = { .mgr = mgr, 0 };
1107     int rc;
1108 
1109     /* If dynamicOwnership is turned off, or owner remembering is
1110      * not enabled there's nothing for us to do. */
1111     if (!priv->dynamicOwnership)
1112         return 0;
1113 
1114     if (src && virStorageSourceIsLocalStorage(src))
1115         data.src = src->path;
1116 
1117     if (dst && virStorageSourceIsLocalStorage(dst))
1118         data.dst = dst->path;
1119 
1120     if (!data.src)
1121         return 0;
1122 
1123     if (pid == -1) {
1124         rc = virProcessRunInFork(virSecurityDACMoveImageMetadataHelper, &data);
1125     } else {
1126         rc = virProcessRunInMountNamespace(pid,
1127                                            virSecurityDACMoveImageMetadataHelper,
1128                                            &data);
1129     }
1130 
1131     return rc;
1132 }
1133 
1134 
1135 static int
virSecurityDACSetHostdevLabelHelper(const char * file,bool remember,void * opaque)1136 virSecurityDACSetHostdevLabelHelper(const char *file,
1137                                     bool remember,
1138                                     void *opaque)
1139 {
1140     virSecurityDACCallbackData *cbdata = opaque;
1141     virSecurityManager *mgr = cbdata->manager;
1142     virSecurityLabelDef *secdef = cbdata->secdef;
1143     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
1144     uid_t user;
1145     gid_t group;
1146 
1147     if (virSecurityDACGetIds(secdef, priv, &user, &group, NULL, NULL) < 0)
1148         return -1;
1149 
1150     return virSecurityDACSetOwnership(mgr, NULL, file, user, group, remember);
1151 }
1152 
1153 
1154 static int
virSecurityDACSetPCILabel(virPCIDevice * dev G_GNUC_UNUSED,const char * file,void * opaque)1155 virSecurityDACSetPCILabel(virPCIDevice *dev G_GNUC_UNUSED,
1156                           const char *file,
1157                           void *opaque)
1158 {
1159     return virSecurityDACSetHostdevLabelHelper(file, true, opaque);
1160 }
1161 
1162 
1163 static int
virSecurityDACSetUSBLabel(virUSBDevice * dev G_GNUC_UNUSED,const char * file,void * opaque)1164 virSecurityDACSetUSBLabel(virUSBDevice *dev G_GNUC_UNUSED,
1165                           const char *file,
1166                           void *opaque)
1167 {
1168     return virSecurityDACSetHostdevLabelHelper(file, true, opaque);
1169 }
1170 
1171 
1172 static int
virSecurityDACSetSCSILabel(virSCSIDevice * dev G_GNUC_UNUSED,const char * file,void * opaque)1173 virSecurityDACSetSCSILabel(virSCSIDevice *dev G_GNUC_UNUSED,
1174                            const char *file,
1175                            void *opaque)
1176 {
1177     return virSecurityDACSetHostdevLabelHelper(file, true, opaque);
1178 }
1179 
1180 
1181 static int
virSecurityDACSetHostLabel(virSCSIVHostDevice * dev G_GNUC_UNUSED,const char * file,void * opaque)1182 virSecurityDACSetHostLabel(virSCSIVHostDevice *dev G_GNUC_UNUSED,
1183                            const char *file,
1184                            void *opaque)
1185 {
1186     return virSecurityDACSetHostdevLabelHelper(file, true, opaque);
1187 }
1188 
1189 
1190 static int
virSecurityDACSetHostdevLabel(virSecurityManager * mgr,virDomainDef * def,virDomainHostdevDef * dev,const char * vroot)1191 virSecurityDACSetHostdevLabel(virSecurityManager *mgr,
1192                               virDomainDef *def,
1193                               virDomainHostdevDef *dev,
1194                               const char *vroot)
1195 {
1196     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
1197     virSecurityDACCallbackData cbdata;
1198     virDomainHostdevSubsysUSB *usbsrc = &dev->source.subsys.u.usb;
1199     virDomainHostdevSubsysPCI *pcisrc = &dev->source.subsys.u.pci;
1200     virDomainHostdevSubsysSCSI *scsisrc = &dev->source.subsys.u.scsi;
1201     virDomainHostdevSubsysSCSIVHost *hostsrc = &dev->source.subsys.u.scsi_host;
1202     virDomainHostdevSubsysMediatedDev *mdevsrc = &dev->source.subsys.u.mdev;
1203     int ret = -1;
1204 
1205     if (!priv->dynamicOwnership)
1206         return 0;
1207 
1208     if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
1209         return 0;
1210 
1211     /* Like virSecurityDACSetImageLabel() for a networked disk,
1212      * do nothing for an iSCSI hostdev
1213      */
1214     if (dev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
1215         scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI)
1216         return 0;
1217 
1218     cbdata.manager = mgr;
1219     cbdata.secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
1220 
1221     if (cbdata.secdef && !cbdata.secdef->relabel)
1222         return 0;
1223 
1224     switch ((virDomainHostdevSubsysType)dev->source.subsys.type) {
1225     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
1226         g_autoptr(virUSBDevice) usb = NULL;
1227 
1228         if (dev->missing)
1229             return 0;
1230 
1231         if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, vroot)))
1232             return -1;
1233 
1234         ret = virUSBDeviceFileIterate(usb,
1235                                       virSecurityDACSetUSBLabel,
1236                                       &cbdata);
1237         break;
1238     }
1239 
1240     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
1241         g_autoptr(virPCIDevice) pci = NULL;
1242 
1243         if (!virPCIDeviceExists(&pcisrc->addr))
1244             break;
1245 
1246         pci = virPCIDeviceNew(&pcisrc->addr);
1247 
1248         if (!pci)
1249             return -1;
1250 
1251         if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
1252             g_autofree char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci);
1253 
1254             if (!vfioGroupDev)
1255                 return -1;
1256 
1257             ret = virSecurityDACSetHostdevLabelHelper(vfioGroupDev,
1258                                                       false,
1259                                                       &cbdata);
1260         } else {
1261             ret = virPCIDeviceFileIterate(pci,
1262                                           virSecurityDACSetPCILabel,
1263                                           &cbdata);
1264         }
1265         break;
1266     }
1267 
1268     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
1269         virDomainHostdevSubsysSCSIHost *scsihostsrc = &scsisrc->u.host;
1270         g_autoptr(virSCSIDevice) scsi =
1271             virSCSIDeviceNew(NULL,
1272                              scsihostsrc->adapter, scsihostsrc->bus,
1273                              scsihostsrc->target, scsihostsrc->unit,
1274                              dev->readonly, dev->shareable);
1275 
1276         if (!scsi)
1277             return -1;
1278 
1279         ret = virSCSIDeviceFileIterate(scsi,
1280                                        virSecurityDACSetSCSILabel,
1281                                        &cbdata);
1282         break;
1283     }
1284 
1285     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST: {
1286         g_autoptr(virSCSIVHostDevice) host = virSCSIVHostDeviceNew(hostsrc->wwpn);
1287 
1288         if (!host)
1289             return -1;
1290 
1291         ret = virSCSIVHostDeviceFileIterate(host,
1292                                             virSecurityDACSetHostLabel,
1293                                             &cbdata);
1294         break;
1295     }
1296 
1297     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV: {
1298         g_autofree char *vfiodev = NULL;
1299 
1300         if (!(vfiodev = virMediatedDeviceGetIOMMUGroupDev(mdevsrc->uuidstr)))
1301             return -1;
1302 
1303         ret = virSecurityDACSetHostdevLabelHelper(vfiodev, true, &cbdata);
1304         break;
1305     }
1306 
1307     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
1308         ret = 0;
1309         break;
1310     }
1311 
1312     return ret;
1313 }
1314 
1315 
1316 static int
virSecurityDACRestorePCILabel(virPCIDevice * dev G_GNUC_UNUSED,const char * file,void * opaque)1317 virSecurityDACRestorePCILabel(virPCIDevice *dev G_GNUC_UNUSED,
1318                               const char *file,
1319                               void *opaque)
1320 {
1321     virSecurityManager *mgr = opaque;
1322     return virSecurityDACRestoreFileLabel(mgr, file);
1323 }
1324 
1325 
1326 static int
virSecurityDACRestoreUSBLabel(virUSBDevice * dev G_GNUC_UNUSED,const char * file,void * opaque)1327 virSecurityDACRestoreUSBLabel(virUSBDevice *dev G_GNUC_UNUSED,
1328                               const char *file,
1329                               void *opaque)
1330 {
1331     virSecurityManager *mgr = opaque;
1332     return virSecurityDACRestoreFileLabel(mgr, file);
1333 }
1334 
1335 
1336 static int
virSecurityDACRestoreSCSILabel(virSCSIDevice * dev G_GNUC_UNUSED,const char * file,void * opaque)1337 virSecurityDACRestoreSCSILabel(virSCSIDevice *dev G_GNUC_UNUSED,
1338                                const char *file,
1339                                void *opaque)
1340 {
1341     virSecurityManager *mgr = opaque;
1342     return virSecurityDACRestoreFileLabel(mgr, file);
1343 }
1344 
1345 
1346 static int
virSecurityDACRestoreHostLabel(virSCSIVHostDevice * dev G_GNUC_UNUSED,const char * file,void * opaque)1347 virSecurityDACRestoreHostLabel(virSCSIVHostDevice *dev G_GNUC_UNUSED,
1348                                const char *file,
1349                                void *opaque)
1350 {
1351     virSecurityManager *mgr = opaque;
1352     return virSecurityDACRestoreFileLabel(mgr, file);
1353 }
1354 
1355 
1356 static int
virSecurityDACRestoreHostdevLabel(virSecurityManager * mgr,virDomainDef * def,virDomainHostdevDef * dev,const char * vroot)1357 virSecurityDACRestoreHostdevLabel(virSecurityManager *mgr,
1358                                   virDomainDef *def,
1359                                   virDomainHostdevDef *dev,
1360                                   const char *vroot)
1361 
1362 {
1363     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
1364     virSecurityLabelDef *secdef;
1365     virDomainHostdevSubsysUSB *usbsrc = &dev->source.subsys.u.usb;
1366     virDomainHostdevSubsysPCI *pcisrc = &dev->source.subsys.u.pci;
1367     virDomainHostdevSubsysSCSI *scsisrc = &dev->source.subsys.u.scsi;
1368     virDomainHostdevSubsysSCSIVHost *hostsrc = &dev->source.subsys.u.scsi_host;
1369     virDomainHostdevSubsysMediatedDev *mdevsrc = &dev->source.subsys.u.mdev;
1370     int ret = -1;
1371 
1372     secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
1373 
1374     if (!priv->dynamicOwnership || (secdef && !secdef->relabel))
1375         return 0;
1376 
1377     if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
1378         return 0;
1379 
1380     /* Like virSecurityDACRestoreImageLabelInt() for a networked disk,
1381      * do nothing for an iSCSI hostdev
1382      */
1383     if (dev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
1384         scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI)
1385         return 0;
1386 
1387     switch ((virDomainHostdevSubsysType)dev->source.subsys.type) {
1388     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
1389         g_autoptr(virUSBDevice) usb = NULL;
1390 
1391         if (dev->missing)
1392             return 0;
1393 
1394         if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, vroot)))
1395             return -1;
1396 
1397         ret = virUSBDeviceFileIterate(usb, virSecurityDACRestoreUSBLabel, mgr);
1398         break;
1399     }
1400 
1401     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
1402         g_autoptr(virPCIDevice) pci = NULL;
1403 
1404         if (!virPCIDeviceExists(&pcisrc->addr))
1405             break;
1406 
1407         pci = virPCIDeviceNew(&pcisrc->addr);
1408 
1409         if (!pci)
1410             return -1;
1411 
1412         if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
1413             g_autofree char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci);
1414 
1415             if (!vfioGroupDev)
1416                 return -1;
1417 
1418             ret = virSecurityDACRestoreFileLabelInternal(mgr, NULL,
1419                                                          vfioGroupDev, false);
1420         } else {
1421             ret = virPCIDeviceFileIterate(pci, virSecurityDACRestorePCILabel, mgr);
1422         }
1423         break;
1424     }
1425 
1426     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
1427         virDomainHostdevSubsysSCSIHost *scsihostsrc = &scsisrc->u.host;
1428         g_autoptr(virSCSIDevice) scsi =
1429             virSCSIDeviceNew(NULL,
1430                              scsihostsrc->adapter, scsihostsrc->bus,
1431                              scsihostsrc->target, scsihostsrc->unit,
1432                              dev->readonly, dev->shareable);
1433 
1434         if (!scsi)
1435             return -1;
1436 
1437         ret = virSCSIDeviceFileIterate(scsi, virSecurityDACRestoreSCSILabel, mgr);
1438         break;
1439     }
1440 
1441     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST: {
1442         g_autoptr(virSCSIVHostDevice) host = virSCSIVHostDeviceNew(hostsrc->wwpn);
1443 
1444         if (!host)
1445             return -1;
1446 
1447         ret = virSCSIVHostDeviceFileIterate(host,
1448                                             virSecurityDACRestoreHostLabel,
1449                                             mgr);
1450         break;
1451     }
1452 
1453     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV: {
1454         g_autofree char *vfiodev = NULL;
1455 
1456         if (!(vfiodev = virMediatedDeviceGetIOMMUGroupDev(mdevsrc->uuidstr)))
1457             return -1;
1458 
1459         ret = virSecurityDACRestoreFileLabel(mgr, vfiodev);
1460         break;
1461     }
1462 
1463     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
1464         ret = 0;
1465         break;
1466     }
1467 
1468     return ret;
1469 }
1470 
1471 
1472 static int
virSecurityDACSetChardevLabelHelper(virSecurityManager * mgr,virDomainDef * def,virDomainChrSourceDef * dev_source,bool chardevStdioLogd,bool remember)1473 virSecurityDACSetChardevLabelHelper(virSecurityManager *mgr,
1474                                     virDomainDef *def,
1475                                     virDomainChrSourceDef *dev_source,
1476                                     bool chardevStdioLogd,
1477                                     bool remember)
1478 
1479 {
1480     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
1481     virSecurityLabelDef *seclabel;
1482     virSecurityDeviceLabelDef *chr_seclabel = NULL;
1483     g_autofree char *in = NULL;
1484     g_autofree char *out = NULL;
1485     uid_t user;
1486     gid_t group;
1487 
1488     seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
1489 
1490     chr_seclabel = virDomainChrSourceDefGetSecurityLabelDef(dev_source,
1491                                                             SECURITY_DAC_NAME);
1492 
1493     if (chr_seclabel && !chr_seclabel->relabel)
1494         return 0;
1495 
1496     if (!chr_seclabel &&
1497         dev_source->type == VIR_DOMAIN_CHR_TYPE_FILE &&
1498         chardevStdioLogd)
1499         return 0;
1500 
1501     if (chr_seclabel && chr_seclabel->label) {
1502         if (virParseOwnershipIds(chr_seclabel->label, &user, &group) < 0)
1503             return -1;
1504     } else {
1505         if (virSecurityDACGetIds(seclabel, priv, &user, &group, NULL, NULL) < 0)
1506             return -1;
1507     }
1508 
1509     switch ((virDomainChrType)dev_source->type) {
1510     case VIR_DOMAIN_CHR_TYPE_DEV:
1511     case VIR_DOMAIN_CHR_TYPE_FILE:
1512         if (virSecurityDACSetOwnership(mgr, NULL,
1513                                        dev_source->data.file.path,
1514                                        user, group, remember) < 0) {
1515             return -1;
1516         }
1517         break;
1518 
1519     case VIR_DOMAIN_CHR_TYPE_PIPE:
1520         in = g_strdup_printf("%s.in", dev_source->data.file.path);
1521         out = g_strdup_printf("%s.out", dev_source->data.file.path);
1522         if (virFileExists(in) && virFileExists(out)) {
1523             if (virSecurityDACSetOwnership(mgr, NULL, in, user, group, remember) < 0 ||
1524                 virSecurityDACSetOwnership(mgr, NULL, out, user, group, remember) < 0) {
1525                 return -1;
1526             }
1527         } else if (virSecurityDACSetOwnership(mgr, NULL,
1528                                               dev_source->data.file.path,
1529                                               user, group, remember) < 0) {
1530             return -1;
1531         }
1532         break;
1533 
1534     case VIR_DOMAIN_CHR_TYPE_UNIX:
1535         if (!dev_source->data.nix.listen ||
1536             (dev_source->data.nix.path &&
1537              virFileExists(dev_source->data.nix.path))) {
1538             /* Also label mode='bind' sockets if they exist,
1539              * e.g. because they were created by libvirt
1540              * and passed via FD */
1541             if (virSecurityDACSetOwnership(mgr, NULL,
1542                                            dev_source->data.nix.path,
1543                                            user, group, remember) < 0) {
1544                 return -1;
1545             }
1546         }
1547         break;
1548 
1549     case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
1550     case VIR_DOMAIN_CHR_TYPE_NULL:
1551     case VIR_DOMAIN_CHR_TYPE_VC:
1552     case VIR_DOMAIN_CHR_TYPE_PTY:
1553     case VIR_DOMAIN_CHR_TYPE_STDIO:
1554     case VIR_DOMAIN_CHR_TYPE_UDP:
1555     case VIR_DOMAIN_CHR_TYPE_TCP:
1556     case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
1557     case VIR_DOMAIN_CHR_TYPE_NMDM:
1558     case VIR_DOMAIN_CHR_TYPE_LAST:
1559         break;
1560     }
1561 
1562     return 0;
1563 }
1564 
1565 
1566 static int
virSecurityDACSetChardevLabel(virSecurityManager * mgr,virDomainDef * def,virDomainChrSourceDef * dev_source,bool chardevStdioLogd)1567 virSecurityDACSetChardevLabel(virSecurityManager *mgr,
1568                               virDomainDef *def,
1569                               virDomainChrSourceDef *dev_source,
1570                               bool chardevStdioLogd)
1571 {
1572     return virSecurityDACSetChardevLabelHelper(mgr, def, dev_source,
1573                                                chardevStdioLogd, true);
1574 }
1575 
1576 
1577 static int
virSecurityDACRestoreChardevLabelHelper(virSecurityManager * mgr,virDomainDef * def G_GNUC_UNUSED,virDomainChrSourceDef * dev_source,bool chardevStdioLogd,bool recall)1578 virSecurityDACRestoreChardevLabelHelper(virSecurityManager *mgr,
1579                                         virDomainDef *def G_GNUC_UNUSED,
1580                                         virDomainChrSourceDef *dev_source,
1581                                         bool chardevStdioLogd,
1582                                         bool recall)
1583 {
1584     virSecurityDeviceLabelDef *chr_seclabel = NULL;
1585     g_autofree char *in = NULL;
1586     g_autofree char *out = NULL;
1587 
1588     chr_seclabel = virDomainChrSourceDefGetSecurityLabelDef(dev_source,
1589                                                             SECURITY_DAC_NAME);
1590 
1591     if (chr_seclabel && !chr_seclabel->relabel)
1592         return 0;
1593 
1594     if (!chr_seclabel &&
1595         dev_source->type == VIR_DOMAIN_CHR_TYPE_FILE &&
1596         chardevStdioLogd)
1597         return 0;
1598 
1599     switch ((virDomainChrType)dev_source->type) {
1600     case VIR_DOMAIN_CHR_TYPE_DEV:
1601     case VIR_DOMAIN_CHR_TYPE_FILE:
1602         if (virSecurityDACRestoreFileLabelInternal(mgr, NULL,
1603                                                    dev_source->data.file.path,
1604                                                    recall) < 0) {
1605             return -1;
1606         }
1607         break;
1608 
1609     case VIR_DOMAIN_CHR_TYPE_PIPE:
1610         out = g_strdup_printf("%s.out", dev_source->data.file.path);
1611         in = g_strdup_printf("%s.in", dev_source->data.file.path);
1612         if (virFileExists(in) && virFileExists(out)) {
1613             if (virSecurityDACRestoreFileLabelInternal(mgr, NULL, out, recall) < 0 ||
1614                 virSecurityDACRestoreFileLabelInternal(mgr, NULL, in, recall) < 0) {
1615                 return -1;
1616             }
1617         } else if (virSecurityDACRestoreFileLabelInternal(mgr, NULL,
1618                                                           dev_source->data.file.path,
1619                                                           recall) < 0) {
1620             return -1;
1621         }
1622         break;
1623 
1624     case VIR_DOMAIN_CHR_TYPE_UNIX:
1625         if (!dev_source->data.nix.listen &&
1626             virSecurityDACRestoreFileLabelInternal(mgr, NULL,
1627                                                    dev_source->data.nix.path,
1628                                                    recall) < 0) {
1629             return -1;
1630         }
1631         break;
1632 
1633     case VIR_DOMAIN_CHR_TYPE_NULL:
1634     case VIR_DOMAIN_CHR_TYPE_VC:
1635     case VIR_DOMAIN_CHR_TYPE_PTY:
1636     case VIR_DOMAIN_CHR_TYPE_STDIO:
1637     case VIR_DOMAIN_CHR_TYPE_UDP:
1638     case VIR_DOMAIN_CHR_TYPE_TCP:
1639     case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
1640     case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
1641     case VIR_DOMAIN_CHR_TYPE_NMDM:
1642     case VIR_DOMAIN_CHR_TYPE_LAST:
1643         break;
1644     }
1645 
1646     return 0;
1647 }
1648 
1649 
1650 static int
virSecurityDACRestoreChardevLabel(virSecurityManager * mgr,virDomainDef * def,virDomainChrSourceDef * dev_source,bool chardevStdioLogd)1651 virSecurityDACRestoreChardevLabel(virSecurityManager *mgr,
1652                                   virDomainDef *def,
1653                                   virDomainChrSourceDef *dev_source,
1654                                   bool chardevStdioLogd)
1655 {
1656     return virSecurityDACRestoreChardevLabelHelper(mgr, def, dev_source,
1657                                                    chardevStdioLogd, true);
1658 }
1659 
1660 
1661 struct _virSecuritySELinuxChardevCallbackData {
1662     virSecurityManager *mgr;
1663     bool chardevStdioLogd;
1664 };
1665 
1666 
1667 static int
virSecurityDACRestoreChardevCallback(virDomainDef * def,virDomainChrDef * dev G_GNUC_UNUSED,void * opaque)1668 virSecurityDACRestoreChardevCallback(virDomainDef *def,
1669                                      virDomainChrDef *dev G_GNUC_UNUSED,
1670                                      void *opaque)
1671 {
1672     struct _virSecuritySELinuxChardevCallbackData *data = opaque;
1673 
1674     return virSecurityDACRestoreChardevLabel(data->mgr, def, dev->source,
1675                                              data->chardevStdioLogd);
1676 }
1677 
1678 
1679 static int
virSecurityDACSetTPMFileLabel(virSecurityManager * mgr,virDomainDef * def,virDomainTPMDef * tpm)1680 virSecurityDACSetTPMFileLabel(virSecurityManager *mgr,
1681                               virDomainDef *def,
1682                               virDomainTPMDef *tpm)
1683 {
1684     int ret = 0;
1685 
1686     switch (tpm->type) {
1687     case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
1688         ret = virSecurityDACSetChardevLabelHelper(mgr, def,
1689                                                   tpm->data.passthrough.source,
1690                                                   false, false);
1691         break;
1692     case VIR_DOMAIN_TPM_TYPE_EMULATOR:
1693         ret = virSecurityDACSetChardevLabelHelper(mgr, def,
1694                                                   tpm->data.emulator.source,
1695                                                   false, false);
1696         break;
1697     case VIR_DOMAIN_TPM_TYPE_LAST:
1698         break;
1699     }
1700 
1701     return ret;
1702 }
1703 
1704 
1705 static int
virSecurityDACRestoreTPMFileLabel(virSecurityManager * mgr,virDomainDef * def,virDomainTPMDef * tpm)1706 virSecurityDACRestoreTPMFileLabel(virSecurityManager *mgr,
1707                                   virDomainDef *def,
1708                                   virDomainTPMDef *tpm)
1709 {
1710     int ret = 0;
1711 
1712     switch (tpm->type) {
1713     case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
1714         ret = virSecurityDACRestoreChardevLabelHelper(mgr, def,
1715                                                       tpm->data.passthrough.source,
1716                                                       false, false);
1717         break;
1718     case VIR_DOMAIN_TPM_TYPE_EMULATOR:
1719         /* swtpm will have removed the Unix socket upon termination */
1720     case VIR_DOMAIN_TPM_TYPE_LAST:
1721         break;
1722     }
1723 
1724     return ret;
1725 }
1726 
1727 
1728 static int
virSecurityDACSetGraphicsLabel(virSecurityManager * mgr,virDomainDef * def,virDomainGraphicsDef * gfx)1729 virSecurityDACSetGraphicsLabel(virSecurityManager *mgr,
1730                                virDomainDef *def,
1731                                virDomainGraphicsDef *gfx)
1732 
1733 {
1734     const char *rendernode = virDomainGraphicsGetRenderNode(gfx);
1735     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
1736     virSecurityLabelDef *seclabel;
1737     uid_t user;
1738     gid_t group;
1739 
1740     /* There's nothing to relabel */
1741     if (!rendernode)
1742         return 0;
1743 
1744     /* Skip chowning the shared render file if namespaces are disabled */
1745     if (!priv->mountNamespace)
1746         return 0;
1747 
1748     seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
1749     if (seclabel && !seclabel->relabel)
1750         return 0;
1751 
1752     if (virSecurityDACGetIds(seclabel, priv, &user, &group, NULL, NULL) < 0)
1753         return -1;
1754 
1755     if (virSecurityDACSetOwnership(mgr, NULL, rendernode, user, group, true) < 0)
1756         return -1;
1757 
1758     return 0;
1759 }
1760 
1761 
1762 static int
virSecurityDACRestoreGraphicsLabel(virSecurityManager * mgr G_GNUC_UNUSED,virDomainDef * def G_GNUC_UNUSED,virDomainGraphicsDef * gfx G_GNUC_UNUSED)1763 virSecurityDACRestoreGraphicsLabel(virSecurityManager *mgr G_GNUC_UNUSED,
1764                                virDomainDef *def G_GNUC_UNUSED,
1765                                virDomainGraphicsDef *gfx G_GNUC_UNUSED)
1766 
1767 {
1768     /* The only graphics labelling we do is dependent on mountNamespaces,
1769        in which case 'restoring' the label doesn't actually accomplish
1770        anything, so there's nothing to do here */
1771     return 0;
1772 }
1773 
1774 
1775 static int
virSecurityDACSetInputLabel(virSecurityManager * mgr,virDomainDef * def,virDomainInputDef * input)1776 virSecurityDACSetInputLabel(virSecurityManager *mgr,
1777                             virDomainDef *def,
1778                             virDomainInputDef *input)
1779 
1780 {
1781     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
1782     virSecurityLabelDef *seclabel;
1783     int ret = -1;
1784     uid_t user;
1785     gid_t group;
1786 
1787     seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
1788     if (seclabel && !seclabel->relabel)
1789         return 0;
1790 
1791     switch ((virDomainInputType)input->type) {
1792     case VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH:
1793     case VIR_DOMAIN_INPUT_TYPE_EVDEV:
1794         if (virSecurityDACGetIds(seclabel, priv, &user, &group, NULL, NULL) < 0)
1795             return -1;
1796 
1797         ret = virSecurityDACSetOwnership(mgr, NULL,
1798                                          input->source.evdev,
1799                                          user, group, true);
1800         break;
1801 
1802     case VIR_DOMAIN_INPUT_TYPE_MOUSE:
1803     case VIR_DOMAIN_INPUT_TYPE_TABLET:
1804     case VIR_DOMAIN_INPUT_TYPE_KBD:
1805     case VIR_DOMAIN_INPUT_TYPE_LAST:
1806         ret = 0;
1807         break;
1808     }
1809 
1810     return ret;
1811 }
1812 
1813 static int
virSecurityDACRestoreInputLabel(virSecurityManager * mgr,virDomainDef * def G_GNUC_UNUSED,virDomainInputDef * input)1814 virSecurityDACRestoreInputLabel(virSecurityManager *mgr,
1815                                 virDomainDef *def G_GNUC_UNUSED,
1816                                 virDomainInputDef *input)
1817 {
1818     int ret = -1;
1819 
1820     switch ((virDomainInputType)input->type) {
1821     case VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH:
1822     case VIR_DOMAIN_INPUT_TYPE_EVDEV:
1823         ret = virSecurityDACRestoreFileLabel(mgr, input->source.evdev);
1824         break;
1825 
1826     case VIR_DOMAIN_INPUT_TYPE_MOUSE:
1827     case VIR_DOMAIN_INPUT_TYPE_TABLET:
1828     case VIR_DOMAIN_INPUT_TYPE_KBD:
1829     case VIR_DOMAIN_INPUT_TYPE_LAST:
1830         ret = 0;
1831         break;
1832     }
1833 
1834     return ret;
1835 }
1836 
1837 
1838 static int
virSecurityDACRestoreMemoryLabel(virSecurityManager * mgr,virDomainDef * def G_GNUC_UNUSED,virDomainMemoryDef * mem)1839 virSecurityDACRestoreMemoryLabel(virSecurityManager *mgr,
1840                                  virDomainDef *def G_GNUC_UNUSED,
1841                                  virDomainMemoryDef *mem)
1842 {
1843     int ret = -1;
1844 
1845     switch (mem->model) {
1846     case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
1847     case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
1848         ret = virSecurityDACRestoreFileLabel(mgr, mem->nvdimmPath);
1849         break;
1850 
1851     case VIR_DOMAIN_MEMORY_MODEL_DIMM:
1852     case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
1853     case VIR_DOMAIN_MEMORY_MODEL_LAST:
1854     case VIR_DOMAIN_MEMORY_MODEL_NONE:
1855         ret = 0;
1856         break;
1857     }
1858 
1859     return ret;
1860 }
1861 
1862 
1863 static int
virSecurityDACRestoreSEVLabel(virSecurityManager * mgr G_GNUC_UNUSED,virDomainDef * def G_GNUC_UNUSED)1864 virSecurityDACRestoreSEVLabel(virSecurityManager *mgr G_GNUC_UNUSED,
1865                               virDomainDef *def G_GNUC_UNUSED)
1866 {
1867     /* we only label /dev/sev when running with namespaces, so we don't need to
1868      * restore anything */
1869     return 0;
1870 }
1871 
1872 
1873 static int
virSecurityDACRestoreSysinfoLabel(virSecurityManager * mgr,virSysinfoDef * def)1874 virSecurityDACRestoreSysinfoLabel(virSecurityManager *mgr,
1875                                   virSysinfoDef *def)
1876 {
1877     size_t i;
1878 
1879     for (i = 0; i < def->nfw_cfgs; i++) {
1880         virSysinfoFWCfgDef *f = &def->fw_cfgs[i];
1881 
1882         if (f->file &&
1883             virSecurityDACRestoreFileLabel(mgr, f->file) < 0)
1884             return -1;
1885     }
1886 
1887     return 0;
1888 }
1889 
1890 
1891 static int
virSecurityDACRestoreAllLabel(virSecurityManager * mgr,virDomainDef * def,bool migrated,bool chardevStdioLogd)1892 virSecurityDACRestoreAllLabel(virSecurityManager *mgr,
1893                               virDomainDef *def,
1894                               bool migrated,
1895                               bool chardevStdioLogd)
1896 {
1897     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
1898     virSecurityLabelDef *secdef;
1899     size_t i;
1900     int rc = 0;
1901 
1902     struct _virSecuritySELinuxChardevCallbackData chardevData = {
1903         .mgr = mgr,
1904         .chardevStdioLogd = chardevStdioLogd,
1905     };
1906 
1907     secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
1908 
1909     if (!priv->dynamicOwnership || (secdef && !secdef->relabel))
1910         return 0;
1911 
1912     VIR_DEBUG("Restoring security label on %s migrated=%d",
1913               def->name, migrated);
1914 
1915     for (i = 0; i < def->ndisks; i++) {
1916         if (virSecurityDACRestoreImageLabelInt(mgr,
1917                                                def,
1918                                                def->disks[i]->src,
1919                                                migrated) < 0)
1920             rc = -1;
1921     }
1922 
1923     for (i = 0; i < def->ngraphics; i++) {
1924         if (virSecurityDACRestoreGraphicsLabel(mgr, def, def->graphics[i]) < 0)
1925             return -1;
1926     }
1927 
1928     for (i = 0; i < def->ninputs; i++) {
1929         if (virSecurityDACRestoreInputLabel(mgr, def, def->inputs[i]) < 0)
1930             rc = -1;
1931     }
1932 
1933     for (i = 0; i < def->nhostdevs; i++) {
1934         if (virSecurityDACRestoreHostdevLabel(mgr,
1935                                               def,
1936                                               def->hostdevs[i],
1937                                               NULL) < 0)
1938             rc = -1;
1939     }
1940 
1941     for (i = 0; i < def->nmems; i++) {
1942         if (virSecurityDACRestoreMemoryLabel(mgr,
1943                                              def,
1944                                              def->mems[i]) < 0)
1945             rc = -1;
1946     }
1947 
1948     if (virDomainChrDefForeach(def,
1949                                false,
1950                                virSecurityDACRestoreChardevCallback,
1951                                &chardevData) < 0)
1952         rc = -1;
1953 
1954     for (i = 0; i < def->ntpms; i++) {
1955         if (virSecurityDACRestoreTPMFileLabel(mgr,
1956                                               def,
1957                                               def->tpms[i]) < 0)
1958             rc = -1;
1959     }
1960 
1961     if (def->sec &&
1962         def->sec->sectype == VIR_DOMAIN_LAUNCH_SECURITY_SEV) {
1963         if (virSecurityDACRestoreSEVLabel(mgr, def) < 0)
1964             rc = -1;
1965     }
1966 
1967     for (i = 0; i < def->nsysinfo; i++) {
1968         if (virSecurityDACRestoreSysinfoLabel(mgr,
1969                                               def->sysinfo[i]) < 0)
1970             rc = -1;
1971     }
1972 
1973     if (def->os.loader && def->os.loader->nvram &&
1974         virSecurityDACRestoreFileLabel(mgr, def->os.loader->nvram) < 0)
1975         rc = -1;
1976 
1977     if (def->os.kernel &&
1978         virSecurityDACRestoreFileLabel(mgr, def->os.kernel) < 0)
1979         rc = -1;
1980 
1981     if (def->os.initrd &&
1982         virSecurityDACRestoreFileLabel(mgr, def->os.initrd) < 0)
1983         rc = -1;
1984 
1985     if (def->os.dtb &&
1986         virSecurityDACRestoreFileLabel(mgr, def->os.dtb) < 0)
1987         rc = -1;
1988 
1989     if (def->os.slic_table &&
1990         virSecurityDACRestoreFileLabel(mgr, def->os.slic_table) < 0)
1991         rc = -1;
1992 
1993     return rc;
1994 }
1995 
1996 
1997 static int
virSecurityDACSetChardevCallback(virDomainDef * def,virDomainChrDef * dev G_GNUC_UNUSED,void * opaque)1998 virSecurityDACSetChardevCallback(virDomainDef *def,
1999                                  virDomainChrDef *dev G_GNUC_UNUSED,
2000                                  void *opaque)
2001 {
2002     struct _virSecuritySELinuxChardevCallbackData *data = opaque;
2003 
2004     return virSecurityDACSetChardevLabel(data->mgr, def, dev->source,
2005                                          data->chardevStdioLogd);
2006 }
2007 
2008 
2009 static int
virSecurityDACSetMemoryLabel(virSecurityManager * mgr,virDomainDef * def,virDomainMemoryDef * mem)2010 virSecurityDACSetMemoryLabel(virSecurityManager *mgr,
2011                              virDomainDef *def,
2012                              virDomainMemoryDef *mem)
2013 
2014 {
2015     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
2016     virSecurityLabelDef *seclabel;
2017     int ret = -1;
2018     uid_t user;
2019     gid_t group;
2020 
2021     switch (mem->model) {
2022     case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
2023     case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
2024         seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
2025         if (seclabel && !seclabel->relabel)
2026             return 0;
2027 
2028         if (virSecurityDACGetIds(seclabel, priv, &user, &group, NULL, NULL) < 0)
2029             return -1;
2030 
2031         ret = virSecurityDACSetOwnership(mgr, NULL,
2032                                          mem->nvdimmPath,
2033                                          user, group, true);
2034         break;
2035 
2036     case VIR_DOMAIN_MEMORY_MODEL_DIMM:
2037     case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
2038     case VIR_DOMAIN_MEMORY_MODEL_LAST:
2039     case VIR_DOMAIN_MEMORY_MODEL_NONE:
2040         ret = 0;
2041         break;
2042     }
2043 
2044     return ret;
2045 }
2046 
2047 
2048 static int
virSecurityDACSetSEVLabel(virSecurityManager * mgr,virDomainDef * def)2049 virSecurityDACSetSEVLabel(virSecurityManager *mgr,
2050                           virDomainDef *def)
2051 {
2052     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
2053     virSecurityLabelDef *seclabel;
2054     uid_t user;
2055     gid_t group;
2056 
2057     /* Skip chowning /dev/sev if namespaces are disabled as we'd significantly
2058      * increase the chance of a DOS attack on SEV
2059      */
2060     if (!priv->mountNamespace)
2061         return 0;
2062 
2063     seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
2064     if (seclabel && !seclabel->relabel)
2065         return 0;
2066 
2067     if (virSecurityDACGetIds(seclabel, priv, &user, &group, NULL, NULL) < 0)
2068         return -1;
2069 
2070     if (virSecurityDACSetOwnership(mgr, NULL, DEV_SEV,
2071                                    user, group, true) < 0)
2072         return -1;
2073 
2074     return 0;
2075 }
2076 
2077 
2078 static int
virSecurityDACSetSysinfoLabel(virSecurityManager * mgr,uid_t user,gid_t group,virSysinfoDef * def)2079 virSecurityDACSetSysinfoLabel(virSecurityManager *mgr,
2080                               uid_t user,
2081                               gid_t group,
2082                               virSysinfoDef *def)
2083 {
2084     size_t i;
2085 
2086     for (i = 0; i < def->nfw_cfgs; i++) {
2087         virSysinfoFWCfgDef *f = &def->fw_cfgs[i];
2088 
2089         if (f->file &&
2090             virSecurityDACSetOwnership(mgr, NULL, f->file,
2091                                        user, group, true) < 0)
2092             return -1;
2093     }
2094 
2095     return 0;
2096 }
2097 
2098 
2099 static int
virSecurityDACSetAllLabel(virSecurityManager * mgr,virDomainDef * def,const char * incomingPath G_GNUC_UNUSED,bool chardevStdioLogd,bool migrated G_GNUC_UNUSED)2100 virSecurityDACSetAllLabel(virSecurityManager *mgr,
2101                           virDomainDef *def,
2102                           const char *incomingPath G_GNUC_UNUSED,
2103                           bool chardevStdioLogd,
2104                           bool migrated G_GNUC_UNUSED)
2105 {
2106     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
2107     virSecurityLabelDef *secdef;
2108     size_t i;
2109     uid_t user;
2110     gid_t group;
2111 
2112     struct _virSecuritySELinuxChardevCallbackData chardevData = {
2113         .mgr = mgr,
2114         .chardevStdioLogd = chardevStdioLogd,
2115     };
2116 
2117     secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
2118 
2119     if (!priv->dynamicOwnership || (secdef && !secdef->relabel))
2120         return 0;
2121 
2122     for (i = 0; i < def->ndisks; i++) {
2123         /* XXX fixme - we need to recursively label the entire tree :-( */
2124         if (virDomainDiskGetType(def->disks[i]) == VIR_STORAGE_TYPE_DIR)
2125             continue;
2126         if (virSecurityDACSetImageLabel(mgr, def, def->disks[i]->src,
2127                                         VIR_SECURITY_DOMAIN_IMAGE_LABEL_BACKING_CHAIN |
2128                                         VIR_SECURITY_DOMAIN_IMAGE_PARENT_CHAIN_TOP) < 0)
2129             return -1;
2130     }
2131 
2132     for (i = 0; i < def->ngraphics; i++) {
2133         if (virSecurityDACSetGraphicsLabel(mgr, def, def->graphics[i]) < 0)
2134             return -1;
2135     }
2136 
2137     for (i = 0; i < def->ninputs; i++) {
2138         if (virSecurityDACSetInputLabel(mgr, def, def->inputs[i]) < 0)
2139             return -1;
2140     }
2141 
2142     for (i = 0; i < def->nhostdevs; i++) {
2143         if (virSecurityDACSetHostdevLabel(mgr,
2144                                           def,
2145                                           def->hostdevs[i],
2146                                           NULL) < 0)
2147             return -1;
2148     }
2149 
2150     for (i = 0; i < def->nmems; i++) {
2151         if (virSecurityDACSetMemoryLabel(mgr,
2152                                          def,
2153                                          def->mems[i]) < 0)
2154             return -1;
2155     }
2156 
2157     if (virDomainChrDefForeach(def,
2158                                true,
2159                                virSecurityDACSetChardevCallback,
2160                                &chardevData) < 0)
2161         return -1;
2162 
2163     for (i = 0; i < def->ntpms; i++) {
2164         if (virSecurityDACSetTPMFileLabel(mgr,
2165                                           def,
2166                                           def->tpms[i]) < 0)
2167             return -1;
2168     }
2169 
2170     if (def->sec &&
2171         def->sec->sectype == VIR_DOMAIN_LAUNCH_SECURITY_SEV) {
2172         if (virSecurityDACSetSEVLabel(mgr, def) < 0)
2173             return -1;
2174     }
2175 
2176     if (virSecurityDACGetImageIds(secdef, priv, &user, &group))
2177         return -1;
2178 
2179     for (i = 0; i < def->nsysinfo; i++) {
2180         if (virSecurityDACSetSysinfoLabel(mgr, user, group, def->sysinfo[i]) < 0)
2181             return -1;
2182     }
2183 
2184     if (def->os.loader && def->os.loader->nvram &&
2185         virSecurityDACSetOwnership(mgr, NULL,
2186                                    def->os.loader->nvram,
2187                                    user, group, true) < 0)
2188         return -1;
2189 
2190     if (def->os.kernel &&
2191         virSecurityDACSetOwnership(mgr, NULL,
2192                                    def->os.kernel,
2193                                    user, group, true) < 0)
2194         return -1;
2195 
2196     if (def->os.initrd &&
2197         virSecurityDACSetOwnership(mgr, NULL,
2198                                    def->os.initrd,
2199                                    user, group, true) < 0)
2200         return -1;
2201 
2202     if (def->os.dtb &&
2203         virSecurityDACSetOwnership(mgr, NULL,
2204                                    def->os.dtb,
2205                                    user, group, true) < 0)
2206         return -1;
2207 
2208     if (def->os.slic_table &&
2209         virSecurityDACSetOwnership(mgr, NULL,
2210                                    def->os.slic_table,
2211                                    user, group, true) < 0)
2212         return -1;
2213 
2214     return 0;
2215 }
2216 
2217 
2218 static int
virSecurityDACSetProcessLabel(virSecurityManager * mgr,virDomainDef * def)2219 virSecurityDACSetProcessLabel(virSecurityManager *mgr,
2220                               virDomainDef *def)
2221 {
2222     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
2223     virSecurityLabelDef *secdef;
2224     uid_t user;
2225     gid_t group;
2226     gid_t *groups;
2227     int ngroups;
2228 
2229     secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
2230 
2231     if (virSecurityDACGetIds(secdef, priv, &user, &group, &groups, &ngroups) < 0)
2232         return -1;
2233 
2234     VIR_DEBUG("Dropping privileges to %u:%u, %d supplemental groups",
2235               (unsigned int)user, (unsigned int)group, ngroups);
2236 
2237     if (virSetUIDGID(user, group, groups, ngroups) < 0)
2238         return -1;
2239 
2240     return 0;
2241 }
2242 
2243 
2244 static int
virSecurityDACSetChildProcessLabel(virSecurityManager * mgr,virDomainDef * def,virCommand * cmd)2245 virSecurityDACSetChildProcessLabel(virSecurityManager *mgr,
2246                                    virDomainDef *def,
2247                                    virCommand *cmd)
2248 {
2249     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
2250     virSecurityLabelDef *secdef;
2251     uid_t user;
2252     gid_t group;
2253 
2254     secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
2255 
2256     if (virSecurityDACGetIds(secdef, priv, &user, &group, NULL, NULL) < 0)
2257         return -1;
2258 
2259     VIR_DEBUG("Setting child to drop privileges to %u:%u",
2260               (unsigned int)user, (unsigned int)group);
2261 
2262     virCommandSetUID(cmd, user);
2263     virCommandSetGID(cmd, group);
2264     return 0;
2265 }
2266 
2267 
2268 static int
virSecurityDACVerify(virSecurityManager * mgr G_GNUC_UNUSED,virDomainDef * def G_GNUC_UNUSED)2269 virSecurityDACVerify(virSecurityManager *mgr G_GNUC_UNUSED,
2270                      virDomainDef *def G_GNUC_UNUSED)
2271 {
2272     return 0;
2273 }
2274 
2275 static int
virSecurityDACGenLabel(virSecurityManager * mgr,virDomainDef * def)2276 virSecurityDACGenLabel(virSecurityManager *mgr,
2277                        virDomainDef *def)
2278 {
2279     int rc = -1;
2280     virSecurityLabelDef *seclabel;
2281     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
2282 
2283     seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
2284     if (seclabel == NULL)
2285         return rc;
2286 
2287     if (seclabel->imagelabel) {
2288         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2289                        _("security image label already "
2290                          "defined for VM"));
2291         return rc;
2292     }
2293 
2294     if (seclabel->model
2295         && STRNEQ(seclabel->model, SECURITY_DAC_NAME)) {
2296         virReportError(VIR_ERR_INTERNAL_ERROR,
2297                        _("security label model %s is not supported "
2298                          "with selinux"),
2299                        seclabel->model);
2300             return rc;
2301     }
2302 
2303     switch ((virDomainSeclabelType)seclabel->type) {
2304     case VIR_DOMAIN_SECLABEL_STATIC:
2305         if (seclabel->label == NULL) {
2306             virReportError(VIR_ERR_INTERNAL_ERROR,
2307                            _("missing label for static security "
2308                              "driver in domain %s"), def->name);
2309             return rc;
2310         }
2311         break;
2312     case VIR_DOMAIN_SECLABEL_DYNAMIC:
2313         seclabel->label = g_strdup_printf("+%u:+%u", (unsigned int)priv->user,
2314                                           (unsigned int)priv->group);
2315         if (seclabel->label == NULL) {
2316             virReportError(VIR_ERR_INTERNAL_ERROR,
2317                            _("cannot generate dac user and group id "
2318                              "for domain %s"), def->name);
2319             return rc;
2320         }
2321         break;
2322     case VIR_DOMAIN_SECLABEL_NONE:
2323         /* no op */
2324         return 0;
2325     case VIR_DOMAIN_SECLABEL_DEFAULT:
2326     case VIR_DOMAIN_SECLABEL_LAST:
2327         virReportError(VIR_ERR_INTERNAL_ERROR,
2328                        _("unexpected security label type '%s'"),
2329                        virDomainSeclabelTypeToString(seclabel->type));
2330         return rc;
2331     }
2332 
2333     if (seclabel->relabel && !seclabel->imagelabel)
2334         seclabel->imagelabel = g_strdup(seclabel->label);
2335 
2336     return 0;
2337 }
2338 
2339 static int
virSecurityDACReleaseLabel(virSecurityManager * mgr G_GNUC_UNUSED,virDomainDef * def G_GNUC_UNUSED)2340 virSecurityDACReleaseLabel(virSecurityManager *mgr G_GNUC_UNUSED,
2341                            virDomainDef *def G_GNUC_UNUSED)
2342 {
2343     return 0;
2344 }
2345 
2346 static int
virSecurityDACReserveLabel(virSecurityManager * mgr G_GNUC_UNUSED,virDomainDef * def G_GNUC_UNUSED,pid_t pid G_GNUC_UNUSED)2347 virSecurityDACReserveLabel(virSecurityManager *mgr G_GNUC_UNUSED,
2348                            virDomainDef *def G_GNUC_UNUSED,
2349                            pid_t pid G_GNUC_UNUSED)
2350 {
2351     return 0;
2352 }
2353 
2354 #ifdef __linux__
2355 static int
virSecurityDACGetProcessLabelInternal(pid_t pid,virSecurityLabelPtr seclabel)2356 virSecurityDACGetProcessLabelInternal(pid_t pid,
2357                                       virSecurityLabelPtr seclabel)
2358 {
2359     struct stat sb;
2360     g_autofree char *path = NULL;
2361 
2362     VIR_DEBUG("Getting DAC user and group on process '%d'", pid);
2363 
2364     path = g_strdup_printf("/proc/%d", (int)pid);
2365 
2366     if (g_lstat(path, &sb) < 0) {
2367         virReportSystemError(errno,
2368                              _("unable to get uid and gid for PID %d via procfs"),
2369                              pid);
2370         return -1;
2371     }
2372 
2373     g_snprintf(seclabel->label, VIR_SECURITY_LABEL_BUFLEN,
2374                "+%u:+%u", (unsigned int)sb.st_uid, (unsigned int)sb.st_gid);
2375     return 0;
2376 }
2377 #elif defined(__FreeBSD__) && !defined(__DragonFly__)
2378 static int
virSecurityDACGetProcessLabelInternal(pid_t pid,virSecurityLabelPtr seclabel)2379 virSecurityDACGetProcessLabelInternal(pid_t pid,
2380                                       virSecurityLabelPtr seclabel)
2381 {
2382     struct kinfo_proc p;
2383     int mib[4];
2384     size_t len = 4;
2385 
2386     sysctlnametomib("kern.proc.pid", mib, &len);
2387 
2388     len = sizeof(struct kinfo_proc);
2389     mib[3] = pid;
2390 
2391     if (sysctl(mib, 4, &p, &len, NULL, 0) < 0) {
2392         virReportSystemError(errno,
2393                              _("unable to get PID %d uid and gid via sysctl"),
2394                              pid);
2395         return -1;
2396     }
2397 
2398     g_snprintf(seclabel->label, VIR_SECURITY_LABEL_BUFLEN,
2399                "+%u:+%u", (unsigned int)p.ki_uid, (unsigned int)p.ki_groups[0]);
2400 
2401     return 0;
2402 }
2403 #else
2404 static int
virSecurityDACGetProcessLabelInternal(pid_t pid G_GNUC_UNUSED,virSecurityLabelPtr seclabel G_GNUC_UNUSED)2405 virSecurityDACGetProcessLabelInternal(pid_t pid G_GNUC_UNUSED,
2406                                       virSecurityLabelPtr seclabel G_GNUC_UNUSED)
2407 {
2408     virReportSystemError(ENOSYS, "%s",
2409                          _("Cannot get process uid and gid on this platform"));
2410     return -1;
2411 }
2412 #endif
2413 
2414 static int
virSecurityDACGetProcessLabel(virSecurityManager * mgr G_GNUC_UNUSED,virDomainDef * def,pid_t pid,virSecurityLabelPtr seclabel)2415 virSecurityDACGetProcessLabel(virSecurityManager *mgr G_GNUC_UNUSED,
2416                               virDomainDef *def,
2417                               pid_t pid,
2418                               virSecurityLabelPtr seclabel)
2419 {
2420     virSecurityLabelDef *secdef =
2421         virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
2422 
2423     if (secdef == NULL) {
2424         VIR_DEBUG("missing label for DAC security "
2425                   "driver in domain %s", def->name);
2426 
2427         if (virSecurityDACGetProcessLabelInternal(pid, seclabel) < 0)
2428             return -1;
2429         return 0;
2430     }
2431 
2432     if (secdef->label)
2433         ignore_value(virStrcpy(seclabel->label, secdef->label,
2434                                VIR_SECURITY_LABEL_BUFLEN));
2435 
2436     return 0;
2437 }
2438 
2439 static int
virSecurityDACSetDaemonSocketLabel(virSecurityManager * mgr G_GNUC_UNUSED,virDomainDef * vm G_GNUC_UNUSED)2440 virSecurityDACSetDaemonSocketLabel(virSecurityManager *mgr G_GNUC_UNUSED,
2441                                    virDomainDef *vm G_GNUC_UNUSED)
2442 {
2443     return 0;
2444 }
2445 
2446 
2447 static int
virSecurityDACSetSocketLabel(virSecurityManager * mgr G_GNUC_UNUSED,virDomainDef * def G_GNUC_UNUSED)2448 virSecurityDACSetSocketLabel(virSecurityManager *mgr G_GNUC_UNUSED,
2449                              virDomainDef *def G_GNUC_UNUSED)
2450 {
2451     return 0;
2452 }
2453 
2454 
2455 static int
virSecurityDACClearSocketLabel(virSecurityManager * mgr G_GNUC_UNUSED,virDomainDef * def G_GNUC_UNUSED)2456 virSecurityDACClearSocketLabel(virSecurityManager *mgr G_GNUC_UNUSED,
2457                                virDomainDef *def G_GNUC_UNUSED)
2458 {
2459     return 0;
2460 }
2461 
2462 static int
virSecurityDACSetImageFDLabel(virSecurityManager * mgr G_GNUC_UNUSED,virDomainDef * def G_GNUC_UNUSED,int fd G_GNUC_UNUSED)2463 virSecurityDACSetImageFDLabel(virSecurityManager *mgr G_GNUC_UNUSED,
2464                               virDomainDef *def G_GNUC_UNUSED,
2465                               int fd G_GNUC_UNUSED)
2466 {
2467     return 0;
2468 }
2469 
2470 static int
virSecurityDACSetTapFDLabel(virSecurityManager * mgr G_GNUC_UNUSED,virDomainDef * def G_GNUC_UNUSED,int fd G_GNUC_UNUSED)2471 virSecurityDACSetTapFDLabel(virSecurityManager *mgr G_GNUC_UNUSED,
2472                             virDomainDef *def G_GNUC_UNUSED,
2473                             int fd G_GNUC_UNUSED)
2474 {
2475     return 0;
2476 }
2477 
2478 static char *
virSecurityDACGetMountOptions(virSecurityManager * mgr G_GNUC_UNUSED,virDomainDef * vm G_GNUC_UNUSED)2479 virSecurityDACGetMountOptions(virSecurityManager *mgr G_GNUC_UNUSED,
2480                               virDomainDef *vm G_GNUC_UNUSED)
2481 {
2482     return NULL;
2483 }
2484 
2485 static const char *
virSecurityDACGetBaseLabel(virSecurityManager * mgr,int virt G_GNUC_UNUSED)2486 virSecurityDACGetBaseLabel(virSecurityManager *mgr,
2487                            int virt G_GNUC_UNUSED)
2488 {
2489     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
2490     return priv->baselabel;
2491 }
2492 
2493 static int
virSecurityDACDomainSetPathLabel(virSecurityManager * mgr,virDomainDef * def,const char * path,bool allowSubtree G_GNUC_UNUSED)2494 virSecurityDACDomainSetPathLabel(virSecurityManager *mgr,
2495                                  virDomainDef *def,
2496                                  const char *path,
2497                                  bool allowSubtree G_GNUC_UNUSED)
2498 {
2499     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
2500     virSecurityLabelDef *seclabel;
2501     uid_t user;
2502     gid_t group;
2503 
2504     seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
2505 
2506     if (virSecurityDACGetIds(seclabel, priv, &user, &group, NULL, NULL) < 0)
2507         return -1;
2508 
2509     return virSecurityDACSetOwnership(mgr, NULL, path, user, group, true);
2510 }
2511 
2512 static int
virSecurityDACDomainRestorePathLabel(virSecurityManager * mgr,virDomainDef * def G_GNUC_UNUSED,const char * path)2513 virSecurityDACDomainRestorePathLabel(virSecurityManager *mgr,
2514                                      virDomainDef *def G_GNUC_UNUSED,
2515                                      const char *path)
2516 {
2517     return virSecurityDACRestoreFileLabel(mgr, path);
2518 }
2519 
2520 
2521 virSecurityDriver virSecurityDriverDAC = {
2522     .privateDataLen                     = sizeof(virSecurityDACData),
2523     .name                               = SECURITY_DAC_NAME,
2524     .probe                              = virSecurityDACProbe,
2525     .open                               = virSecurityDACOpen,
2526     .close                              = virSecurityDACClose,
2527 
2528     .getModel                           = virSecurityDACGetModel,
2529     .getDOI                             = virSecurityDACGetDOI,
2530 
2531     .preFork                            = virSecurityDACPreFork,
2532 
2533     .transactionStart                   = virSecurityDACTransactionStart,
2534     .transactionCommit                  = virSecurityDACTransactionCommit,
2535     .transactionAbort                   = virSecurityDACTransactionAbort,
2536 
2537     .domainSecurityVerify               = virSecurityDACVerify,
2538 
2539     .domainSetSecurityImageLabel        = virSecurityDACSetImageLabel,
2540     .domainRestoreSecurityImageLabel    = virSecurityDACRestoreImageLabel,
2541     .domainMoveImageMetadata            = virSecurityDACMoveImageMetadata,
2542 
2543     .domainSetSecurityMemoryLabel       = virSecurityDACSetMemoryLabel,
2544     .domainRestoreSecurityMemoryLabel   = virSecurityDACRestoreMemoryLabel,
2545 
2546     .domainSetSecurityInputLabel        = virSecurityDACSetInputLabel,
2547     .domainRestoreSecurityInputLabel    = virSecurityDACRestoreInputLabel,
2548 
2549     .domainSetSecurityDaemonSocketLabel = virSecurityDACSetDaemonSocketLabel,
2550     .domainSetSecuritySocketLabel       = virSecurityDACSetSocketLabel,
2551     .domainClearSecuritySocketLabel     = virSecurityDACClearSocketLabel,
2552 
2553     .domainGenSecurityLabel             = virSecurityDACGenLabel,
2554     .domainReserveSecurityLabel         = virSecurityDACReserveLabel,
2555     .domainReleaseSecurityLabel         = virSecurityDACReleaseLabel,
2556 
2557     .domainGetSecurityProcessLabel      = virSecurityDACGetProcessLabel,
2558     .domainSetSecurityProcessLabel      = virSecurityDACSetProcessLabel,
2559     .domainSetSecurityChildProcessLabel = virSecurityDACSetChildProcessLabel,
2560 
2561     .domainSetSecurityAllLabel          = virSecurityDACSetAllLabel,
2562     .domainRestoreSecurityAllLabel      = virSecurityDACRestoreAllLabel,
2563 
2564     .domainSetSecurityHostdevLabel      = virSecurityDACSetHostdevLabel,
2565     .domainRestoreSecurityHostdevLabel  = virSecurityDACRestoreHostdevLabel,
2566 
2567     .domainSetSecurityImageFDLabel      = virSecurityDACSetImageFDLabel,
2568     .domainSetSecurityTapFDLabel        = virSecurityDACSetTapFDLabel,
2569 
2570     .domainGetSecurityMountOptions      = virSecurityDACGetMountOptions,
2571 
2572     .getBaseLabel                       = virSecurityDACGetBaseLabel,
2573 
2574     .domainSetPathLabel                 = virSecurityDACDomainSetPathLabel,
2575     .domainRestorePathLabel             = virSecurityDACDomainRestorePathLabel,
2576 
2577     .domainSetSecurityChardevLabel      = virSecurityDACSetChardevLabel,
2578     .domainRestoreSecurityChardevLabel  = virSecurityDACRestoreChardevLabel,
2579 };
2580