diff --git a/include/linux/flex_array.h b/include/linux/flex_array.h
new file mode 100644
index 000000000000..ebdbf0e5f722
--- /dev/null
+++ b/include/linux/flex_array.h
@@ -0,0 +1,325 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_FLEX_ARRAY_H_
+#define _LINUX_FLEX_ARRAY_H_
+
+#include <linux/string.h>
+
+/* Make sure we compose correctly with KASAN. */
+#ifndef __underlying_memcpy
+#define __underlying_memcpy     __builtin_memcpy
+#endif
+#ifndef __underlying_memset
+#define __underlying_memset	__builtin_memset
+#endif
+
+/*
+ * A "flexible array structure" (FAS) is a structure which ends with a
+ * flexible array member (FAM) _and_ contains another member that represents
+ * how many array elements are present in the struct instance's flexible
+ * array member:
+ *
+ * struct flex_array_struct_example {
+ *	...		// arbitrary members
+ *	u16 part_count;	// count of elements stored in "parts" below.
+ *	...		// arbitrary members
+ *	u32 parts[];	// flexible array member containing u32 elements.
+ * };
+ *
+ * Without the "count of elements" member, a structure ending with a
+ * flexible array has no way to check its own size, and should be
+ * considered just a blob of memory that is length-checked through some
+ * other means. Kernel structures with flexible arrays should strive to
+ * always be true flexible array structures so that they can be operated
+ * on with the flex*()-family of helpers defined below.
+ *
+ * To use the normal flex*() helpers, prepare for future C syntax that
+ * would identify a flex array's count member directly, and keep kernel
+ * declarations minimized, a common declaration, bounded_flex_array(), is
+ * provided:
+ *
+ * struct flex_array_struct_example {
+ *	...			 // arbitrary members
+ *	bounded_flex_array(
+ *		u16, part_count, // count of elements stored in "parts" below.
+ *		u32, parts	 // flexible array with elements of type u32.
+ *	);
+ * );
+ *
+ * To handle the less common case when the count member cannot be made a
+ * neighbor of the flex array, either the extended flex*() helpers can be
+ * used, or the members can also be declared separately:
+ *
+ * struct flex_array_struct_example {
+ *	...		// position-sensitive members
+ *	// count of elements stored in "parts" below.
+ *	DECLARE_FAS_COUNT(u16, part_count);
+ *	..		// position-sensitive members
+ *	// flexible array with elements of type u32.
+ *	DECLARE_FAS_ARRAY(u32, parts);
+ * };
+ *
+ * The above two declaration styles will create an alias for part_count as
+ * __flex_array_elements_count and for parts as __flex_array_elements,
+ * which are used internally to avoid needing to repeat the member names
+ * as arguments to the normal flex*() helpers.
+ *
+ * The extended flex*() helpers are designed to be used in the less common
+ * situations when the member aliases are not available, especially in two
+ * flexible array struct layout situations: "encapsulated" and "split".
+ *
+ * An "encapsulated flexible array structure" is a structure that contains
+ * a full "flexible array structure" as its final struct member. These are
+ * used frequently when needing to pass around a copy of a flexible array
+ * structure, and track other things about the data outside of the scope of
+ * the flexible array structure itself:
+ *
+ * struct encapsulated_example {
+ *	...		// arbitrary members
+ *	struct flex_array_struct_example fas;
+ * };
+ *
+ * A "split flexible array structure" is like an encapsulated flexible
+ * array struct, but the element count member is at a different level,
+ * separate from the struct that contains the flexible array:
+ *
+ * struct blob_example {
+ *	...		// arbitrary members
+ *	u32 parts[];	// flexible array with elements of type u32.
+ * };
+ *
+ * struct split_example {
+ *	...		// arbitrary members
+ *	u16 part_count;	// count of elements stored in "parts" below.
+ *	...		// arbitrary members
+ *	struct blob_example blob;
+ * };
+ *
+ * In the case where the element count member is not stored in native
+ * CPU format, the extended helpers can be used to specify the to/from
+ * cpu helper needed to do the conversions.
+ *
+ * Examples of using flex_cpy():
+ *
+ *	struct simple {
+ *		u32 flags;
+ *		bounded_flex_array(
+ *			u32,	count,
+ *			u8,	data
+ *		);
+ *	};
+ *	struct hardware_defined {
+ *		DECLARE_FAS_COUNT(u32, count);
+ *		u32 state;
+ *		u32 flags;
+ *		DECLARE_FAS_ARRAY(u8, data);
+ *	};
+ *
+ *	int do_simple(struct simple *src) {
+ *		struct simple *ptr_simple = NULL;
+ *		struct hardware_defined *ptr_hw = NULL;
+ *
+ *		...allocation of ptr_simple happens...
+ *		ptr_simple->count = src->count;
+ *		rc = flex_cpy(ptr_simple, src);
+ *		...
+ *		...allocation of ptr_hw happens...
+ *		ptr_hw->count = src->count;
+ *		rc = flex_cpy(ptr_hw, src);
+ *		...
+ *	}
+ *
+ *	struct blob {
+ *		u32 flags;
+ *		u8 data[];
+ *	};
+ *	struct split {
+ *		be32 count;
+ *		struct blob blob;
+ *	};
+ *	struct split *ptr_split = NULL;
+ *
+ *	int do_split(struct split *src) {
+ *		struct split *ptr = NULL;
+ *
+ *		...allocation of ptr happens...
+ *		ptr->count = src->count;
+ *		rc = __flex_cpy(ptr, src, blob.data, count, be32_to_cpu);
+ *		...
+ *	}
+ *
+ */
+
+/* Wrappers around the UAPI macros. */
+#define bounded_flex_array(COUNT_TYPE, COUNT_NAME, ARRAY_TYPE, ARRAY_NAME) \
+	__DECLARE_FAS_COUNT(COUNT_TYPE, COUNT_NAME);	\
+	__DECLARE_FAS_ARRAY(ARRAY_TYPE, ARRAY_NAME)
+
+#define DECLARE_FAS_COUNT(TYPE, NAME)			\
+	__DECLARE_FAS_COUNT(TYPE, NAME)
+
+#define DECLARE_FAS_ARRAY(TYPE, NAME)			\
+	__DECLARE_FAS_ARRAY(TYPE, NAME)
+
+/* All the helpers return negative on failure, and must be checked. */
+static inline int __must_check __must_check_errno(int err)
+{
+	return err;
+}
+
+#define __passthru(x)	(x)
+
+/**
+ * __fas_elements_bytes - Calculate potential size of the flexible
+ *			  array elements of a given flexible array
+ *			  structure
+ *
+ * @p: Pointer to flexible array structure.
+ * @flex_member: Member name of the flexible array elements.
+ * @count_member: Member name of the flexible array elements count.
+ * @elements_count: Count of proposed number of @p->__flex_array_elements
+ * @bytes: Pointer to variable to write calculation of total size in bytes.
+ *
+ * Returns: 0 on successful calculation, -ve on error.
+ *
+ * This performs the same calculation as flex_array_size(), except
+ * that the result is bounds checked and written to @bytes instead
+ * of being returned.
+ */
+#define __fas_elements_bytes(p, flex_member, count_member,		\
+			     elements_count, bytes)			\
+__must_check_errno(({							\
+	int __feb_err = -EINVAL;					\
+	size_t __feb_elements_count = (elements_count);			\
+	size_t __feb_elements_max =					\
+		type_max(typeof((p)->count_member));			\
+	if (__feb_elements_count > __feb_elements_max ||		\
+	    check_mul_overflow(sizeof(*(p)->flex_member),		\
+			       __feb_elements_count, bytes)) {		\
+		*(bytes) = 0;						\
+		__feb_err = -E2BIG;					\
+	} else {							\
+		__feb_err = 0;						\
+	}								\
+	__feb_err;							\
+}))
+
+/**
+ * fas_elements_bytes - Calculate current size of the flexible array
+ *			elements of a given flexible array structure
+ *
+ * @p: Pointer to flexible array structure.
+ * @bytes: Pointer to variable to write calculation of total size in bytes.
+ *
+ * Returns: 0 on successful calculation, -ve on error.
+ *
+ * This performs the same calculation as flex_array_size(), except
+ * that the result is bounds checked and written to @bytes instead
+ * of being returned.
+ */
+#define fas_elements_bytes(p, bytes)					\
+	__fas_elements_bytes(p, __flex_array_elements,			\
+			     __flex_array_elements_count,		\
+			     (p)->__flex_array_elements_count, bytes)
+
+/**
+ * __fas_bytes - Calculate potential size of flexible array structure
+ *
+ * @p: Pointer to flexible array structure.
+ * @flex_member: Member name of the flexible array elements.
+ * @count_member: Member name of the flexible array elements count.
+ * @elements_count: Count of proposed number of @p->__flex_array_elements
+ * @bytes: Pointer to variable to write calculation of total size in bytes.
+ *
+ * Returns: 0 on successful calculation, -ve on error.
+ *
+ * This performs the same calculation as struct_size(), except
+ * that the result is bounds checked and written to @bytes instead
+ * of being returned.
+ */
+#define __fas_bytes(p, flex_member, count_member, elements_count, bytes)\
+__must_check_errno(({							\
+	int __fasb_err;							\
+	typeof(*bytes) __fasb_bytes;					\
+									\
+	if (__fas_elements_bytes(p, flex_member, count_member,		\
+				 elements_count, &__fasb_bytes) ||	\
+	    check_add_overflow(sizeof(*(p)), __fasb_bytes, bytes)) {	\
+		*(bytes) = 0;						\
+		__fasb_err = -E2BIG;					\
+	} else {							\
+		__fasb_err = 0;						\
+	}								\
+	__fasb_err;							\
+}))
+
+/**
+ * fas_bytes - Calculate current size of flexible array structure
+ *
+ * @p: Pointer to flexible array structure.
+ * @bytes: Pointer to variable to write calculation of total size in bytes.
+ *
+ * This performs the same calculation as struct_size(), except
+ * that the result is bounds checked and written to @bytes instead
+ * of being returned, using the current size of the flexible array
+ * structure (via @p->__flexible_array_elements_count).
+ *
+ * Returns: 0 on successful calculation, -ve on error.
+ */
+#define fas_bytes(p, bytes)						\
+	__fas_bytes(p, __flex_array_elements,				\
+		    __flex_array_elements_count,			\
+		    (p)->__flex_array_elements_count, bytes)
+
+/**
+ * flex_cpy - Copy from one flexible array struct into another
+ *
+ * @dst: Destination pointer
+ * @src: Source pointer
+ *
+ * The full structure of @src will be copied to @dst, including all trailing
+ * flexible array elements. @dst->__flex_array_elements_count must be large
+ * enough to hold @src->__flex_array_elements_count. Any elements left over
+ * in @dst will be zero-wiped.
+ *
+ * Returns: 0 on successful calculation, -ve on error.
+ */
+#define __flex_cpy(dst, src, elements_member, count_member, to_cpu)	\
+__must_check_errno(({							\
+	int __fc_err = -EINVAL;						\
+	typeof(*(dst)) *__fc_dst = (dst);				\
+	typeof(*(src)) *__fc_src = (src);				\
+	size_t __fc_dst_bytes, __fc_src_bytes;				\
+									\
+	BUILD_BUG_ON(!__same_type(*(__fc_dst), *(__fc_src)));		\
+									\
+	do {								\
+		if (__fas_bytes(__fc_dst,				\
+				elements_member,			\
+				count_member,				\
+				to_cpu(__fc_dst->count_member),		\
+				&__fc_dst_bytes) ||			\
+		    __fas_bytes(__fc_src,				\
+				elements_member,			\
+				count_member,				\
+				to_cpu(__fc_src->count_member),		\
+				&__fc_src_bytes) ||			\
+		    __fc_dst_bytes < __fc_src_bytes) {			\
+			/* do we need to wipe dst here? */		\
+			__fc_err = -E2BIG;				\
+			break;						\
+		}							\
+		__underlying_memcpy(__fc_dst, __fc_src, __fc_src_bytes);\
+		/* __flex_array_elements_count is included in memcpy */	\
+		/* Wipe any now-unused trailing elements in @dst: */	\
+		__underlying_memset((u8 *)__fc_dst + __fc_src_bytes, 0,	\
+				 __fc_dst_bytes - __fc_src_bytes);	\
+		__fc_err = 0;						\
+	} while (0);							\
+	__fc_err;							\
+}))
+
+#define flex_cpy(dst, src)						\
+	__flex_cpy(dst, src, __flex_array_elements,			\
+		   __flex_array_elements_count, __passthru)
+
+#endif /* _LINUX_FLEX_ARRAY_H_ */
diff --git a/include/linux/string.h b/include/linux/string.h
index cf7607b32102..9277f9e2a432 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -256,6 +256,7 @@ static inline const char *kbasename(const char *path)
 #define unsafe_memcpy(dst, src, bytes, justification)		\
 	memcpy(dst, src, bytes)
 #endif
+#include <linux/flex_array.h>
 
 void memcpy_and_pad(void *dest, size_t dest_len, const void *src, size_t count,
 		    int pad);
diff --git a/include/uapi/linux/stddef.h b/include/uapi/linux/stddef.h
index 7837ba4fe728..e16afe1951d8 100644
--- a/include/uapi/linux/stddef.h
+++ b/include/uapi/linux/stddef.h
@@ -44,4 +44,18 @@
 		struct { } __empty_ ## NAME; \
 		TYPE NAME[]; \
 	}
+
+/* For use with flexible array structure helpers, in <linux/flex_array.h> */
+#define __DECLARE_FAS_COUNT(TYPE, NAME)					\
+	union {								\
+		TYPE __flex_array_elements_count;			\
+		TYPE NAME;						\
+	}
+
+#define __DECLARE_FAS_ARRAY(TYPE, NAME)					\
+	union {								\
+		__DECLARE_FLEX_ARRAY(TYPE, __flex_array_elements);	\
+		__DECLARE_FLEX_ARRAY(TYPE, NAME);			\
+	}
+
 #endif
