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