]>
Commit | Line | Data |
---|---|---|
2466bf70 JS |
1 | /* -*- linux-c -*- |
2 | * Copy from user space functions | |
ef36f781 | 3 | * Copyright (C) 2005-2014 Red Hat Inc. |
2466bf70 JS |
4 | * Copyright (C) 2005 Intel Corporation. |
5 | * | |
6 | * This file is part of systemtap, and is free software. You can | |
7 | * redistribute it and/or modify it under the terms of the GNU General | |
8 | * Public License (GPL); either version 2, or (at your option) any | |
9 | * later version. | |
10 | */ | |
11 | ||
12 | #ifndef _STAPLINUX_COPY_C_ /* -*- linux-c -*- */ | |
13 | #define _STAPLINUX_COPY_C_ | |
14 | ||
15 | /** @file copy.c | |
16 | * @brief Functions to copy from user space. | |
17 | */ | |
18 | ||
19 | /** @addtogroup copy Functions to copy from user space. | |
20 | * Functions to copy from user space. | |
21 | * None of these functions will sleep (for example to allow pages | |
22 | * to be swapped in). It is possible (although rare) that the data | |
23 | * in user space will not present and these functions will return an error. | |
24 | * @{ | |
25 | */ | |
26 | ||
2466bf70 JS |
27 | #ifdef CONFIG_GENERIC_STRNCPY_FROM_USER |
28 | #define __stp_strncpy_from_user(dst,src,count,res) \ | |
29 | do { res = strncpy_from_user(dst, src, count); } while(0) | |
30 | #else /* !CONFIG_GENERIC_STRNCPY_FROM_USER */ | |
31 | #if defined (__i386__) | |
32 | #define __stp_strncpy_from_user(dst,src,count,res) \ | |
33 | do { \ | |
34 | int __d0, __d1, __d2; \ | |
35 | __asm__ __volatile__( \ | |
36 | " testl %1,%1\n" \ | |
37 | " jz 2f\n" \ | |
38 | "0: lodsb\n" \ | |
39 | " stosb\n" \ | |
40 | " testb %%al,%%al\n" \ | |
41 | " jz 1f\n" \ | |
42 | " decl %1\n" \ | |
43 | " jnz 0b\n" \ | |
44 | "1: subl %1,%0\n" \ | |
45 | "2:\n" \ | |
46 | ".section .fixup,\"ax\"\n" \ | |
47 | "3: movl %5,%0\n" \ | |
48 | " jmp 2b\n" \ | |
49 | ".previous\n" \ | |
50 | ".section __ex_table,\"a\"\n" \ | |
51 | " .align 4\n" \ | |
52 | " .long 0b,3b\n" \ | |
53 | ".previous" \ | |
54 | : "=d"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \ | |
55 | "=&D" (__d2) \ | |
56 | : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \ | |
57 | : "memory"); \ | |
58 | } while (0) | |
59 | #elif defined (__x86_64__) | |
60 | #define __stp_strncpy_from_user(dst,src,count,res) \ | |
61 | do { \ | |
62 | long __d0, __d1, __d2; \ | |
63 | __asm__ __volatile__( \ | |
64 | " testq %1,%1\n" \ | |
65 | " jz 2f\n" \ | |
66 | "0: lodsb\n" \ | |
67 | " stosb\n" \ | |
68 | " testb %%al,%%al\n" \ | |
69 | " jz 1f\n" \ | |
70 | " decq %1\n" \ | |
71 | " jnz 0b\n" \ | |
72 | "1: subq %1,%0\n" \ | |
73 | "2:\n" \ | |
74 | ".section .fixup,\"ax\"\n" \ | |
75 | "3: movq %5,%0\n" \ | |
76 | " jmp 2b\n" \ | |
77 | ".previous\n" \ | |
78 | ".section __ex_table,\"a\"\n" \ | |
79 | " .align 8\n" \ | |
80 | " .quad 0b,3b\n" \ | |
81 | ".previous" \ | |
82 | : "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \ | |
83 | "=&D" (__d2) \ | |
84 | : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \ | |
85 | : "memory"); \ | |
86 | } while (0) | |
87 | #elif defined (__powerpc__) || defined (__arm__) | |
88 | #define __stp_strncpy_from_user(dst,src,count,res) \ | |
89 | do { res = __strncpy_from_user(dst, src, count); } while(0) | |
90 | ||
930c64c1 | 91 | #elif defined (__s390__) || defined (__s390x__)|| defined (__aarch64__) |
2466bf70 JS |
92 | #define __stp_strncpy_from_user(dst,src,count,res) \ |
93 | do { res = strncpy_from_user(dst, src, count); } while(0) | |
94 | #elif defined (__ia64__) | |
95 | #define __stp_strncpy_from_user(dst,src,count,res) \ | |
b137ba9a | 96 | do { res = __strncpy_from_user(dst, src, count); } while(0) |
2466bf70 JS |
97 | #endif |
98 | #endif /* !CONFIG_GENERIC_STRNCPY_FROM_USER */ | |
99 | ||
b137ba9a | 100 | |
2466bf70 JS |
101 | /** Copy a NULL-terminated string from userspace. |
102 | * On success, returns the length of the string (not including the trailing | |
103 | * NULL). | |
104 | * | |
105 | * If access to userspace fails, returns -EFAULT (some data may have been | |
106 | * copied). | |
107 | * @param dst Destination address, in kernel space. This buffer must be at | |
108 | * least <i>count</i> bytes long. | |
109 | * @param src Source address, in user space. | |
110 | * @param count Maximum number of bytes to copy, including the trailing NULL. | |
111 | * | |
112 | * If <i>count</i> is smaller than the length of the string, copies | |
113 | * <i>count</i> bytes and returns <i>count</i>. | |
114 | */ | |
115 | ||
8fee9cc5 | 116 | /* XXX: see also kread/uread in loc2c-runtime.h */ |
2466bf70 JS |
117 | static long _stp_strncpy_from_user(char *dst, const char __user *src, long count) |
118 | { | |
119 | long res = -EFAULT; | |
8fee9cc5 FCE |
120 | mm_segment_t _oldfs = get_fs(); |
121 | set_fs(USER_DS); | |
122 | pagefault_disable(); | |
123 | if (access_ok(VERIFY_READ, src, count)) /* XXX: bad_addr? */ | |
2466bf70 | 124 | __stp_strncpy_from_user(dst, src, count, res); |
8fee9cc5 FCE |
125 | pagefault_enable(); |
126 | set_fs(_oldfs); | |
2466bf70 JS |
127 | return res; |
128 | } | |
129 | ||
130 | /** Copy a block of data from user space. | |
131 | * | |
7d860223 DS |
132 | * If data could not be copied, this function will not modify the |
133 | * destination. | |
134 | * | |
2466bf70 JS |
135 | * @param dst Destination address, in kernel space. |
136 | * @param src Source address, in user space. | |
137 | * @param count Number of bytes to copy. | |
138 | * @return number of bytes that could not be copied. On success, | |
139 | * this will be zero. | |
140 | * | |
141 | */ | |
142 | ||
b137ba9a | 143 | /* XXX: see also kread/uread in loc2c-runtime.h */ |
2466bf70 JS |
144 | static unsigned long _stp_copy_from_user(char *dst, const char __user *src, unsigned long count) |
145 | { | |
146 | if (count) { | |
b137ba9a FCE |
147 | mm_segment_t _oldfs = get_fs(); |
148 | set_fs(USER_DS); | |
149 | pagefault_disable(); | |
2466bf70 JS |
150 | if (access_ok(VERIFY_READ, src, count)) |
151 | count = __copy_from_user_inatomic(dst, src, count); | |
152 | else | |
7d860223 DS |
153 | /* Notice that if we fail, we don't modify |
154 | * the destination. In the failure case, we | |
155 | * can't trust 'count' to be reasonable. */ | |
156 | count = -EFAULT; | |
b137ba9a FCE |
157 | pagefault_enable(); |
158 | set_fs(_oldfs); | |
2466bf70 JS |
159 | } |
160 | return count; | |
161 | } | |
162 | ||
163 | /** @} */ | |
164 | #endif /* _STAPLINUX_COPY_C_ */ |