In some cases callers might want to filter what devices are
stored in this module (esp. when used in combination with udev
who cares about nothing but "/dev/" prefixed paths).
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/libvirt_private.syms | 1 +
src/util/virudev.c | 25 ++++++++++++++++++++++
src/util/virudev.h | 13 ++++++++++++
tests/virudevtest.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 92 insertions(+), 1 deletion(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index c6d17c4..2a1f96e 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2588,6 +2588,7 @@ virUdevMgrNew;
virUdevMgrNewFromFile;
virUdevMgrNewFromStr;
virUdevMgrRemoveAllLabels;
+virUdevMgrSetFilter;
# util/viruri.h
diff --git a/src/util/virudev.c b/src/util/virudev.c
index 9940f5f..c17682c 100644
--- a/src/util/virudev.c
+++ b/src/util/virudev.c
@@ -36,6 +36,9 @@
struct _virUdevMgr {
virObjectLockable parent;
virHashTablePtr labels;
+
+ virUdevMgrFilter filter;
+ void *opaque;
};
struct _udevSeclabel {
@@ -274,6 +277,17 @@ virUdevMgrAddLabel(virUdevMgrPtr mgr,
virObjectLock(mgr);
+ if (mgr->filter) {
+ int rc = mgr->filter(device, seclabel, mgr->opaque);
+ if (rc < 0)
+ goto cleanup;
+ if (rc == 0) {
+ /* Claim success. */
+ ret = 0;
+ goto cleanup;
+ }
+ }
+
if ((list = virHashLookup(mgr->labels, device))) {
virSecurityDeviceLabelDefPtr entry = udevSeclabelFindByModel(list,
seclabel->model);
@@ -561,3 +575,14 @@ virUdevMgrNewFromFile(const char *filename)
VIR_FREE(state);
return NULL;
}
+
+void
+virUdevMgrSetFilter(virUdevMgrPtr mgr,
+ virUdevMgrFilter filter,
+ void *opaque)
+{
+ virObjectLock(mgr);
+ mgr->filter = filter;
+ mgr->opaque = opaque;
+ virObjectUnlock(mgr);
+}
diff --git a/src/util/virudev.h b/src/util/virudev.h
index 4e286bb..2f035e3 100644
--- a/src/util/virudev.h
+++ b/src/util/virudev.h
@@ -28,6 +28,15 @@
typedef struct _virUdevMgr virUdevMgr;
typedef virUdevMgr *virUdevMgrPtr;
+/* Filter some devices out in virUdevMgrAddLabel.
+ * Return 0 to NOT record label for device,
+ * 1 to record the label for device,
+ * -1 on error.
+ */
+typedef int (*virUdevMgrFilter)(const char *device,
+ const virSecurityDeviceLabelDef *seclabel,
+ void *opaque);
+
virUdevMgrPtr virUdevMgrNew(void);
virUdevMgrPtr virUdevMgrNewFromStr(const char *str);
virUdevMgrPtr virUdevMgrNewFromFile(const char *filename);
@@ -47,4 +56,8 @@ char *virUdevMgrDumpStr(virUdevMgrPtr mgr);
int virUdevMgrDumpFile(virUdevMgrPtr mgr,
const char *filename);
+void virUdevMgrSetFilter(virUdevMgrPtr mgr,
+ virUdevMgrFilter filter,
+ void *opaque);
+
#endif
diff --git a/tests/virudevtest.c b/tests/virudevtest.c
index 36a9077..cd5d136 100644
--- a/tests/virudevtest.c
+++ b/tests/virudevtest.c
@@ -29,6 +29,7 @@
struct testUdevData {
const char *file;
const char *const *labels;
+ virUdevMgrFilter filter;
};
@@ -49,6 +50,8 @@ testDump(const void *opaque)
if (!(mgr = virUdevMgrNew()))
goto cleanup;
+ virUdevMgrSetFilter(mgr, data->filter, NULL);
+
tmp = data->labels;
while (*tmp) {
const char *device;
@@ -194,6 +197,25 @@ testLookup(const void *opaque)
static int
+filterAll(const char *device ATTRIBUTE_UNUSED,
+ const virSecurityDeviceLabelDef *seclabel ATTRIBUTE_UNUSED,
+ void *opaque ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+
+static int
+filterAllowSda(const char *device,
+ const virSecurityDeviceLabelDef *seclabel ATTRIBUTE_UNUSED,
+ void *opaque ATTRIBUTE_UNUSED)
+{
+ return STRPREFIX(device, "/dev/sda") ? 1 : 0;
+}
+
+
+
+static int
mymain(void)
{
int ret = 0;
@@ -202,7 +224,7 @@ mymain(void)
do { \
const char *labels[] = {__VA_ARGS__, NULL}; \
struct testUdevData data = { \
- .file = filename, .labels = labels, \
+ .file = filename, .labels = labels, .filter = NULL, \
}; \
if (virTestRun("Dump " filename, testDump, &data) < 0) \
ret = -1; \
@@ -227,6 +249,17 @@ mymain(void)
ret = -1; \
} while (0)
+#define DO_TEST_FILTER(filename, fltr, ...) \
+ do { \
+ const char *labels[] = {__VA_ARGS__, NULL}; \
+ struct testUdevData data = { \
+ .file = filename, .labels = labels, .filter = fltr, \
+ }; \
+ if (virTestRun("Filter " filename, testDump, &data) < 0) \
+ ret = -1; \
+ } while (0)
+
+
DO_TEST_DUMP("empty", NULL);
DO_TEST_DUMP("simple-selinux",
"/dev/sda", "selinux",
"someSELinuxLabel");
@@ -254,6 +287,25 @@ mymain(void)
"/dev/sdb", "dac", "otherDACLabel",
"/dev/sdb", "selinux",
"otherSELinuxLabel");
+ DO_TEST_FILTER("empty", filterAll,
+ "/dev/sda", "dac", "someDACLabel",
+ "/dev/sda", "selinux",
"someSELinuxLabel",
+ "/dev/sdb", "dac", "otherDACLabel",
+ "/dev/sdb", "selinux",
"otherSELinuxLabel");
+ DO_TEST_FILTER("simple-selinux", filterAllowSda,
+ "/dev/sda", "selinux",
"someSELinuxLabel",
+ "/dev/sdb", "dac", "otherDACLabel",
+ "/dev/sdb", "selinux",
"otherSELinuxLabel");
+ DO_TEST_FILTER("simple-dac", filterAllowSda,
+ "/dev/sda", "dac", "someDACLabel",
+ "/dev/sdb", "dac", "otherDACLabel",
+ "/dev/sdb", "selinux",
"otherSELinuxLabel");
+ DO_TEST_FILTER("complex", NULL,
+ "/dev/sda", "dac", "someDACLabel",
+ "/dev/sda", "selinux",
"someSELinuxLabel",
+ "/dev/sdb", "dac", "otherDACLabel",
+ "/dev/sdb", "selinux",
"otherSELinuxLabel");
+
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
--
2.8.4