1*185f3d38SThomas Gleixner /* 2*185f3d38SThomas Gleixner * User address space access functions. 3*185f3d38SThomas Gleixner * 4*185f3d38SThomas Gleixner * Copyright 1997 Andi Kleen <ak@muc.de> 5*185f3d38SThomas Gleixner * Copyright 1997 Linus Torvalds 6*185f3d38SThomas Gleixner * Copyright 2002 Andi Kleen <ak@suse.de> 7*185f3d38SThomas Gleixner */ 8*185f3d38SThomas Gleixner #include <linux/module.h> 9*185f3d38SThomas Gleixner #include <asm/uaccess.h> 10*185f3d38SThomas Gleixner 11*185f3d38SThomas Gleixner /* 12*185f3d38SThomas Gleixner * Copy a null terminated string from userspace. 13*185f3d38SThomas Gleixner */ 14*185f3d38SThomas Gleixner 15*185f3d38SThomas Gleixner #define __do_strncpy_from_user(dst,src,count,res) \ 16*185f3d38SThomas Gleixner do { \ 17*185f3d38SThomas Gleixner long __d0, __d1, __d2; \ 18*185f3d38SThomas Gleixner might_sleep(); \ 19*185f3d38SThomas Gleixner __asm__ __volatile__( \ 20*185f3d38SThomas Gleixner " testq %1,%1\n" \ 21*185f3d38SThomas Gleixner " jz 2f\n" \ 22*185f3d38SThomas Gleixner "0: lodsb\n" \ 23*185f3d38SThomas Gleixner " stosb\n" \ 24*185f3d38SThomas Gleixner " testb %%al,%%al\n" \ 25*185f3d38SThomas Gleixner " jz 1f\n" \ 26*185f3d38SThomas Gleixner " decq %1\n" \ 27*185f3d38SThomas Gleixner " jnz 0b\n" \ 28*185f3d38SThomas Gleixner "1: subq %1,%0\n" \ 29*185f3d38SThomas Gleixner "2:\n" \ 30*185f3d38SThomas Gleixner ".section .fixup,\"ax\"\n" \ 31*185f3d38SThomas Gleixner "3: movq %5,%0\n" \ 32*185f3d38SThomas Gleixner " jmp 2b\n" \ 33*185f3d38SThomas Gleixner ".previous\n" \ 34*185f3d38SThomas Gleixner ".section __ex_table,\"a\"\n" \ 35*185f3d38SThomas Gleixner " .align 8\n" \ 36*185f3d38SThomas Gleixner " .quad 0b,3b\n" \ 37*185f3d38SThomas Gleixner ".previous" \ 38*185f3d38SThomas Gleixner : "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \ 39*185f3d38SThomas Gleixner "=&D" (__d2) \ 40*185f3d38SThomas Gleixner : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \ 41*185f3d38SThomas Gleixner : "memory"); \ 42*185f3d38SThomas Gleixner } while (0) 43*185f3d38SThomas Gleixner 44*185f3d38SThomas Gleixner long 45*185f3d38SThomas Gleixner __strncpy_from_user(char *dst, const char __user *src, long count) 46*185f3d38SThomas Gleixner { 47*185f3d38SThomas Gleixner long res; 48*185f3d38SThomas Gleixner __do_strncpy_from_user(dst, src, count, res); 49*185f3d38SThomas Gleixner return res; 50*185f3d38SThomas Gleixner } 51*185f3d38SThomas Gleixner EXPORT_SYMBOL(__strncpy_from_user); 52*185f3d38SThomas Gleixner 53*185f3d38SThomas Gleixner long 54*185f3d38SThomas Gleixner strncpy_from_user(char *dst, const char __user *src, long count) 55*185f3d38SThomas Gleixner { 56*185f3d38SThomas Gleixner long res = -EFAULT; 57*185f3d38SThomas Gleixner if (access_ok(VERIFY_READ, src, 1)) 58*185f3d38SThomas Gleixner return __strncpy_from_user(dst, src, count); 59*185f3d38SThomas Gleixner return res; 60*185f3d38SThomas Gleixner } 61*185f3d38SThomas Gleixner EXPORT_SYMBOL(strncpy_from_user); 62*185f3d38SThomas Gleixner 63*185f3d38SThomas Gleixner /* 64*185f3d38SThomas Gleixner * Zero Userspace 65*185f3d38SThomas Gleixner */ 66*185f3d38SThomas Gleixner 67*185f3d38SThomas Gleixner unsigned long __clear_user(void __user *addr, unsigned long size) 68*185f3d38SThomas Gleixner { 69*185f3d38SThomas Gleixner long __d0; 70*185f3d38SThomas Gleixner might_sleep(); 71*185f3d38SThomas Gleixner /* no memory constraint because it doesn't change any memory gcc knows 72*185f3d38SThomas Gleixner about */ 73*185f3d38SThomas Gleixner asm volatile( 74*185f3d38SThomas Gleixner " testq %[size8],%[size8]\n" 75*185f3d38SThomas Gleixner " jz 4f\n" 76*185f3d38SThomas Gleixner "0: movq %[zero],(%[dst])\n" 77*185f3d38SThomas Gleixner " addq %[eight],%[dst]\n" 78*185f3d38SThomas Gleixner " decl %%ecx ; jnz 0b\n" 79*185f3d38SThomas Gleixner "4: movq %[size1],%%rcx\n" 80*185f3d38SThomas Gleixner " testl %%ecx,%%ecx\n" 81*185f3d38SThomas Gleixner " jz 2f\n" 82*185f3d38SThomas Gleixner "1: movb %b[zero],(%[dst])\n" 83*185f3d38SThomas Gleixner " incq %[dst]\n" 84*185f3d38SThomas Gleixner " decl %%ecx ; jnz 1b\n" 85*185f3d38SThomas Gleixner "2:\n" 86*185f3d38SThomas Gleixner ".section .fixup,\"ax\"\n" 87*185f3d38SThomas Gleixner "3: lea 0(%[size1],%[size8],8),%[size8]\n" 88*185f3d38SThomas Gleixner " jmp 2b\n" 89*185f3d38SThomas Gleixner ".previous\n" 90*185f3d38SThomas Gleixner ".section __ex_table,\"a\"\n" 91*185f3d38SThomas Gleixner " .align 8\n" 92*185f3d38SThomas Gleixner " .quad 0b,3b\n" 93*185f3d38SThomas Gleixner " .quad 1b,2b\n" 94*185f3d38SThomas Gleixner ".previous" 95*185f3d38SThomas Gleixner : [size8] "=c"(size), [dst] "=&D" (__d0) 96*185f3d38SThomas Gleixner : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr), 97*185f3d38SThomas Gleixner [zero] "r" (0UL), [eight] "r" (8UL)); 98*185f3d38SThomas Gleixner return size; 99*185f3d38SThomas Gleixner } 100*185f3d38SThomas Gleixner EXPORT_SYMBOL(__clear_user); 101*185f3d38SThomas Gleixner 102*185f3d38SThomas Gleixner unsigned long clear_user(void __user *to, unsigned long n) 103*185f3d38SThomas Gleixner { 104*185f3d38SThomas Gleixner if (access_ok(VERIFY_WRITE, to, n)) 105*185f3d38SThomas Gleixner return __clear_user(to, n); 106*185f3d38SThomas Gleixner return n; 107*185f3d38SThomas Gleixner } 108*185f3d38SThomas Gleixner EXPORT_SYMBOL(clear_user); 109*185f3d38SThomas Gleixner 110*185f3d38SThomas Gleixner /* 111*185f3d38SThomas Gleixner * Return the size of a string (including the ending 0) 112*185f3d38SThomas Gleixner * 113*185f3d38SThomas Gleixner * Return 0 on exception, a value greater than N if too long 114*185f3d38SThomas Gleixner */ 115*185f3d38SThomas Gleixner 116*185f3d38SThomas Gleixner long __strnlen_user(const char __user *s, long n) 117*185f3d38SThomas Gleixner { 118*185f3d38SThomas Gleixner long res = 0; 119*185f3d38SThomas Gleixner char c; 120*185f3d38SThomas Gleixner 121*185f3d38SThomas Gleixner while (1) { 122*185f3d38SThomas Gleixner if (res>n) 123*185f3d38SThomas Gleixner return n+1; 124*185f3d38SThomas Gleixner if (__get_user(c, s)) 125*185f3d38SThomas Gleixner return 0; 126*185f3d38SThomas Gleixner if (!c) 127*185f3d38SThomas Gleixner return res+1; 128*185f3d38SThomas Gleixner res++; 129*185f3d38SThomas Gleixner s++; 130*185f3d38SThomas Gleixner } 131*185f3d38SThomas Gleixner } 132*185f3d38SThomas Gleixner EXPORT_SYMBOL(__strnlen_user); 133*185f3d38SThomas Gleixner 134*185f3d38SThomas Gleixner long strnlen_user(const char __user *s, long n) 135*185f3d38SThomas Gleixner { 136*185f3d38SThomas Gleixner if (!access_ok(VERIFY_READ, s, n)) 137*185f3d38SThomas Gleixner return 0; 138*185f3d38SThomas Gleixner return __strnlen_user(s, n); 139*185f3d38SThomas Gleixner } 140*185f3d38SThomas Gleixner EXPORT_SYMBOL(strnlen_user); 141*185f3d38SThomas Gleixner 142*185f3d38SThomas Gleixner long strlen_user(const char __user *s) 143*185f3d38SThomas Gleixner { 144*185f3d38SThomas Gleixner long res = 0; 145*185f3d38SThomas Gleixner char c; 146*185f3d38SThomas Gleixner 147*185f3d38SThomas Gleixner for (;;) { 148*185f3d38SThomas Gleixner if (get_user(c, s)) 149*185f3d38SThomas Gleixner return 0; 150*185f3d38SThomas Gleixner if (!c) 151*185f3d38SThomas Gleixner return res+1; 152*185f3d38SThomas Gleixner res++; 153*185f3d38SThomas Gleixner s++; 154*185f3d38SThomas Gleixner } 155*185f3d38SThomas Gleixner } 156*185f3d38SThomas Gleixner EXPORT_SYMBOL(strlen_user); 157*185f3d38SThomas Gleixner 158*185f3d38SThomas Gleixner unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len) 159*185f3d38SThomas Gleixner { 160*185f3d38SThomas Gleixner if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) { 161*185f3d38SThomas Gleixner return copy_user_generic((__force void *)to, (__force void *)from, len); 162*185f3d38SThomas Gleixner } 163*185f3d38SThomas Gleixner return len; 164*185f3d38SThomas Gleixner } 165*185f3d38SThomas Gleixner EXPORT_SYMBOL(copy_in_user); 166*185f3d38SThomas Gleixner 167