• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * SuperH process tracing
3  *
4  * Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka
5  * Copyright (C) 2002 - 2008  Paul Mundt
6  *
7  * Audit support by Yuichi Nakamura <ynakam@hitachisoft.jp>
8  *
9  * This file is subject to the terms and conditions of the GNU General Public
10  * License.  See the file "COPYING" in the main directory of this archive
11  * for more details.
12  */
13 #include <linux/kernel.h>
14 #include <linux/sched.h>
15 #include <linux/mm.h>
16 #include <linux/smp.h>
17 #include <linux/errno.h>
18 #include <linux/ptrace.h>
19 #include <linux/user.h>
20 #include <linux/slab.h>
21 #include <linux/security.h>
22 #include <linux/signal.h>
23 #include <linux/io.h>
24 #include <linux/audit.h>
25 #include <linux/seccomp.h>
26 #include <linux/tracehook.h>
27 #include <linux/elf.h>
28 #include <linux/regset.h>
29 #include <asm/uaccess.h>
30 #include <asm/pgtable.h>
31 #include <asm/system.h>
32 #include <asm/processor.h>
33 #include <asm/mmu_context.h>
34 #include <asm/syscalls.h>
35 #include <asm/fpu.h>
36 
37 /*
38  * This routine will get a word off of the process kernel stack.
39  */
get_stack_long(struct task_struct * task,int offset)40 static inline int get_stack_long(struct task_struct *task, int offset)
41 {
42 	unsigned char *stack;
43 
44 	stack = (unsigned char *)task_pt_regs(task);
45 	stack += offset;
46 	return (*((int *)stack));
47 }
48 
49 /*
50  * This routine will put a word on the process kernel stack.
51  */
put_stack_long(struct task_struct * task,int offset,unsigned long data)52 static inline int put_stack_long(struct task_struct *task, int offset,
53 				 unsigned long data)
54 {
55 	unsigned char *stack;
56 
57 	stack = (unsigned char *)task_pt_regs(task);
58 	stack += offset;
59 	*(unsigned long *) stack = data;
60 	return 0;
61 }
62 
user_enable_single_step(struct task_struct * child)63 void user_enable_single_step(struct task_struct *child)
64 {
65 	/* Next scheduling will set up UBC */
66 	if (child->thread.ubc_pc == 0)
67 		ubc_usercnt += 1;
68 
69 	child->thread.ubc_pc = get_stack_long(child,
70 				offsetof(struct pt_regs, pc));
71 
72 	set_tsk_thread_flag(child, TIF_SINGLESTEP);
73 }
74 
user_disable_single_step(struct task_struct * child)75 void user_disable_single_step(struct task_struct *child)
76 {
77 	clear_tsk_thread_flag(child, TIF_SINGLESTEP);
78 
79 	/*
80 	 * Ensure the UBC is not programmed at the next context switch.
81 	 *
82 	 * Normally this is not needed but there are sequences such as
83 	 * singlestep, signal delivery, and continue that leave the
84 	 * ubc_pc non-zero leading to spurious SIGTRAPs.
85 	 */
86 	if (child->thread.ubc_pc != 0) {
87 		ubc_usercnt -= 1;
88 		child->thread.ubc_pc = 0;
89 	}
90 }
91 
92 /*
93  * Called by kernel/ptrace.c when detaching..
94  *
95  * Make sure single step bits etc are not set.
96  */
ptrace_disable(struct task_struct * child)97 void ptrace_disable(struct task_struct *child)
98 {
99 	user_disable_single_step(child);
100 }
101 
genregs_get(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,void * kbuf,void __user * ubuf)102 static int genregs_get(struct task_struct *target,
103 		       const struct user_regset *regset,
104 		       unsigned int pos, unsigned int count,
105 		       void *kbuf, void __user *ubuf)
106 {
107 	const struct pt_regs *regs = task_pt_regs(target);
108 	int ret;
109 
110 	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
111 				  regs->regs,
112 				  0, 16 * sizeof(unsigned long));
113 	if (!ret)
114 		/* PC, PR, SR, GBR, MACH, MACL, TRA */
115 		ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
116 					  &regs->pc,
117 					  offsetof(struct pt_regs, pc),
118 					  sizeof(struct pt_regs));
119 	if (!ret)
120 		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
121 					       sizeof(struct pt_regs), -1);
122 
123 	return ret;
124 }
125 
genregs_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)126 static int genregs_set(struct task_struct *target,
127 		       const struct user_regset *regset,
128 		       unsigned int pos, unsigned int count,
129 		       const void *kbuf, const void __user *ubuf)
130 {
131 	struct pt_regs *regs = task_pt_regs(target);
132 	int ret;
133 
134 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
135 				 regs->regs,
136 				 0, 16 * sizeof(unsigned long));
137 	if (!ret && count > 0)
138 		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
139 					 &regs->pc,
140 					 offsetof(struct pt_regs, pc),
141 					 sizeof(struct pt_regs));
142 	if (!ret)
143 		ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
144 						sizeof(struct pt_regs), -1);
145 
146 	return ret;
147 }
148 
149 #ifdef CONFIG_SH_FPU
fpregs_get(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,void * kbuf,void __user * ubuf)150 int fpregs_get(struct task_struct *target,
151 	       const struct user_regset *regset,
152 	       unsigned int pos, unsigned int count,
153 	       void *kbuf, void __user *ubuf)
154 {
155 	int ret;
156 
157 	ret = init_fpu(target);
158 	if (ret)
159 		return ret;
160 
161 	if ((boot_cpu_data.flags & CPU_HAS_FPU))
162 		return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
163 					   &target->thread.fpu.hard, 0, -1);
164 
165 	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
166 				   &target->thread.fpu.soft, 0, -1);
167 }
168 
fpregs_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)169 static int fpregs_set(struct task_struct *target,
170 		       const struct user_regset *regset,
171 		       unsigned int pos, unsigned int count,
172 		       const void *kbuf, const void __user *ubuf)
173 {
174 	int ret;
175 
176 	ret = init_fpu(target);
177 	if (ret)
178 		return ret;
179 
180 	set_stopped_child_used_math(target);
181 
182 	if ((boot_cpu_data.flags & CPU_HAS_FPU))
183 		return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
184 					  &target->thread.fpu.hard, 0, -1);
185 
186 	return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
187 				  &target->thread.fpu.soft, 0, -1);
188 }
189 
fpregs_active(struct task_struct * target,const struct user_regset * regset)190 static int fpregs_active(struct task_struct *target,
191 			 const struct user_regset *regset)
192 {
193 	return tsk_used_math(target) ? regset->n : 0;
194 }
195 #endif
196 
197 #ifdef CONFIG_SH_DSP
dspregs_get(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,void * kbuf,void __user * ubuf)198 static int dspregs_get(struct task_struct *target,
199 		       const struct user_regset *regset,
200 		       unsigned int pos, unsigned int count,
201 		       void *kbuf, void __user *ubuf)
202 {
203 	const struct pt_dspregs *regs = task_pt_dspregs(target);
204 	int ret;
205 
206 	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs,
207 				  0, sizeof(struct pt_dspregs));
208 	if (!ret)
209 		ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
210 					       sizeof(struct pt_dspregs), -1);
211 
212 	return ret;
213 }
214 
dspregs_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)215 static int dspregs_set(struct task_struct *target,
216 		       const struct user_regset *regset,
217 		       unsigned int pos, unsigned int count,
218 		       const void *kbuf, const void __user *ubuf)
219 {
220 	struct pt_dspregs *regs = task_pt_dspregs(target);
221 	int ret;
222 
223 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, regs,
224 				 0, sizeof(struct pt_dspregs));
225 	if (!ret)
226 		ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
227 						sizeof(struct pt_dspregs), -1);
228 
229 	return ret;
230 }
231 
dspregs_active(struct task_struct * target,const struct user_regset * regset)232 static int dspregs_active(struct task_struct *target,
233 			  const struct user_regset *regset)
234 {
235 	struct pt_regs *regs = task_pt_regs(target);
236 
237 	return regs->sr & SR_DSP ? regset->n : 0;
238 }
239 #endif
240 
241 /*
242  * These are our native regset flavours.
243  */
244 enum sh_regset {
245 	REGSET_GENERAL,
246 #ifdef CONFIG_SH_FPU
247 	REGSET_FPU,
248 #endif
249 #ifdef CONFIG_SH_DSP
250 	REGSET_DSP,
251 #endif
252 };
253 
254 static const struct user_regset sh_regsets[] = {
255 	/*
256 	 * Format is:
257 	 *	R0 --> R15
258 	 *	PC, PR, SR, GBR, MACH, MACL, TRA
259 	 */
260 	[REGSET_GENERAL] = {
261 		.core_note_type	= NT_PRSTATUS,
262 		.n		= ELF_NGREG,
263 		.size		= sizeof(long),
264 		.align		= sizeof(long),
265 		.get		= genregs_get,
266 		.set		= genregs_set,
267 	},
268 
269 #ifdef CONFIG_SH_FPU
270 	[REGSET_FPU] = {
271 		.core_note_type	= NT_PRFPREG,
272 		.n		= sizeof(struct user_fpu_struct) / sizeof(long),
273 		.size		= sizeof(long),
274 		.align		= sizeof(long),
275 		.get		= fpregs_get,
276 		.set		= fpregs_set,
277 		.active		= fpregs_active,
278 	},
279 #endif
280 
281 #ifdef CONFIG_SH_DSP
282 	[REGSET_DSP] = {
283 		.n		= sizeof(struct pt_dspregs) / sizeof(long),
284 		.size		= sizeof(long),
285 		.align		= sizeof(long),
286 		.get		= dspregs_get,
287 		.set		= dspregs_set,
288 		.active		= dspregs_active,
289 	},
290 #endif
291 };
292 
293 static const struct user_regset_view user_sh_native_view = {
294 	.name		= "sh",
295 	.e_machine	= EM_SH,
296 	.regsets	= sh_regsets,
297 	.n		= ARRAY_SIZE(sh_regsets),
298 };
299 
task_user_regset_view(struct task_struct * task)300 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
301 {
302 	return &user_sh_native_view;
303 }
304 
arch_ptrace(struct task_struct * child,long request,long addr,long data)305 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
306 {
307 	struct user * dummy = NULL;
308 	unsigned long __user *datap = (unsigned long __user *)data;
309 	int ret;
310 
311 	switch (request) {
312 	/* read the word at location addr in the USER area. */
313 	case PTRACE_PEEKUSR: {
314 		unsigned long tmp;
315 
316 		ret = -EIO;
317 		if ((addr & 3) || addr < 0 ||
318 		    addr > sizeof(struct user) - 3)
319 			break;
320 
321 		if (addr < sizeof(struct pt_regs))
322 			tmp = get_stack_long(child, addr);
323 		else if (addr >= (long) &dummy->fpu &&
324 			 addr < (long) &dummy->u_fpvalid) {
325 			if (!tsk_used_math(child)) {
326 				if (addr == (long)&dummy->fpu.fpscr)
327 					tmp = FPSCR_INIT;
328 				else
329 					tmp = 0;
330 			} else
331 				tmp = ((long *)&child->thread.fpu)
332 					[(addr - (long)&dummy->fpu) >> 2];
333 		} else if (addr == (long) &dummy->u_fpvalid)
334 			tmp = !!tsk_used_math(child);
335 		else
336 			tmp = 0;
337 		ret = put_user(tmp, datap);
338 		break;
339 	}
340 
341 	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
342 		ret = -EIO;
343 		if ((addr & 3) || addr < 0 ||
344 		    addr > sizeof(struct user) - 3)
345 			break;
346 
347 		if (addr < sizeof(struct pt_regs))
348 			ret = put_stack_long(child, addr, data);
349 		else if (addr >= (long) &dummy->fpu &&
350 			 addr < (long) &dummy->u_fpvalid) {
351 			set_stopped_child_used_math(child);
352 			((long *)&child->thread.fpu)
353 				[(addr - (long)&dummy->fpu) >> 2] = data;
354 			ret = 0;
355 		} else if (addr == (long) &dummy->u_fpvalid) {
356 			conditional_stopped_child_used_math(data, child);
357 			ret = 0;
358 		}
359 		break;
360 
361 	case PTRACE_GETREGS:
362 		return copy_regset_to_user(child, &user_sh_native_view,
363 					   REGSET_GENERAL,
364 					   0, sizeof(struct pt_regs),
365 					   (void __user *)data);
366 	case PTRACE_SETREGS:
367 		return copy_regset_from_user(child, &user_sh_native_view,
368 					     REGSET_GENERAL,
369 					     0, sizeof(struct pt_regs),
370 					     (const void __user *)data);
371 #ifdef CONFIG_SH_FPU
372 	case PTRACE_GETFPREGS:
373 		return copy_regset_to_user(child, &user_sh_native_view,
374 					   REGSET_FPU,
375 					   0, sizeof(struct user_fpu_struct),
376 					   (void __user *)data);
377 	case PTRACE_SETFPREGS:
378 		return copy_regset_from_user(child, &user_sh_native_view,
379 					     REGSET_FPU,
380 					     0, sizeof(struct user_fpu_struct),
381 					     (const void __user *)data);
382 #endif
383 #ifdef CONFIG_SH_DSP
384 	case PTRACE_GETDSPREGS:
385 		return copy_regset_to_user(child, &user_sh_native_view,
386 					   REGSET_DSP,
387 					   0, sizeof(struct pt_dspregs),
388 					   (void __user *)data);
389 	case PTRACE_SETDSPREGS:
390 		return copy_regset_from_user(child, &user_sh_native_view,
391 					     REGSET_DSP,
392 					     0, sizeof(struct pt_dspregs),
393 					     (const void __user *)data);
394 #endif
395 #ifdef CONFIG_BINFMT_ELF_FDPIC
396 	case PTRACE_GETFDPIC: {
397 		unsigned long tmp = 0;
398 
399 		switch (addr) {
400 		case PTRACE_GETFDPIC_EXEC:
401 			tmp = child->mm->context.exec_fdpic_loadmap;
402 			break;
403 		case PTRACE_GETFDPIC_INTERP:
404 			tmp = child->mm->context.interp_fdpic_loadmap;
405 			break;
406 		default:
407 			break;
408 		}
409 
410 		ret = 0;
411 		if (put_user(tmp, datap)) {
412 			ret = -EFAULT;
413 			break;
414 		}
415 		break;
416 	}
417 #endif
418 	default:
419 		ret = ptrace_request(child, request, addr, data);
420 		break;
421 	}
422 
423 	return ret;
424 }
425 
audit_arch(void)426 static inline int audit_arch(void)
427 {
428 	int arch = EM_SH;
429 
430 #ifdef CONFIG_CPU_LITTLE_ENDIAN
431 	arch |= __AUDIT_ARCH_LE;
432 #endif
433 
434 	return arch;
435 }
436 
do_syscall_trace_enter(struct pt_regs * regs)437 asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
438 {
439 	long ret = 0;
440 
441 	secure_computing(regs->regs[0]);
442 
443 	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
444 	    tracehook_report_syscall_entry(regs))
445 		/*
446 		 * Tracing decided this syscall should not happen.
447 		 * We'll return a bogus call number to get an ENOSYS
448 		 * error, but leave the original number in regs->regs[0].
449 		 */
450 		ret = -1L;
451 
452 	if (unlikely(current->audit_context))
453 		audit_syscall_entry(audit_arch(), regs->regs[3],
454 				    regs->regs[4], regs->regs[5],
455 				    regs->regs[6], regs->regs[7]);
456 
457 	return ret ?: regs->regs[0];
458 }
459 
do_syscall_trace_leave(struct pt_regs * regs)460 asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
461 {
462 	int step;
463 
464 	if (unlikely(current->audit_context))
465 		audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]),
466 				   regs->regs[0]);
467 
468 	step = test_thread_flag(TIF_SINGLESTEP);
469 	if (step || test_thread_flag(TIF_SYSCALL_TRACE))
470 		tracehook_report_syscall_exit(regs, step);
471 }
472