File 2e8ebfe3-label-vhostuser-port.patch of Package libvirt
xxxxxxxxxx
1
commit 2e8ebfe3fa17bb785d6bc26a17391dc4f34ad8b3
2
Author: Jim Fehlig <jfehlig@suse.com>
3
Date: Tue Jul 27 18:13:36 2021 -0600
4
5
qemu: Set label on vhostuser net device when hotplugging
6
7
Attaching a newly created vhostuser port to a VM fails due to an
8
apparmor denial
9
10
internal error: unable to execute QEMU command 'chardev-add': Failed
11
to bind socket to /run/openvswitch/vhu838c4d29-c9: Permission denied
12
13
In the case of a net device type VIR_DOMAIN_NET_TYPE_VHOSTUSER, the
14
underlying chardev is not labeled in qemuDomainAttachNetDevice prior
15
to calling qemuMonitorAttachCharDev.
16
17
A simple fix would be to call qemuSecuritySetChardevLabel using the
18
embedded virDomainChrSourceDef in the virDomainNetDef vhostuser data,
19
but this incurs the risk of incorrectly restoring the label. E.g.
20
consider the DAC driver behavior with a vhostuser net device, which
21
uses a socket for the chardev backend. The DAC driver uses XATTRS to
22
store original labelling information, but XATTRS are not compatible
23
with sockets. Without the original labelling information, the socket
24
labels will be restored with root ownership, preventing other
25
less-privileged processes from connecting to the socket.
26
27
This patch avoids overloading chardev labelling with vhostuser net
28
devices by introducing virSecurityManager{Set,Restore}NetdevLabel,
29
which is currently only implemented for the apparmor driver. The
30
new APIs are then used to set and restore labels for the vhostuser
31
net devices.
32
33
Signed-off-by: Jim Fehlig <jfehlig@suse.com>
34
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
35
36
Index: libvirt-7.1.0/src/libvirt_private.syms
37
===================================================================
38
--- libvirt-7.1.0.orig/src/libvirt_private.syms
39
+++ libvirt-7.1.0/src/libvirt_private.syms
40
41
virSecurityManagerRestoreImageLabel;
42
virSecurityManagerRestoreInputLabel;
43
virSecurityManagerRestoreMemoryLabel;
44
+virSecurityManagerRestoreNetdevLabel;
45
virSecurityManagerRestoreSavedStateLabel;
46
virSecurityManagerRestoreTPMLabels;
47
virSecurityManagerSetAllLabel;
48
49
virSecurityManagerSetImageLabel;
50
virSecurityManagerSetInputLabel;
51
virSecurityManagerSetMemoryLabel;
52
+virSecurityManagerSetNetdevLabel;
53
virSecurityManagerSetProcessLabel;
54
virSecurityManagerSetSavedStateLabel;
55
virSecurityManagerSetSocketLabel;
56
Index: libvirt-7.1.0/src/qemu/qemu_hotplug.c
57
===================================================================
58
--- libvirt-7.1.0.orig/src/qemu/qemu_hotplug.c
59
+++ libvirt-7.1.0/src/qemu/qemu_hotplug.c
60
61
g_autofree char *netdev_name = NULL;
62
g_autoptr(virConnect) conn = NULL;
63
virErrorPtr save_err = NULL;
64
+ bool teardownlabel = false;
65
66
/* preallocate new slot for device */
67
if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets + 1) < 0)
68
69
&net->ifname) < 0)
70
goto cleanup;
71
72
+ if (qemuSecuritySetNetdevLabel(driver, vm, net) < 0)
73
+ goto cleanup;
74
+ teardownlabel = true;
75
break;
76
77
case VIR_DOMAIN_NET_TYPE_USER:
78
79
qemuDomainNetDeviceVportRemove(net);
80
}
81
82
+ if (teardownlabel &&
83
+ qemuSecurityRestoreNetdevLabel(driver, vm, net) < 0)
84
+ VIR_WARN("Unable to restore network device labelling on hotplug fail");
85
+
86
virDomainNetRemoveHostdev(vm->def, net);
87
88
if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
89
90
cfg->stateDir));
91
}
92
93
+ if (actualType == VIR_DOMAIN_NET_TYPE_VHOSTUSER) {
94
+ if (qemuSecurityRestoreNetdevLabel(driver, vm, net) < 0)
95
+ VIR_WARN("Unable to restore security label on vhostuser char device");
96
+ }
97
+
98
qemuDomainNetDeviceVportRemove(net);
99
100
if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
101
Index: libvirt-7.1.0/src/qemu/qemu_security.c
102
===================================================================
103
--- libvirt-7.1.0.orig/src/qemu/qemu_security.c
104
+++ libvirt-7.1.0/src/qemu/qemu_security.c
105
106
return ret;
107
}
108
109
+int
110
+qemuSecuritySetNetdevLabel(virQEMUDriverPtr driver,
111
+ virDomainObjPtr vm,
112
+ virDomainNetDefPtr net)
113
+{
114
+ int ret = -1;
115
+ qemuDomainObjPrivatePtr priv = vm->privateData;
116
+ pid_t pid = -1;
117
+
118
+ if (qemuDomainNamespaceEnabled(vm, QEMU_DOMAIN_NS_MOUNT))
119
+ pid = vm->pid;
120
+
121
+ if (virSecurityManagerTransactionStart(driver->securityManager) < 0)
122
+ goto cleanup;
123
+
124
+ if (virSecurityManagerSetNetdevLabel(driver->securityManager,
125
+ vm->def, net) < 0)
126
+ goto cleanup;
127
+
128
+ if (virSecurityManagerTransactionCommit(driver->securityManager,
129
+ pid, priv->rememberOwner) < 0)
130
+ goto cleanup;
131
+
132
+ ret = 0;
133
+ cleanup:
134
+ virSecurityManagerTransactionAbort(driver->securityManager);
135
+ return ret;
136
+}
137
+
138
+
139
+int
140
+qemuSecurityRestoreNetdevLabel(virQEMUDriverPtr driver,
141
+ virDomainObjPtr vm,
142
+ virDomainNetDefPtr net)
143
+{
144
+ int ret = -1;
145
+ qemuDomainObjPrivatePtr priv = vm->privateData;
146
+ pid_t pid = -1;
147
+
148
+ if (qemuDomainNamespaceEnabled(vm, QEMU_DOMAIN_NS_MOUNT))
149
+ pid = vm->pid;
150
+
151
+ if (virSecurityManagerTransactionStart(driver->securityManager) < 0)
152
+ goto cleanup;
153
+
154
+ if (virSecurityManagerRestoreNetdevLabel(driver->securityManager,
155
+ vm->def, net) < 0)
156
+ goto cleanup;
157
+
158
+ if (virSecurityManagerTransactionCommit(driver->securityManager,
159
+ pid, priv->rememberOwner) < 0)
160
+ goto cleanup;
161
+
162
+ ret = 0;
163
+ cleanup:
164
+ virSecurityManagerTransactionAbort(driver->securityManager);
165
+ return ret;
166
+}
167
+
168
169
/*
170
* qemuSecurityStartVhostUserGPU:
171
Index: libvirt-7.1.0/src/qemu/qemu_security.h
172
===================================================================
173
--- libvirt-7.1.0.orig/src/qemu/qemu_security.h
174
+++ libvirt-7.1.0/src/qemu/qemu_security.h
175
176
virDomainObjPtr vm,
177
virDomainChrDefPtr chr);
178
179
+int qemuSecuritySetNetdevLabel(virQEMUDriverPtr driver,
180
+ virDomainObjPtr vm,
181
+ virDomainNetDefPtr net);
182
+
183
+int qemuSecurityRestoreNetdevLabel(virQEMUDriverPtr driver,
184
+ virDomainObjPtr vm,
185
+ virDomainNetDefPtr net);
186
+
187
int qemuSecurityStartVhostUserGPU(virQEMUDriverPtr driver,
188
virDomainObjPtr vm,
189
virCommandPtr cmd,
190
Index: libvirt-7.1.0/src/security/security_apparmor.c
191
===================================================================
192
--- libvirt-7.1.0.orig/src/security/security_apparmor.c
193
+++ libvirt-7.1.0/src/security/security_apparmor.c
194
195
}
196
197
static int
198
+AppArmorSetNetdevLabel(virSecurityManagerPtr mgr,
199
+ virDomainDefPtr def,
200
+ virDomainNetDefPtr net)
201
+{
202
+ int ret = -1;
203
+ virSecurityLabelDefPtr secdef;
204
+ virDomainChrSourceDefPtr dev_source;
205
+ virDomainNetType actualType;
206
+
207
+ secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME);
208
+ if (!secdef)
209
+ return 0;
210
+
211
+ actualType = virDomainNetGetActualType(net);
212
+ if (actualType != VIR_DOMAIN_NET_TYPE_VHOSTUSER)
213
+ return 0;
214
+
215
+ dev_source = net->data.vhostuser;
216
+ switch ((virDomainChrType)dev_source->type) {
217
+ case VIR_DOMAIN_CHR_TYPE_UNIX:
218
+ ret = reload_profile(mgr, def, dev_source->data.file.path, true);
219
+ break;
220
+
221
+ case VIR_DOMAIN_CHR_TYPE_DEV:
222
+ case VIR_DOMAIN_CHR_TYPE_FILE:
223
+ case VIR_DOMAIN_CHR_TYPE_PTY:
224
+ case VIR_DOMAIN_CHR_TYPE_PIPE:
225
+ case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
226
+ case VIR_DOMAIN_CHR_TYPE_NULL:
227
+ case VIR_DOMAIN_CHR_TYPE_VC:
228
+ case VIR_DOMAIN_CHR_TYPE_STDIO:
229
+ case VIR_DOMAIN_CHR_TYPE_UDP:
230
+ case VIR_DOMAIN_CHR_TYPE_TCP:
231
+ case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
232
+ case VIR_DOMAIN_CHR_TYPE_NMDM:
233
+ case VIR_DOMAIN_CHR_TYPE_LAST:
234
+ ret = 0;
235
+ break;
236
+ }
237
+
238
+ return ret;
239
+}
240
+
241
+static int
242
+AppArmorRestoreNetdevLabel(virSecurityManagerPtr mgr,
243
+ virDomainDefPtr def,
244
+ virDomainNetDefPtr net G_GNUC_UNUSED)
245
+{
246
+ virSecurityLabelDefPtr secdef;
247
+
248
+ secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME);
249
+ if (!secdef)
250
+ return 0;
251
+
252
+ return reload_profile(mgr, def, NULL, false);
253
+}
254
+
255
+static int
256
AppArmorSetPathLabel(virSecurityManagerPtr mgr,
257
virDomainDefPtr def,
258
const char *path,
259
260
.domainSetSecurityChardevLabel = AppArmorSetChardevLabel,
261
.domainRestoreSecurityChardevLabel = AppArmorRestoreChardevLabel,
262
263
+ .domainSetSecurityNetdevLabel = AppArmorSetNetdevLabel,
264
+ .domainRestoreSecurityNetdevLabel = AppArmorRestoreNetdevLabel,
265
+
266
.domainSetSecurityImageFDLabel = AppArmorSetFDLabel,
267
.domainSetSecurityTapFDLabel = AppArmorSetFDLabel,
268
269
Index: libvirt-7.1.0/src/security/security_driver.h
270
===================================================================
271
--- libvirt-7.1.0.orig/src/security/security_driver.h
272
+++ libvirt-7.1.0/src/security/security_driver.h
273
274
virDomainDefPtr def);
275
typedef int (*virSecurityDomainRestoreTPMLabels) (virSecurityManagerPtr mgr,
276
virDomainDefPtr def);
277
+typedef int (*virSecurityDomainSetNetdevLabel) (virSecurityManagerPtr mgr,
278
+ virDomainDefPtr def,
279
+ virDomainNetDefPtr net);
280
+typedef int (*virSecurityDomainRestoreNetdevLabel) (virSecurityManagerPtr mgr,
281
+ virDomainDefPtr def,
282
+ virDomainNetDefPtr net);
283
284
285
struct _virSecurityDriver {
286
287
288
virSecurityDomainSetTPMLabels domainSetSecurityTPMLabels;
289
virSecurityDomainRestoreTPMLabels domainRestoreSecurityTPMLabels;
290
+
291
+ virSecurityDomainSetNetdevLabel domainSetSecurityNetdevLabel;
292
+ virSecurityDomainRestoreNetdevLabel domainRestoreSecurityNetdevLabel;
293
};
294
295
virSecurityDriverPtr virSecurityDriverLookup(const char *name,
296
Index: libvirt-7.1.0/src/security/security_manager.c
297
===================================================================
298
--- libvirt-7.1.0.orig/src/security/security_manager.c
299
+++ libvirt-7.1.0/src/security/security_manager.c
300
301
}
302
303
304
+int
305
+virSecurityManagerSetNetdevLabel(virSecurityManagerPtr mgr,
306
+ virDomainDefPtr vm,
307
+ virDomainNetDefPtr net)
308
+{
309
+ int ret;
310
+
311
+ if (mgr->drv->domainSetSecurityNetdevLabel) {
312
+ virObjectLock(mgr);
313
+ ret = mgr->drv->domainSetSecurityNetdevLabel(mgr, vm, net);
314
+ virObjectUnlock(mgr);
315
+
316
+ return ret;
317
+ }
318
+
319
+ return 0;
320
+}
321
+
322
+
323
+int
324
+virSecurityManagerRestoreNetdevLabel(virSecurityManagerPtr mgr,
325
+ virDomainDefPtr vm,
326
+ virDomainNetDefPtr net)
327
+{
328
+ int ret;
329
+
330
+ if (mgr->drv->domainRestoreSecurityNetdevLabel) {
331
+ virObjectLock(mgr);
332
+ ret = mgr->drv->domainRestoreSecurityNetdevLabel(mgr, vm, net);
333
+ virObjectUnlock(mgr);
334
+
335
+ return ret;
336
+ }
337
+
338
+ return 0;
339
+}
340
+
341
+
342
static int
343
cmpstringp(const void *p1, const void *p2)
344
{
345
Index: libvirt-7.1.0/src/security/security_manager.h
346
===================================================================
347
--- libvirt-7.1.0.orig/src/security/security_manager.h
348
+++ libvirt-7.1.0/src/security/security_manager.h
349
350
int virSecurityManagerRestoreTPMLabels(virSecurityManagerPtr mgr,
351
virDomainDefPtr vm);
352
353
+int virSecurityManagerSetNetdevLabel(virSecurityManagerPtr mgr,
354
+ virDomainDefPtr vm,
355
+ virDomainNetDefPtr net);
356
+
357
+int virSecurityManagerRestoreNetdevLabel(virSecurityManagerPtr mgr,
358
+ virDomainDefPtr vm,
359
+ virDomainNetDefPtr net);
360
+
361
typedef struct _virSecurityManagerMetadataLockState virSecurityManagerMetadataLockState;
362
typedef virSecurityManagerMetadataLockState *virSecurityManagerMetadataLockStatePtr;
363
struct _virSecurityManagerMetadataLockState {
364
Index: libvirt-7.1.0/src/security/security_stack.c
365
===================================================================
366
--- libvirt-7.1.0.orig/src/security/security_stack.c
367
+++ libvirt-7.1.0/src/security/security_stack.c
368
369
}
370
371
372
+static int
373
+virSecurityStackDomainSetNetdevLabel(virSecurityManagerPtr mgr,
374
+ virDomainDefPtr def,
375
+ virDomainNetDefPtr net)
376
+{
377
+ virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
378
+ virSecurityStackItemPtr item = priv->itemsHead;
379
+
380
+ for (; item; item = item->next) {
381
+ if (virSecurityManagerSetNetdevLabel(item->securityManager, def, net) < 0)
382
+ goto rollback;
383
+ }
384
+
385
+ return 0;
386
+
387
+ rollback:
388
+ for (item = item->prev; item; item = item->prev) {
389
+ if (virSecurityManagerRestoreNetdevLabel(item->securityManager,
390
+ def, net) < 0) {
391
+ VIR_WARN("Unable to restore netdev label after failed set label "
392
+ "call virDriver=%s driver=%s domain=%s",
393
+ virSecurityManagerGetVirtDriver(mgr),
394
+ virSecurityManagerGetDriver(item->securityManager),
395
+ def->name);
396
+ }
397
+ }
398
+ return -1;
399
+}
400
+
401
+
402
+static int
403
+virSecurityStackDomainRestoreNetdevLabel(virSecurityManagerPtr mgr,
404
+ virDomainDefPtr def,
405
+ virDomainNetDefPtr net)
406
+{
407
+ virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
408
+ virSecurityStackItemPtr item = priv->itemsHead;
409
+ int rc = 0;
410
+
411
+ for (; item; item = item->next) {
412
+ if (virSecurityManagerRestoreNetdevLabel(item->securityManager,
413
+ def, net) < 0)
414
+ rc = -1;
415
+ }
416
+
417
+ return rc;
418
+}
419
+
420
+
421
virSecurityDriver virSecurityDriverStack = {
422
.privateDataLen = sizeof(virSecurityStackData),
423
.name = "stack",
424
425
426
.domainSetSecurityTPMLabels = virSecurityStackSetTPMLabels,
427
.domainRestoreSecurityTPMLabels = virSecurityStackRestoreTPMLabels,
428
+
429
+ .domainSetSecurityNetdevLabel = virSecurityStackDomainSetNetdevLabel,
430
+ .domainRestoreSecurityNetdevLabel = virSecurityStackDomainRestoreNetdevLabel,
431
};
432