git: 302c6d25da69 - main - Implement vmemdup_{array}_user

From: Vladimir Kondratyev <wulf_at_FreeBSD.org>
Date: Tue, 15 Sep 2026 20:19:00 UTC
The branch main has been updated by wulf:

URL: https://cgit.FreeBSD.org/src/commit/?id=302c6d25da6907ec762ff8937fa86d380743b000

commit 302c6d25da6907ec762ff8937fa86d380743b000
Author:     David Heidelberg <david@ixit.cz>
AuthorDate: 2026-09-15 20:17:52 +0000
Commit:     Vladimir Kondratyev <wulf@FreeBSD.org>
CommitDate: 2026-09-15 20:17:52 +0000

    Implement vmemdup_{array}_user
    
    This is what FreeBSD now does for memdup_user and memdup_array_user
    (which is wrong for memdup, but correct for vmemdup).
    
    The amdgpu DRM driver started this in Linux ~6.12.86+
    
    Reviewed by:    wulf
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D57444
---
 sys/compat/linuxkpi/common/include/linux/string.h | 26 +++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/sys/compat/linuxkpi/common/include/linux/string.h b/sys/compat/linuxkpi/common/include/linux/string.h
index 8a4da9e19c94..75d7212998cf 100644
--- a/sys/compat/linuxkpi/common/include/linux/string.h
+++ b/sys/compat/linuxkpi/common/include/linux/string.h
@@ -73,6 +73,21 @@ memdup_user(const void *ptr, size_t len)
 	return (retval);
 }
 
+static inline void *
+vmemdup_user(const void *ptr, size_t len)
+{
+	void *retval;
+	int error;
+
+	retval = malloc(len, M_KMALLOC, M_WAITOK);
+	error = linux_copyin(ptr, retval, len);
+	if (error != 0) {
+		free(retval, M_KMALLOC);
+		return (ERR_PTR(error));
+	}
+	return (retval);
+}
+
 static inline void *
 memdup_user_nul(const void *ptr, size_t len)
 {
@@ -100,6 +115,17 @@ memdup_array_user(const void *src, size_t n, size_t size)
 	return (memdup_user(src, len));
 }
 
+static inline void *
+vmemdup_array_user(const void *src, size_t n, size_t size)
+{
+	size_t len;
+
+	if (check_mul_overflow(n, size, &len))
+		return (ERR_PTR(-EOVERFLOW));
+
+	return (vmemdup_user(src, len));
+}
+
 static inline void *
 kmemdup(const void *src, size_t len, gfp_t gfp)
 {