Blame view

lib/usercopy.c 2.01 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
d597580d3   Al Viro   generic ...copy_....
2
  #include <linux/uaccess.h>
f5a1a536f   Aleksa Sarai   lib: introduce co...
3
  #include <linux/bitops.h>
d597580d3   Al Viro   generic ...copy_....
4
5
6
7
8
9
10
  
  /* out-of-line parts */
  
  #ifndef INLINE_COPY_FROM_USER
  unsigned long _copy_from_user(void *to, const void __user *from, unsigned long n)
  {
  	unsigned long res = n;
9c5f6908d   Al Viro   copy_{from,to}_us...
11
  	might_fault();
96d4f267e   Linus Torvalds   Remove 'type' arg...
12
  	if (likely(access_ok(from, n))) {
9c5f6908d   Al Viro   copy_{from,to}_us...
13
  		kasan_check_write(to, n);
d597580d3   Al Viro   generic ...copy_....
14
  		res = raw_copy_from_user(to, from, n);
9c5f6908d   Al Viro   copy_{from,to}_us...
15
  	}
d597580d3   Al Viro   generic ...copy_....
16
17
18
19
20
21
22
23
  	if (unlikely(res))
  		memset(to + (n - res), 0, res);
  	return res;
  }
  EXPORT_SYMBOL(_copy_from_user);
  #endif
  
  #ifndef INLINE_COPY_TO_USER
a0e94598e   Christophe Leroy   Fix misannotated ...
24
  unsigned long _copy_to_user(void __user *to, const void *from, unsigned long n)
d597580d3   Al Viro   generic ...copy_....
25
  {
9c5f6908d   Al Viro   copy_{from,to}_us...
26
  	might_fault();
96d4f267e   Linus Torvalds   Remove 'type' arg...
27
  	if (likely(access_ok(to, n))) {
9c5f6908d   Al Viro   copy_{from,to}_us...
28
  		kasan_check_read(from, n);
d597580d3   Al Viro   generic ...copy_....
29
  		n = raw_copy_to_user(to, from, n);
9c5f6908d   Al Viro   copy_{from,to}_us...
30
  	}
d597580d3   Al Viro   generic ...copy_....
31
32
33
34
  	return n;
  }
  EXPORT_SYMBOL(_copy_to_user);
  #endif
f5a1a536f   Aleksa Sarai   lib: introduce co...
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
  
  /**
   * check_zeroed_user: check if a userspace buffer only contains zero bytes
   * @from: Source address, in userspace.
   * @size: Size of buffer.
   *
   * This is effectively shorthand for "memchr_inv(from, 0, size) == NULL" for
   * userspace addresses (and is more efficient because we don't care where the
   * first non-zero byte is).
   *
   * Returns:
   *  * 0: There were non-zero bytes present in the buffer.
   *  * 1: The buffer was full of zero bytes.
   *  * -EFAULT: access to userspace failed.
   */
  int check_zeroed_user(const void __user *from, size_t size)
  {
  	unsigned long val;
  	uintptr_t align = (uintptr_t) from % sizeof(unsigned long);
  
  	if (unlikely(size == 0))
  		return 1;
  
  	from -= align;
  	size += align;
  
  	if (!user_access_begin(from, size))
  		return -EFAULT;
  
  	unsafe_get_user(val, (unsigned long __user *) from, err_fault);
  	if (align)
  		val &= ~aligned_byte_mask(align);
  
  	while (size > sizeof(unsigned long)) {
  		if (unlikely(val))
  			goto done;
  
  		from += sizeof(unsigned long);
  		size -= sizeof(unsigned long);
  
  		unsafe_get_user(val, (unsigned long __user *) from, err_fault);
  	}
  
  	if (size < sizeof(unsigned long))
  		val &= aligned_byte_mask(size);
  
  done:
  	user_access_end();
  	return (val == 0);
  err_fault:
  	user_access_end();
  	return -EFAULT;
  }
  EXPORT_SYMBOL(check_zeroed_user);