git: fbaa247e8b7a - stable/15 - Implement vmemdup_{array}_user

From: Vladimir Kondratyev <wulf_at_FreeBSD.org>
Date: Tue, 22 Sep 2026 15:48:53 UTC
The branch stable/15 has been updated by wulf:

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

commit fbaa247e8b7a47af307255b01c81943b35af4486
Author:     David Heidelberg <david@ixit.cz>
AuthorDate: 2026-09-15 20:17:52 +0000
Commit:     Vladimir Kondratyev <wulf@FreeBSD.org>
CommitDate: 2026-09-22 15:47:03 +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
    
    (cherry picked from commit 302c6d25da6907ec762ff8937fa86d380743b000)
---
 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 b195dcc8fe9b..9df4ce0d796d 100644
--- a/sys/compat/linuxkpi/common/include/linux/string.h
+++ b/sys/compat/linuxkpi/common/include/linux/string.h
@@ -72,6 +72,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)
 {
@@ -99,6 +114,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)
 {