0001
0002
0003
0004
0005 #include <linux/export.h>
0006 #include <linux/mm.h>
0007 #include <linux/uaccess.h>
0008
0009 bool __weak copy_from_kernel_nofault_allowed(const void *unsafe_src,
0010 size_t size)
0011 {
0012 return true;
0013 }
0014
0015 #define copy_from_kernel_nofault_loop(dst, src, len, type, err_label) \
0016 while (len >= sizeof(type)) { \
0017 __get_kernel_nofault(dst, src, type, err_label); \
0018 dst += sizeof(type); \
0019 src += sizeof(type); \
0020 len -= sizeof(type); \
0021 }
0022
0023 long copy_from_kernel_nofault(void *dst, const void *src, size_t size)
0024 {
0025 unsigned long align = 0;
0026
0027 if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))
0028 align = (unsigned long)dst | (unsigned long)src;
0029
0030 if (!copy_from_kernel_nofault_allowed(src, size))
0031 return -ERANGE;
0032
0033 pagefault_disable();
0034 if (!(align & 7))
0035 copy_from_kernel_nofault_loop(dst, src, size, u64, Efault);
0036 if (!(align & 3))
0037 copy_from_kernel_nofault_loop(dst, src, size, u32, Efault);
0038 if (!(align & 1))
0039 copy_from_kernel_nofault_loop(dst, src, size, u16, Efault);
0040 copy_from_kernel_nofault_loop(dst, src, size, u8, Efault);
0041 pagefault_enable();
0042 return 0;
0043 Efault:
0044 pagefault_enable();
0045 return -EFAULT;
0046 }
0047 EXPORT_SYMBOL_GPL(copy_from_kernel_nofault);
0048
0049 #define copy_to_kernel_nofault_loop(dst, src, len, type, err_label) \
0050 while (len >= sizeof(type)) { \
0051 __put_kernel_nofault(dst, src, type, err_label); \
0052 dst += sizeof(type); \
0053 src += sizeof(type); \
0054 len -= sizeof(type); \
0055 }
0056
0057 long copy_to_kernel_nofault(void *dst, const void *src, size_t size)
0058 {
0059 unsigned long align = 0;
0060
0061 if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))
0062 align = (unsigned long)dst | (unsigned long)src;
0063
0064 pagefault_disable();
0065 if (!(align & 7))
0066 copy_to_kernel_nofault_loop(dst, src, size, u64, Efault);
0067 if (!(align & 3))
0068 copy_to_kernel_nofault_loop(dst, src, size, u32, Efault);
0069 if (!(align & 1))
0070 copy_to_kernel_nofault_loop(dst, src, size, u16, Efault);
0071 copy_to_kernel_nofault_loop(dst, src, size, u8, Efault);
0072 pagefault_enable();
0073 return 0;
0074 Efault:
0075 pagefault_enable();
0076 return -EFAULT;
0077 }
0078
0079 long strncpy_from_kernel_nofault(char *dst, const void *unsafe_addr, long count)
0080 {
0081 const void *src = unsafe_addr;
0082
0083 if (unlikely(count <= 0))
0084 return 0;
0085 if (!copy_from_kernel_nofault_allowed(unsafe_addr, count))
0086 return -ERANGE;
0087
0088 pagefault_disable();
0089 do {
0090 __get_kernel_nofault(dst, src, u8, Efault);
0091 dst++;
0092 src++;
0093 } while (dst[-1] && src - unsafe_addr < count);
0094 pagefault_enable();
0095
0096 dst[-1] = '\0';
0097 return src - unsafe_addr;
0098 Efault:
0099 pagefault_enable();
0100 dst[-1] = '\0';
0101 return -EFAULT;
0102 }
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113 long copy_from_user_nofault(void *dst, const void __user *src, size_t size)
0114 {
0115 long ret = -EFAULT;
0116 if (access_ok(src, size)) {
0117 pagefault_disable();
0118 ret = __copy_from_user_inatomic(dst, src, size);
0119 pagefault_enable();
0120 }
0121
0122 if (ret)
0123 return -EFAULT;
0124 return 0;
0125 }
0126 EXPORT_SYMBOL_GPL(copy_from_user_nofault);
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137 long copy_to_user_nofault(void __user *dst, const void *src, size_t size)
0138 {
0139 long ret = -EFAULT;
0140
0141 if (access_ok(dst, size)) {
0142 pagefault_disable();
0143 ret = __copy_to_user_inatomic(dst, src, size);
0144 pagefault_enable();
0145 }
0146
0147 if (ret)
0148 return -EFAULT;
0149 return 0;
0150 }
0151 EXPORT_SYMBOL_GPL(copy_to_user_nofault);
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171 long strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
0172 long count)
0173 {
0174 long ret;
0175
0176 if (unlikely(count <= 0))
0177 return 0;
0178
0179 pagefault_disable();
0180 ret = strncpy_from_user(dst, unsafe_addr, count);
0181 pagefault_enable();
0182
0183 if (ret >= count) {
0184 ret = count;
0185 dst[ret - 1] = '\0';
0186 } else if (ret > 0) {
0187 ret++;
0188 }
0189
0190 return ret;
0191 }
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209 long strnlen_user_nofault(const void __user *unsafe_addr, long count)
0210 {
0211 int ret;
0212
0213 pagefault_disable();
0214 ret = strnlen_user(unsafe_addr, count);
0215 pagefault_enable();
0216
0217 return ret;
0218 }
0219
0220 void __copy_overflow(int size, unsigned long count)
0221 {
0222 WARN(1, "Buffer overflow detected (%d < %lu)!\n", size, count);
0223 }
0224 EXPORT_SYMBOL(__copy_overflow);