aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/ptrace.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-04-09 22:39:25 -0400
committerDavid S. Miller <davem@davemloft.net>2008-04-09 22:39:25 -0400
commitd786a4a6599740eaa4b8d1e1d466853f02db11d4 (patch)
tree98157e4dc5c6b246ac56d95a6a16baccd86b6df7 /arch/sparc64/kernel/ptrace.c
parentad4f95764040077f16ebf24559d5a06f8fb133bc (diff)
[SPARC]: Fix several regset and ptrace bugs.
1) ptrace should pass 'current' to task_user_regset_view() 2) When fetching general registers using a 64-bit view, and the target is 32-bit, we have to convert. 3) Skip the whole register window get/set code block if the user isn't asking to access anything in there. Otherwise we have problems if the user doesn't have an address space setup. Fetching ptrace register is still valid at such a time, and ptrace does not try to access the register window area of the regset. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/ptrace.c')
-rw-r--r--arch/sparc64/kernel/ptrace.c148
1 files changed, 97 insertions, 51 deletions
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index 7963595c77cc..e9fc0aa2da38 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -114,6 +114,85 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
114 preempt_enable(); 114 preempt_enable();
115} 115}
116 116
117static int get_from_target(struct task_struct *target, unsigned long uaddr,
118 void *kbuf, int len)
119{
120 if (target == current) {
121 if (copy_from_user(kbuf, (void __user *) uaddr, len))
122 return -EFAULT;
123 } else {
124 int len2 = access_process_vm(target, uaddr, kbuf, len, 0);
125 if (len2 != len)
126 return -EFAULT;
127 }
128 return 0;
129}
130
131static int set_to_target(struct task_struct *target, unsigned long uaddr,
132 void *kbuf, int len)
133{
134 if (target == current) {
135 if (copy_to_user((void __user *) uaddr, kbuf, len))
136 return -EFAULT;
137 } else {
138 int len2 = access_process_vm(target, uaddr, kbuf, len, 1);
139 if (len2 != len)
140 return -EFAULT;
141 }
142 return 0;
143}
144
145static int regwindow64_get(struct task_struct *target,
146 const struct pt_regs *regs,
147 struct reg_window *wbuf)
148{
149 unsigned long rw_addr = regs->u_regs[UREG_I6];
150
151 if (test_tsk_thread_flag(current, TIF_32BIT)) {
152 struct reg_window32 win32;
153 int i;
154
155 if (get_from_target(target, rw_addr, &win32, sizeof(win32)))
156 return -EFAULT;
157 for (i = 0; i < 8; i++)
158 wbuf->locals[i] = win32.locals[i];
159 for (i = 0; i < 8; i++)
160 wbuf->ins[i] = win32.ins[i];
161 } else {
162 rw_addr += STACK_BIAS;
163 if (get_from_target(target, rw_addr, wbuf, sizeof(*wbuf)))
164 return -EFAULT;
165 }
166
167 return 0;
168}
169
170static int regwindow64_set(struct task_struct *target,
171 const struct pt_regs *regs,
172 struct reg_window *wbuf)
173{
174 unsigned long rw_addr = regs->u_regs[UREG_I6];
175
176 if (test_tsk_thread_flag(current, TIF_32BIT)) {
177 struct reg_window32 win32;
178 int i;
179
180 for (i = 0; i < 8; i++)
181 win32.locals[i] = wbuf->locals[i];
182 for (i = 0; i < 8; i++)
183 win32.ins[i] = wbuf->ins[i];
184
185 if (set_to_target(target, rw_addr, &win32, sizeof(win32)))
186 return -EFAULT;
187 } else {
188 rw_addr += STACK_BIAS;
189 if (set_to_target(target, rw_addr, wbuf, sizeof(*wbuf)))
190 return -EFAULT;
191 }
192
193 return 0;
194}
195
117enum sparc_regset { 196enum sparc_regset {
118 REGSET_GENERAL, 197 REGSET_GENERAL,
119 REGSET_FP, 198 REGSET_FP,
@@ -133,25 +212,13 @@ static int genregs64_get(struct task_struct *target,
133 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, 212 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
134 regs->u_regs, 213 regs->u_regs,
135 0, 16 * sizeof(u64)); 214 0, 16 * sizeof(u64));
136 if (!ret) { 215 if (!ret && count && pos < (32 * sizeof(u64))) {
137 unsigned long __user *reg_window = (unsigned long __user *) 216 struct reg_window window;
138 (regs->u_regs[UREG_I6] + STACK_BIAS);
139 unsigned long window[16];
140
141 if (target == current) {
142 if (copy_from_user(window, reg_window, sizeof(window)))
143 return -EFAULT;
144 } else {
145 if (access_process_vm(target,
146 (unsigned long) reg_window,
147 window,
148 sizeof(window), 0) !=
149 sizeof(window))
150 return -EFAULT;
151 }
152 217
218 if (regwindow64_get(target, regs, &window))
219 return -EFAULT;
153 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, 220 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
154 window, 221 &window,
155 16 * sizeof(u64), 222 16 * sizeof(u64),
156 32 * sizeof(u64)); 223 32 * sizeof(u64));
157 } 224 }
@@ -173,10 +240,11 @@ static int genregs64_get(struct task_struct *target,
173 36 * sizeof(u64)); 240 36 * sizeof(u64));
174 } 241 }
175 242
176 if (!ret) 243 if (!ret) {
177 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 244 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
178 36 * sizeof(u64), -1); 245 36 * sizeof(u64), -1);
179 246
247 }
180 return ret; 248 return ret;
181} 249}
182 250
@@ -194,42 +262,20 @@ static int genregs64_set(struct task_struct *target,
194 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 262 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
195 regs->u_regs, 263 regs->u_regs,
196 0, 16 * sizeof(u64)); 264 0, 16 * sizeof(u64));
197 if (!ret && count > 0) { 265 if (!ret && count && pos < (32 * sizeof(u64))) {
198 unsigned long __user *reg_window = (unsigned long __user *) 266 struct reg_window window;
199 (regs->u_regs[UREG_I6] + STACK_BIAS);
200 unsigned long window[16];
201 267
202 if (target == current) { 268 if (regwindow64_get(target, regs, &window))
203 if (copy_from_user(window, reg_window, sizeof(window))) 269 return -EFAULT;
204 return -EFAULT;
205 } else {
206 if (access_process_vm(target,
207 (unsigned long) reg_window,
208 window,
209 sizeof(window), 0) !=
210 sizeof(window))
211 return -EFAULT;
212 }
213 270
214 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 271 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
215 window, 272 &window,
216 16 * sizeof(u64), 273 16 * sizeof(u64),
217 32 * sizeof(u64)); 274 32 * sizeof(u64));
218 if (!ret) { 275
219 if (target == current) { 276 if (!ret &&
220 if (copy_to_user(reg_window, window, 277 regwindow64_set(target, regs, &window))
221 sizeof(window))) 278 return -EFAULT;
222 return -EFAULT;
223 } else {
224 if (access_process_vm(target,
225 (unsigned long)
226 reg_window,
227 window,
228 sizeof(window), 1) !=
229 sizeof(window))
230 return -EFAULT;
231 }
232 }
233 } 279 }
234 280
235 if (!ret && count > 0) { 281 if (!ret && count > 0) {
@@ -805,7 +851,7 @@ struct compat_fps {
805long compat_arch_ptrace(struct task_struct *child, compat_long_t request, 851long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
806 compat_ulong_t caddr, compat_ulong_t cdata) 852 compat_ulong_t caddr, compat_ulong_t cdata)
807{ 853{
808 const struct user_regset_view *view = task_user_regset_view(child); 854 const struct user_regset_view *view = task_user_regset_view(current);
809 compat_ulong_t caddr2 = task_pt_regs(current)->u_regs[UREG_I4]; 855 compat_ulong_t caddr2 = task_pt_regs(current)->u_regs[UREG_I4];
810 struct pt_regs32 __user *pregs; 856 struct pt_regs32 __user *pregs;
811 struct compat_fps __user *fps; 857 struct compat_fps __user *fps;
@@ -913,7 +959,7 @@ struct fps {
913 959
914long arch_ptrace(struct task_struct *child, long request, long addr, long data) 960long arch_ptrace(struct task_struct *child, long request, long addr, long data)
915{ 961{
916 const struct user_regset_view *view = task_user_regset_view(child); 962 const struct user_regset_view *view = task_user_regset_view(current);
917 unsigned long addr2 = task_pt_regs(current)->u_regs[UREG_I4]; 963 unsigned long addr2 = task_pt_regs(current)->u_regs[UREG_I4];
918 struct pt_regs __user *pregs; 964 struct pt_regs __user *pregs;
919 struct fps __user *fps; 965 struct fps __user *fps;