diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index a7080c86fa76..8f5c042e70a7 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1825,6 +1825,8 @@ static inline bool unprivileged_ebpf_enabled(void)
 	return !sysctl_unprivileged_bpf_disabled;
 }
 
+int bpf_map_verify_value_sig(const void *mod, size_t modlen, bool verify);
+
 #else /* !CONFIG_BPF_SYSCALL */
 static inline struct bpf_prog *bpf_prog_get(u32 ufd)
 {
@@ -2034,6 +2036,11 @@ static inline bool unprivileged_ebpf_enabled(void)
 	return false;
 }
 
+static inline int bpf_map_verify_value_sig(const void *mod, size_t modlen,
+					   bool verify)
+{
+	return -EOPNOTSUPP;
+}
 #endif /* CONFIG_BPF_SYSCALL */
 
 void __bpf_free_used_btfs(struct bpf_prog_aux *aux,
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index f4009dbdf62d..a8e7803d2593 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -1226,6 +1226,9 @@ enum {
 
 /* Create a map that is suitable to be an inner map with dynamic max entries */
 	BPF_F_INNER_MAP		= (1U << 12),
+
+/* Verify map value (fmt: ver data+sig size(be32), ver data, sig, unver data) */
+	BPF_F_VERIFY_ELEM	= (1U << 13)
 };
 
 /* Flags for BPF_PROG_QUERY. */
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index fe40d3b9458f..b430fdd0e892 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -17,7 +17,7 @@
 
 #define ARRAY_CREATE_FLAG_MASK \
 	(BPF_F_NUMA_NODE | BPF_F_MMAPABLE | BPF_F_ACCESS_MASK | \
-	 BPF_F_PRESERVE_ELEMS | BPF_F_INNER_MAP)
+	 BPF_F_PRESERVE_ELEMS | BPF_F_INNER_MAP | BPF_F_VERIFY_ELEM)
 
 static void bpf_array_free_percpu(struct bpf_array *array)
 {
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 2b69306d3c6e..ca9e4a284120 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -35,6 +35,8 @@
 #include <linux/rcupdate_trace.h>
 #include <linux/memcontrol.h>
 #include <linux/trace_events.h>
+#include <linux/verification.h>
+#include <linux/module_signature.h>
 
 #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \
 			  (map)->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || \
@@ -180,6 +182,13 @@ static int bpf_map_update_value(struct bpf_map *map, struct fd f, void *key,
 {
 	int err;
 
+	if (map->map_flags & BPF_F_VERIFY_ELEM) {
+		err = bpf_map_verify_value_sig(value, bpf_map_value_size(map),
+					       true);
+		if (err < 0)
+			return err;
+	}
+
 	/* Need to create a kthread, thus must support schedule */
 	if (bpf_map_is_dev_bound(map)) {
 		return bpf_map_offload_update_elem(map, key, value, flags);
@@ -1057,6 +1066,11 @@ static int map_create(union bpf_attr *attr)
 	if (err)
 		return -EINVAL;
 
+	/* Allow signed data to go through update/push methods only. */
+	if ((attr->map_flags & BPF_F_VERIFY_ELEM) &&
+	    (attr->map_flags & BPF_F_MMAPABLE))
+		return -EINVAL;
+
 	if (attr->btf_vmlinux_value_type_id) {
 		if (attr->map_type != BPF_MAP_TYPE_STRUCT_OPS ||
 		    attr->btf_key_type_id || attr->btf_value_type_id)
@@ -1353,6 +1367,62 @@ static int map_lookup_elem(union bpf_attr *attr)
 	return err;
 }
 
+int bpf_map_verify_value_sig(const void *mod, size_t modlen, bool verify)
+{
+	const size_t marker_len = strlen(MODULE_SIG_STRING);
+	struct module_signature ms;
+	size_t sig_len;
+	u32 _modlen;
+	int ret;
+
+	/*
+	 * Format of mod:
+	 *
+	 * verified data+sig size (be32), verified data, sig, unverified data
+	 */
+	if (modlen <= sizeof(u32))
+		return -ENOENT;
+
+	_modlen = be32_to_cpu(*(u32 *)(mod));
+
+	if (_modlen > modlen - sizeof(u32))
+		return -EINVAL;
+
+	modlen = _modlen;
+	mod += sizeof(u32);
+
+	if (modlen <= marker_len)
+		return -ENOENT;
+
+	if (memcmp(mod + modlen - marker_len, MODULE_SIG_STRING, marker_len))
+		return -ENOENT;
+
+	modlen -= marker_len;
+
+	if (modlen <= sizeof(ms))
+		return -EBADMSG;
+
+	memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));
+
+	ret = mod_check_sig(&ms, modlen, "bpf_map_value");
+	if (ret)
+		return ret;
+
+	sig_len = be32_to_cpu(ms.sig_len);
+	modlen -= sig_len + sizeof(ms);
+
+	if (verify) {
+		ret = verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
+					     VERIFY_USE_SECONDARY_KEYRING,
+					     VERIFYING_UNSPECIFIED_SIGNATURE,
+					     NULL, NULL);
+		if (ret < 0)
+			return ret;
+	}
+
+	return modlen;
+}
+EXPORT_SYMBOL_GPL(bpf_map_verify_value_sig);
 
 #define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags
 
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index f4009dbdf62d..a8e7803d2593 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -1226,6 +1226,9 @@ enum {
 
 /* Create a map that is suitable to be an inner map with dynamic max entries */
 	BPF_F_INNER_MAP		= (1U << 12),
+
+/* Verify map value (fmt: ver data+sig size(be32), ver data, sig, unver data) */
+	BPF_F_VERIFY_ELEM	= (1U << 13)
 };
 
 /* Flags for BPF_PROG_QUERY. */
