Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | /* * User address space access functions. * * Copyright 1997 Andi Kleen <ak@muc.de> * Copyright 1997 Linus Torvalds * Copyright 2002 Andi Kleen <ak@suse.de> */ #include <linux/module.h> #include <asm/uaccess.h> /* * Copy a null terminated string from userspace. */ #define __do_strncpy_from_user(dst,src,count,res) \ do { \ long __d0, __d1, __d2; \ might_fault(); \ __asm__ __volatile__( \ " testq %1,%1\n" \ " jz 2f\n" \ "0: lodsb\n" \ " stosb\n" \ " testb %%al,%%al\n" \ " jz 1f\n" \ " decq %1\n" \ " jnz 0b\n" \ "1: subq %1,%0\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ "3: movq %5,%0\n" \ " jmp 2b\n" \ ".previous\n" \ _ASM_EXTABLE(0b,3b) \ : "=&r"(res), "=&c"(count), "=&a" (__d0), "=&S" (__d1), \ "=&D" (__d2) \ : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \ : "memory"); \ } while (0) long __strncpy_from_user(char *dst, const char __user *src, long count) { long res; __do_strncpy_from_user(dst, src, count, res); return res; } EXPORT_SYMBOL(__strncpy_from_user); long strncpy_from_user(char *dst, const char __user *src, long count) { long res = -EFAULT; if (access_ok(VERIFY_READ, src, 1)) return __strncpy_from_user(dst, src, count); return res; } EXPORT_SYMBOL(strncpy_from_user); /* * Zero Userspace */ unsigned long __clear_user(void __user *addr, unsigned long size) { long __d0; might_fault(); /* no memory constraint because it doesn't change any memory gcc knows about */ asm volatile( " testq %[size8],%[size8]\n" " jz 4f\n" "0: movq %[zero],(%[dst])\n" " addq %[eight],%[dst]\n" " decl %%ecx ; jnz 0b\n" "4: movq %[size1],%%rcx\n" " testl %%ecx,%%ecx\n" " jz 2f\n" "1: movb %b[zero],(%[dst])\n" " incq %[dst]\n" " decl %%ecx ; jnz 1b\n" "2:\n" ".section .fixup,\"ax\"\n" "3: lea 0(%[size1],%[size8],8),%[size8]\n" " jmp 2b\n" ".previous\n" _ASM_EXTABLE(0b,3b) _ASM_EXTABLE(1b,2b) : [size8] "=&c"(size), [dst] "=&D" (__d0) : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr), [zero] "r" (0UL), [eight] "r" (8UL)); return size; } EXPORT_SYMBOL(__clear_user); unsigned long clear_user(void __user *to, unsigned long n) { if (access_ok(VERIFY_WRITE, to, n)) return __clear_user(to, n); return n; } EXPORT_SYMBOL(clear_user); /* * Return the size of a string (including the ending 0) * * Return 0 on exception, a value greater than N if too long */ long __strnlen_user(const char __user *s, long n) { long res = 0; char c; while (1) { if (res>n) return n+1; if (__get_user(c, s)) return 0; if (!c) return res+1; res++; s++; } } EXPORT_SYMBOL(__strnlen_user); long strnlen_user(const char __user *s, long n) { if (!access_ok(VERIFY_READ, s, 1)) return 0; return __strnlen_user(s, n); } EXPORT_SYMBOL(strnlen_user); long strlen_user(const char __user *s) { long res = 0; char c; for (;;) { if (get_user(c, s)) return 0; if (!c) return res+1; res++; s++; } } EXPORT_SYMBOL(strlen_user); unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len) { if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) { return copy_user_generic((__force void *)to, (__force void *)from, len); } return len; } EXPORT_SYMBOL(copy_in_user); /* * Try to copy last bytes and clear the rest if needed. * Since protection fault in copy_from/to_user is not a normal situation, * it is not necessary to optimize tail handling. */ unsigned long copy_user_handle_tail(char *to, char *from, unsigned len, unsigned zerorest) { char c; unsigned zero_len; for (; len; --len) { if (__get_user_nocheck(c, from++, sizeof(char))) break; if (__put_user_nocheck(c, to++, sizeof(char))) break; } for (c = 0, zero_len = len; zerorest && zero_len; --zero_len) if (__put_user_nocheck(c, to++, sizeof(char))) break; return len; } |