diff --git a/MAINTAINERS b/MAINTAINERS
index 7b27435fd20..a0cd161843e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11251,6 +11251,7 @@ L:	linux-kernel@vger.kernel.org
 S:	Maintained
 F:	include/linux/usermode_driver_mgmt.h
 F:	kernel/usermode_driver_mgmt.c
+F:	tools/testing/selftests/umd_mgmt/*
 
 KERNEL VIRTUAL MACHINE (KVM)
 M:	Paolo Bonzini <pbonzini@redhat.com>
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 13a6837a0c6..84202d5b4fb 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -84,6 +84,7 @@ TARGETS += timers
 endif
 TARGETS += tmpfs
 TARGETS += tpm2
+TARGETS += umd_mgmt
 TARGETS += user
 TARGETS += vDSO
 TARGETS += mm
diff --git a/tools/testing/selftests/umd_mgmt/.gitignore b/tools/testing/selftests/umd_mgmt/.gitignore
new file mode 100644
index 00000000000..215c17d13e9
--- /dev/null
+++ b/tools/testing/selftests/umd_mgmt/.gitignore
@@ -0,0 +1 @@
+/sample_umd/sample_umh
diff --git a/tools/testing/selftests/umd_mgmt/Makefile b/tools/testing/selftests/umd_mgmt/Makefile
new file mode 100644
index 00000000000..f1d47eec04e
--- /dev/null
+++ b/tools/testing/selftests/umd_mgmt/Makefile
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0
+TEST_GEN_PROGS_EXTENDED = sample_umd.ko
+
+$(OUTPUT)/%.ko: $(wildcard sample_umd/Makefile sample_umd/*.[ch])
+	$(call msg,MOD,,$@)
+	$(Q)$(MAKE) -C sample_umd install
+
+OVERRIDE_TARGETS := 1
+override define CLEAN
+	$(call msg,CLEAN)
+	$(Q)$(MAKE) -C sample_umd clean
+endef
+
+include ../lib.mk
diff --git a/tools/testing/selftests/umd_mgmt/config b/tools/testing/selftests/umd_mgmt/config
new file mode 100644
index 00000000000..71a078a3ac0
--- /dev/null
+++ b/tools/testing/selftests/umd_mgmt/config
@@ -0,0 +1 @@
+CONFIG_BPFILTER=y
diff --git a/tools/testing/selftests/umd_mgmt/sample_umd/Makefile b/tools/testing/selftests/umd_mgmt/sample_umd/Makefile
new file mode 100644
index 00000000000..6d950e05f3d
--- /dev/null
+++ b/tools/testing/selftests/umd_mgmt/sample_umd/Makefile
@@ -0,0 +1,22 @@
+KDIR ?= ../../../../..
+
+userprogs := sample_umh
+sample_umh-objs := sample_handler.o
+userccflags += -I $(srctree)
+
+$(obj)/sample_binary_blob.o: $(obj)/sample_umh
+
+MODULES = sample_loader_kmod.ko sample_mgr.ko
+
+obj-m += sample_loader_kmod.o sample_mgr.o
+
+sample_loader_kmod-objs = sample_loader.o sample_binary_blob.o
+
+all:
+	+$(Q)$(MAKE) -C $(KDIR) M=$$PWD modules
+
+clean:
+	+$(Q)$(MAKE) -C $(KDIR) M=$$PWD clean
+
+install: all
+	+$(Q)$(MAKE) -C $(KDIR) M=$$PWD modules_install
diff --git a/tools/testing/selftests/umd_mgmt/sample_umd/msgfmt.h b/tools/testing/selftests/umd_mgmt/sample_umd/msgfmt.h
new file mode 100644
index 00000000000..34a62d72cde
--- /dev/null
+++ b/tools/testing/selftests/umd_mgmt/sample_umd/msgfmt.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _SAMPLE_UMH_MSGFMT_H
+#define _SAMPLE_UMH_MSGFMT_H
+
+struct sample_request {
+	uint32_t offset;
+};
+
+struct sample_reply {
+	uint8_t data[128 * 1024];
+};
+
+#endif
diff --git a/tools/testing/selftests/umd_mgmt/sample_umd/sample_binary_blob.S b/tools/testing/selftests/umd_mgmt/sample_umd/sample_binary_blob.S
new file mode 100644
index 00000000000..3687dd13973
--- /dev/null
+++ b/tools/testing/selftests/umd_mgmt/sample_umd/sample_binary_blob.S
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+	.section .init.rodata, "a"
+	.global sample_umh_start
+sample_umh_start:
+	.incbin "tools/testing/selftests/umd_mgmt/sample_umd/sample_umh"
+	.global sample_umh_end
+sample_umh_end:
diff --git a/tools/testing/selftests/umd_mgmt/sample_umd/sample_handler.c b/tools/testing/selftests/umd_mgmt/sample_umd/sample_handler.c
new file mode 100644
index 00000000000..94ea6d99bbc
--- /dev/null
+++ b/tools/testing/selftests/umd_mgmt/sample_umd/sample_handler.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ *
+ * Implement the UMD Handler.
+ */
+#include <unistd.h>
+#include <malloc.h>
+#include <stdint.h>
+
+#include "msgfmt.h"
+
+FILE *debug_f;
+
+static void loop(void)
+{
+	struct sample_request *req = NULL;
+	struct sample_reply *reply = NULL;
+
+	req = calloc(1, sizeof(*req));
+	if (!req)
+		return;
+
+	reply = calloc(1, sizeof(*reply));
+	if (!reply)
+		goto out;
+
+	while (1) {
+		int n, len, offset;
+
+		offset = 0;
+		len = sizeof(*req);
+
+		while (len) {
+			n = read(0, ((void *)req) + offset, len);
+			if (n <= 0) {
+				fprintf(debug_f, "invalid request %d\n", n);
+				goto out;
+			}
+
+			len -= n;
+			offset += n;
+		}
+
+		if (req->offset < sizeof(reply->data))
+			reply->data[req->offset] = 1;
+
+		offset = 0;
+		len = sizeof(*reply);
+
+		while (len) {
+			n = write(1, ((void *)reply) + offset, len);
+			if (n <= 0) {
+				fprintf(debug_f, "reply failed %d\n", n);
+				goto out;
+			}
+
+			len -= n;
+			offset += n;
+		}
+
+		if (req->offset < sizeof(reply->data))
+			reply->data[req->offset] = 0;
+	}
+out:
+	free(req);
+	free(reply);
+}
+
+int main(void)
+{
+	debug_f = fopen("/dev/kmsg", "w");
+	setvbuf(debug_f, 0, _IOLBF, 0);
+	fprintf(debug_f, "<5>Started sample_umh\n");
+	loop();
+	fclose(debug_f);
+
+	return 0;
+}
diff --git a/tools/testing/selftests/umd_mgmt/sample_umd/sample_loader.c b/tools/testing/selftests/umd_mgmt/sample_umd/sample_loader.c
new file mode 100644
index 00000000000..36c0e69e3f7
--- /dev/null
+++ b/tools/testing/selftests/umd_mgmt/sample_umd/sample_loader.c
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ *
+ * Implement the UMD Loader (credits: bpfilter).
+ */
+#include <linux/module.h>
+#include <linux/usermode_driver_mgmt.h>
+
+extern char sample_umh_start;
+extern char sample_umh_end;
+extern struct umd_mgmt sample_mgmt_ops;
+
+static int __init load_umh(void)
+{
+	return umd_mgmt_load(&sample_mgmt_ops, &sample_umh_start,
+			     &sample_umh_end);
+}
+
+static void __exit fini_umh(void)
+{
+	umd_mgmt_unload(&sample_mgmt_ops);
+}
+module_init(load_umh);
+module_exit(fini_umh);
+MODULE_LICENSE("GPL");
diff --git a/tools/testing/selftests/umd_mgmt/sample_umd/sample_mgr.c b/tools/testing/selftests/umd_mgmt/sample_umd/sample_mgr.c
new file mode 100644
index 00000000000..75c572f9849
--- /dev/null
+++ b/tools/testing/selftests/umd_mgmt/sample_umd/sample_mgr.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ *
+ * Implement the UMD Manager.
+ */
+#include <linux/module.h>
+#include <linux/security.h>
+#include <linux/seq_file.h>
+#include <linux/usermode_driver_mgmt.h>
+
+#include "msgfmt.h"
+
+struct umd_mgmt sample_mgmt_ops;
+EXPORT_SYMBOL_GPL(sample_mgmt_ops);
+
+struct dentry *sample_umd_dentry;
+
+static int sample_write_common(u32 offset, bool test)
+{
+	struct sample_request *req;
+	struct sample_reply *reply;
+	int ret;
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	reply = kzalloc(sizeof(*reply), GFP_KERNEL);
+	if (!reply) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	req->offset = offset;
+
+	if (test)
+		/* Lock is already taken. */
+		ret = umd_send_recv(&sample_mgmt_ops.info, req, sizeof(*req),
+				    reply, sizeof(*reply));
+	else
+		ret = umd_mgmt_send_recv(&sample_mgmt_ops, req, sizeof(*req),
+					 reply, sizeof(*reply));
+	if (ret < 0)
+		goto out;
+
+	if (reply->data[req->offset] != 1) {
+		ret = -EINVAL;
+		goto out;
+	}
+out:
+	kfree(req);
+	kfree(reply);
+
+	return ret;
+}
+
+static ssize_t sample_umd_write(struct file *file, const char __user *buf,
+				size_t datalen, loff_t *ppos)
+{
+	char offset_str[8];
+	u32 offset;
+	int ret;
+
+	if (datalen >= sizeof(offset_str))
+		return -EINVAL;
+
+	ret = copy_from_user(offset_str, buf, datalen);
+	if (ret < 0)
+		return ret;
+
+	offset_str[datalen] = '\0';
+
+	ret = kstrtou32(offset_str, 10, &offset);
+	if (ret < 0)
+		return ret;
+
+	if (offset >= sizeof(((struct sample_reply *)0)->data))
+		return -EINVAL;
+
+	ret = sample_write_common(offset, false);
+	if (ret < 0)
+		return ret;
+
+	return datalen;
+}
+
+static const struct file_operations sample_umd_file_ops = {
+	.write = sample_umd_write,
+};
+
+static int sample_post_start_umh(struct umd_mgmt *mgmt)
+{
+	return sample_write_common(0, true);
+}
+
+static int __init load_umh(void)
+{
+	mutex_init(&sample_mgmt_ops.lock);
+	sample_mgmt_ops.info.tgid = NULL;
+	sample_mgmt_ops.info.driver_name = "sample_umh";
+	sample_mgmt_ops.post_start = sample_post_start_umh;
+	sample_mgmt_ops.kmod = "sample_loader_kmod";
+	sample_mgmt_ops.kmod_loaded = false;
+
+	sample_umd_dentry = securityfs_create_file("sample_umd", 0200, NULL,
+						   NULL, &sample_umd_file_ops);
+	if (IS_ERR(sample_umd_dentry))
+		return PTR_ERR(sample_umd_dentry);
+
+	return 0;
+}
+
+static void __exit fini_umh(void)
+{
+	securityfs_remove(sample_umd_dentry);
+}
+module_init(load_umh);
+module_exit(fini_umh);
+MODULE_LICENSE("GPL");
diff --git a/tools/testing/selftests/umd_mgmt/umd_mgmt.sh b/tools/testing/selftests/umd_mgmt/umd_mgmt.sh
new file mode 100755
index 00000000000..9b90d737fec
--- /dev/null
+++ b/tools/testing/selftests/umd_mgmt/umd_mgmt.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2023 Huawei Technologies Duesseldorf GmbH
+#
+# Author: Roberto Sassu <roberto.sassu@huawei.com>
+#
+# Script to test the UMD management library.
+
+# Kselftest framework defines: ksft_pass=0, ksft_fail=1, ksft_skip=4
+ksft_pass=0
+ksft_fail=1
+ksft_skip=4
+
+if ! /sbin/modprobe -q sample_mgr; then
+	echo "umd_mgmt: module sample_mgr is not found [SKIP]"
+	exit $ksft_skip
+fi
+
+if [ ! -f /sys/kernel/security/sample_umd ]; then
+	echo "umd_mgmt: kernel interface is not found [SKIP]"
+	exit $ksft_skip
+fi
+
+i=0
+
+while [ $i -lt 500 ]; do
+	if ! echo $(( RANDOM % 128 * 1024 )) > /sys/kernel/security/sample_umd; then
+		echo "umd_mgmt: test failed"
+		exit $ksft_fail
+	fi
+
+	if [ $(( i % 50 )) -eq 0 ]; then
+		rmmod sample_loader_kmod
+	fi
+
+	(( i++ ))
+done
+
+exit $ksft_pass
