~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/mm/maccess.c

Version: ~ [ linux-6.1-rc7 ] ~ [ linux-6.0.10 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.80 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.156 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.225 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.267 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.300 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.334 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.302 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Access kernel or user memory without faulting.
  4  */
  5 #include <linux/export.h>
  6 #include <linux/mm.h>
  7 #include <linux/uaccess.h>
  8 
  9 bool __weak copy_from_kernel_nofault_allowed(const void *unsafe_src,
 10                 size_t size)
 11 {
 12         return true;
 13 }
 14 
 15 #define copy_from_kernel_nofault_loop(dst, src, len, type, err_label)   \
 16         while (len >= sizeof(type)) {                                   \
 17                 __get_kernel_nofault(dst, src, type, err_label);                \
 18                 dst += sizeof(type);                                    \
 19                 src += sizeof(type);                                    \
 20                 len -= sizeof(type);                                    \
 21         }
 22 
 23 long copy_from_kernel_nofault(void *dst, const void *src, size_t size)
 24 {
 25         unsigned long align = 0;
 26 
 27         if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))
 28                 align = (unsigned long)dst | (unsigned long)src;
 29 
 30         if (!copy_from_kernel_nofault_allowed(src, size))
 31                 return -ERANGE;
 32 
 33         pagefault_disable();
 34         if (!(align & 7))
 35                 copy_from_kernel_nofault_loop(dst, src, size, u64, Efault);
 36         if (!(align & 3))
 37                 copy_from_kernel_nofault_loop(dst, src, size, u32, Efault);
 38         if (!(align & 1))
 39                 copy_from_kernel_nofault_loop(dst, src, size, u16, Efault);
 40         copy_from_kernel_nofault_loop(dst, src, size, u8, Efault);
 41         pagefault_enable();
 42         return 0;
 43 Efault:
 44         pagefault_enable();
 45         return -EFAULT;
 46 }
 47 EXPORT_SYMBOL_GPL(copy_from_kernel_nofault);
 48 
 49 #define copy_to_kernel_nofault_loop(dst, src, len, type, err_label)     \
 50         while (len >= sizeof(type)) {                                   \
 51                 __put_kernel_nofault(dst, src, type, err_label);                \
 52                 dst += sizeof(type);                                    \
 53                 src += sizeof(type);                                    \
 54                 len -= sizeof(type);                                    \
 55         }
 56 
 57 long copy_to_kernel_nofault(void *dst, const void *src, size_t size)
 58 {
 59         unsigned long align = 0;
 60 
 61         if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))
 62                 align = (unsigned long)dst | (unsigned long)src;
 63 
 64         pagefault_disable();
 65         if (!(align & 7))
 66                 copy_to_kernel_nofault_loop(dst, src, size, u64, Efault);
 67         if (!(align & 3))
 68                 copy_to_kernel_nofault_loop(dst, src, size, u32, Efault);
 69         if (!(align & 1))
 70                 copy_to_kernel_nofault_loop(dst, src, size, u16, Efault);
 71         copy_to_kernel_nofault_loop(dst, src, size, u8, Efault);
 72         pagefault_enable();
 73         return 0;
 74 Efault:
 75         pagefault_enable();
 76         return -EFAULT;
 77 }
 78 
 79 long strncpy_from_kernel_nofault(char *dst, const void *unsafe_addr, long count)
 80 {
 81         const void *src = unsafe_addr;
 82 
 83         if (unlikely(count <= 0))
 84                 return 0;
 85         if (!copy_from_kernel_nofault_allowed(unsafe_addr, count))
 86                 return -ERANGE;
 87 
 88         pagefault_disable();
 89         do {
 90                 __get_kernel_nofault(dst, src, u8, Efault);
 91                 dst++;
 92                 src++;
 93         } while (dst[-1] && src - unsafe_addr < count);
 94         pagefault_enable();
 95 
 96         dst[-1] = '\0';
 97         return src - unsafe_addr;
 98 Efault:
 99         pagefault_enable();
100         dst[0] = '\0';
101         return -EFAULT;
102 }
103 
104 /**
105  * copy_from_user_nofault(): safely attempt to read from a user-space location
106  * @dst: pointer to the buffer that shall take the data
107  * @src: address to read from. This must be a user address.
108  * @size: size of the data chunk
109  *
110  * Safely read from user address @src to the buffer at @dst. If a kernel fault
111  * happens, handle that and return -EFAULT.
112  */
113 long copy_from_user_nofault(void *dst, const void __user *src, size_t size)
114 {
115         long ret = -EFAULT;
116         if (access_ok(src, size)) {
117                 pagefault_disable();
118                 ret = __copy_from_user_inatomic(dst, src, size);
119                 pagefault_enable();
120         }
121 
122         if (ret)
123                 return -EFAULT;
124         return 0;
125 }
126 EXPORT_SYMBOL_GPL(copy_from_user_nofault);
127 
128 /**
129  * copy_to_user_nofault(): safely attempt to write to a user-space location
130  * @dst: address to write to
131  * @src: pointer to the data that shall be written
132  * @size: size of the data chunk
133  *
134  * Safely write to address @dst from the buffer at @src.  If a kernel fault
135  * happens, handle that and return -EFAULT.
136  */
137 long copy_to_user_nofault(void __user *dst, const void *src, size_t size)
138 {
139         long ret = -EFAULT;
140 
141         if (access_ok(dst, size)) {
142                 pagefault_disable();
143                 ret = __copy_to_user_inatomic(dst, src, size);
144                 pagefault_enable();
145         }
146 
147         if (ret)
148                 return -EFAULT;
149         return 0;
150 }
151 EXPORT_SYMBOL_GPL(copy_to_user_nofault);
152 
153 /**
154  * strncpy_from_user_nofault: - Copy a NUL terminated string from unsafe user
155  *                              address.
156  * @dst:   Destination address, in kernel space.  This buffer must be at
157  *         least @count bytes long.
158  * @unsafe_addr: Unsafe user address.
159  * @count: Maximum number of bytes to copy, including the trailing NUL.
160  *
161  * Copies a NUL-terminated string from unsafe user address to kernel buffer.
162  *
163  * On success, returns the length of the string INCLUDING the trailing NUL.
164  *
165  * If access fails, returns -EFAULT (some data may have been copied
166  * and the trailing NUL added).
167  *
168  * If @count is smaller than the length of the string, copies @count-1 bytes,
169  * sets the last byte of @dst buffer to NUL and returns @count.
170  */
171 long strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
172                               long count)
173 {
174         long ret;
175 
176         if (unlikely(count <= 0))
177                 return 0;
178 
179         pagefault_disable();
180         ret = strncpy_from_user(dst, unsafe_addr, count);
181         pagefault_enable();
182 
183         if (ret >= count) {
184                 ret = count;
185                 dst[ret - 1] = '\0';
186         } else if (ret > 0) {
187                 ret++;
188         }
189 
190         return ret;
191 }
192 
193 /**
194  * strnlen_user_nofault: - Get the size of a user string INCLUDING final NUL.
195  * @unsafe_addr: The string to measure.
196  * @count: Maximum count (including NUL)
197  *
198  * Get the size of a NUL-terminated string in user space without pagefault.
199  *
200  * Returns the size of the string INCLUDING the terminating NUL.
201  *
202  * If the string is too long, returns a number larger than @count. User
203  * has to check the return value against "> count".
204  * On exception (or invalid count), returns 0.
205  *
206  * Unlike strnlen_user, this can be used from IRQ handler etc. because
207  * it disables pagefaults.
208  */
209 long strnlen_user_nofault(const void __user *unsafe_addr, long count)
210 {
211         int ret;
212 
213         pagefault_disable();
214         ret = strnlen_user(unsafe_addr, count);
215         pagefault_enable();
216 
217         return ret;
218 }
219 
220 void __copy_overflow(int size, unsigned long count)
221 {
222         WARN(1, "Buffer overflow detected (%d < %lu)!\n", size, count);
223 }
224 EXPORT_SYMBOL(__copy_overflow);
225 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp