Skip to content

Commit 11ae5eb

Browse files
committed
Merge tag 'topic/vmemdup-user-array-2023-10-24-1' of git://anongit.freedesktop.org/drm/drm into drm-next
vmemdup-user-array API and changes with it. This is just a process PR to merge the topic branch into drm-next, this contains some core kernel and drm changes. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Dave Airlie <airlied@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/20231024010905.646830-1-airlied@redhat.com
2 parents 3f5ba63 + 06ab64a commit 11ae5eb

File tree

5 files changed

+46
-6
lines changed

5 files changed

+46
-6
lines changed

drivers/gpu/drm/drm_lease.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -510,8 +510,8 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
510510
/* Handle leased objects, if any */
511511
idr_init(&leases);
512512
if (object_count != 0) {
513-
object_ids = memdup_user(u64_to_user_ptr(cl->object_ids),
514-
array_size(object_count, sizeof(__u32)));
513+
object_ids = memdup_array_user(u64_to_user_ptr(cl->object_ids),
514+
object_count, sizeof(__u32));
515515
if (IS_ERR(object_ids)) {
516516
ret = PTR_ERR(object_ids);
517517
idr_destroy(&leases);

drivers/gpu/drm/vmwgfx/vmwgfx_surface.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -774,9 +774,9 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
774774
sizeof(metadata->mip_levels));
775775
metadata->num_sizes = num_sizes;
776776
metadata->sizes =
777-
memdup_user((struct drm_vmw_size __user *)(unsigned long)
777+
memdup_array_user((struct drm_vmw_size __user *)(unsigned long)
778778
req->size_addr,
779-
sizeof(*metadata->sizes) * metadata->num_sizes);
779+
metadata->num_sizes, sizeof(*metadata->sizes));
780780
if (IS_ERR(metadata->sizes)) {
781781
ret = PTR_ERR(metadata->sizes);
782782
goto out_no_sizes;

include/linux/string.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
#include <linux/compiler.h> /* for inline */
66
#include <linux/types.h> /* for size_t */
77
#include <linux/stddef.h> /* for NULL */
8+
#include <linux/err.h> /* for ERR_PTR() */
89
#include <linux/errno.h> /* for E2BIG */
10+
#include <linux/overflow.h> /* for check_mul_overflow() */
911
#include <linux/stdarg.h>
1012
#include <uapi/linux/string.h>
1113

@@ -14,6 +16,44 @@ extern void *memdup_user(const void __user *, size_t);
1416
extern void *vmemdup_user(const void __user *, size_t);
1517
extern void *memdup_user_nul(const void __user *, size_t);
1618

19+
/**
20+
* memdup_array_user - duplicate array from user space
21+
* @src: source address in user space
22+
* @n: number of array members to copy
23+
* @size: size of one array member
24+
*
25+
* Return: an ERR_PTR() on failure. Result is physically
26+
* contiguous, to be freed by kfree().
27+
*/
28+
static inline void *memdup_array_user(const void __user *src, size_t n, size_t size)
29+
{
30+
size_t nbytes;
31+
32+
if (check_mul_overflow(n, size, &nbytes))
33+
return ERR_PTR(-EOVERFLOW);
34+
35+
return memdup_user(src, nbytes);
36+
}
37+
38+
/**
39+
* vmemdup_array_user - duplicate array from user space
40+
* @src: source address in user space
41+
* @n: number of array members to copy
42+
* @size: size of one array member
43+
*
44+
* Return: an ERR_PTR() on failure. Result may be not
45+
* physically contiguous. Use kvfree() to free.
46+
*/
47+
static inline void *vmemdup_array_user(const void __user *src, size_t n, size_t size)
48+
{
49+
size_t nbytes;
50+
51+
if (check_mul_overflow(n, size, &nbytes))
52+
return ERR_PTR(-EOVERFLOW);
53+
54+
return vmemdup_user(src, nbytes);
55+
}
56+
1757
/*
1858
* Include machine specific inline routines
1959
*/

kernel/kexec.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments,
247247
((flags & KEXEC_ARCH_MASK) != KEXEC_ARCH_DEFAULT))
248248
return -EINVAL;
249249

250-
ksegments = memdup_user(segments, nr_segments * sizeof(ksegments[0]));
250+
ksegments = memdup_array_user(segments, nr_segments, sizeof(ksegments[0]));
251251
if (IS_ERR(ksegments))
252252
return PTR_ERR(ksegments);
253253

kernel/watch_queue.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ long watch_queue_set_filter(struct pipe_inode_info *pipe,
331331
filter.__reserved != 0)
332332
return -EINVAL;
333333

334-
tf = memdup_user(_filter->filters, filter.nr_filters * sizeof(*tf));
334+
tf = memdup_array_user(_filter->filters, filter.nr_filters, sizeof(*tf));
335335
if (IS_ERR(tf))
336336
return PTR_ERR(tf);
337337

0 commit comments

Comments
 (0)