ptrace32.c 9.5 KB
Newer Older
1
/*
L
Linus Torvalds 已提交
2 3 4
 * 32bit ptrace for x86-64.
 *
 * Copyright 2001,2002 Andi Kleen, SuSE Labs.
5
 * Some parts copied from arch/i386/kernel/ptrace.c. See that file for earlier
L
Linus Torvalds 已提交
6
 * copyright.
7 8 9 10
 *
 * This allows to access 64bit processes too; but there is no way to
 * see the extended register contents.
 */
L
Linus Torvalds 已提交
11 12 13 14 15 16 17

#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/syscalls.h>
#include <linux/unistd.h>
#include <linux/mm.h>
A
Alexey Dobriyan 已提交
18
#include <linux/err.h>
L
Linus Torvalds 已提交
19 20 21 22 23 24 25 26 27 28
#include <linux/ptrace.h>
#include <asm/ptrace.h>
#include <asm/compat.h>
#include <asm/uaccess.h>
#include <asm/user32.h>
#include <asm/user.h>
#include <asm/errno.h>
#include <asm/debugreg.h>
#include <asm/i387.h>
#include <asm/fpu32.h>
29
#include <asm/ia32.h>
L
Linus Torvalds 已提交
30

31 32 33 34 35 36
/*
 * Determines which flags the user has access to [1 = access, 0 = no access].
 * Prohibits changing ID(21), VIP(20), VIF(19), VM(17), IOPL(12-13), IF(9).
 * Also masks reserved bits (31-22, 15, 5, 3, 1).
 */
#define FLAG_MASK 0x54dd5UL
L
Linus Torvalds 已提交
37

38 39 40
#define R32(l,q)							\
	case offsetof(struct user32, regs.l):				\
		stack[offsetof(struct pt_regs, q) / 8] = val; break
L
Linus Torvalds 已提交
41 42 43 44

static int putreg32(struct task_struct *child, unsigned regno, u32 val)
{
	int i;
A
Al Viro 已提交
45
	__u64 *stack = (__u64 *)task_pt_regs(child);
L
Linus Torvalds 已提交
46 47 48

	switch (regno) {
	case offsetof(struct user32, regs.fs):
49 50
		if (val && (val & 3) != 3)
			return -EIO;
51
		child->thread.fsindex = val & 0xffff;
L
Linus Torvalds 已提交
52 53
		break;
	case offsetof(struct user32, regs.gs):
54 55
		if (val && (val & 3) != 3)
			return -EIO;
56
		child->thread.gsindex = val & 0xffff;
L
Linus Torvalds 已提交
57 58
		break;
	case offsetof(struct user32, regs.ds):
59 60
		if (val && (val & 3) != 3)
			return -EIO;
L
Linus Torvalds 已提交
61 62 63 64 65
		child->thread.ds = val & 0xffff;
		break;
	case offsetof(struct user32, regs.es):
		child->thread.es = val & 0xffff;
		break;
66 67 68 69
	case offsetof(struct user32, regs.ss):
		if ((val & 3) != 3)
			return -EIO;
		stack[offsetof(struct pt_regs, ss)/8] = val & 0xffff;
L
Linus Torvalds 已提交
70
		break;
71 72 73
	case offsetof(struct user32, regs.cs):
		if ((val & 3) != 3)
			return -EIO;
L
Linus Torvalds 已提交
74 75 76
		stack[offsetof(struct pt_regs, cs)/8] = val & 0xffff;
		break;

77
	R32(ebx, rbx);
L
Linus Torvalds 已提交
78 79 80 81 82 83 84 85 86 87 88 89
	R32(ecx, rcx);
	R32(edx, rdx);
	R32(edi, rdi);
	R32(esi, rsi);
	R32(ebp, rbp);
	R32(eax, rax);
	R32(orig_eax, orig_rax);
	R32(eip, rip);
	R32(esp, rsp);

	case offsetof(struct user32, regs.eflags): {
		__u64 *flags = &stack[offsetof(struct pt_regs, eflags)/8];
90

L
Linus Torvalds 已提交
91 92 93 94 95
		val &= FLAG_MASK;
		*flags = val | (*flags & ~FLAG_MASK);
		break;
	}

96
	case offsetof(struct user32, u_debugreg[4]):
L
Linus Torvalds 已提交
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
	case offsetof(struct user32, u_debugreg[5]):
		return -EIO;

	case offsetof(struct user32, u_debugreg[0]):
		child->thread.debugreg0 = val;
		break;

	case offsetof(struct user32, u_debugreg[1]):
		child->thread.debugreg1 = val;
		break;

	case offsetof(struct user32, u_debugreg[2]):
		child->thread.debugreg2 = val;
		break;

	case offsetof(struct user32, u_debugreg[3]):
		child->thread.debugreg3 = val;
		break;

	case offsetof(struct user32, u_debugreg[6]):
		child->thread.debugreg6 = val;
118
		break;
L
Linus Torvalds 已提交
119 120 121 122 123

	case offsetof(struct user32, u_debugreg[7]):
		val &= ~DR_CONTROL_RESERVED;
		/* See arch/i386/kernel/ptrace.c for an explanation of
		 * this awkward check.*/
124
		for (i = 0; i < 4; i++)
L
Linus Torvalds 已提交
125 126
			if ((0x5454 >> ((val >> (16 + 4*i)) & 0xf)) & 1)
			       return -EIO;
127
		child->thread.debugreg7 = val;
128 129 130 131
		if (val)
			set_tsk_thread_flag(child, TIF_DEBUG);
		else
			clear_tsk_thread_flag(child, TIF_DEBUG);
132 133
		break;

L
Linus Torvalds 已提交
134 135 136
	default:
		if (regno > sizeof(struct user32) || (regno & 3))
			return -EIO;
137 138 139 140 141 142

		/*
		 * Other dummy fields in the virtual user structure
		 * are ignored
		 */
		break;
L
Linus Torvalds 已提交
143 144 145 146 147 148
	}
	return 0;
}

#undef R32

149 150 151
#define R32(l,q)							\
	case offsetof(struct user32, regs.l):				\
		*val = stack[offsetof(struct pt_regs, q)/8]; break
L
Linus Torvalds 已提交
152 153 154

static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
{
A
Al Viro 已提交
155
	__u64 *stack = (__u64 *)task_pt_regs(child);
L
Linus Torvalds 已提交
156 157 158

	switch (regno) {
	case offsetof(struct user32, regs.fs):
159
		*val = child->thread.fsindex;
L
Linus Torvalds 已提交
160 161
		break;
	case offsetof(struct user32, regs.gs):
162
		*val = child->thread.gsindex;
L
Linus Torvalds 已提交
163 164 165 166 167 168 169 170 171 172
		break;
	case offsetof(struct user32, regs.ds):
		*val = child->thread.ds;
		break;
	case offsetof(struct user32, regs.es):
		*val = child->thread.es;
		break;

	R32(cs, cs);
	R32(ss, ss);
173
	R32(ebx, rbx);
L
Linus Torvalds 已提交
174 175 176 177 178 179 180 181 182 183 184
	R32(ecx, rcx);
	R32(edx, rdx);
	R32(edi, rdi);
	R32(esi, rsi);
	R32(ebp, rbp);
	R32(eax, rax);
	R32(orig_eax, orig_rax);
	R32(eip, rip);
	R32(eflags, eflags);
	R32(esp, rsp);

185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
	case offsetof(struct user32, u_debugreg[0]):
		*val = child->thread.debugreg0;
		break;
	case offsetof(struct user32, u_debugreg[1]):
		*val = child->thread.debugreg1;
		break;
	case offsetof(struct user32, u_debugreg[2]):
		*val = child->thread.debugreg2;
		break;
	case offsetof(struct user32, u_debugreg[3]):
		*val = child->thread.debugreg3;
		break;
	case offsetof(struct user32, u_debugreg[6]):
		*val = child->thread.debugreg6;
		break;
	case offsetof(struct user32, u_debugreg[7]):
		*val = child->thread.debugreg7;
		break;

L
Linus Torvalds 已提交
204 205 206 207
	default:
		if (regno > sizeof(struct user32) || (regno & 3))
			return -EIO;

208 209 210 211
		/*
		 * Other dummy fields in the virtual user structure
		 * are ignored
		 */
L
Linus Torvalds 已提交
212
		*val = 0;
213
		break;
L
Linus Torvalds 已提交
214 215 216 217 218 219
	}
	return 0;
}

#undef R32

220 221
static long ptrace32_siginfo(unsigned request, u32 pid, u32 addr, u32 data)
{
222
	siginfo_t __user *si = compat_alloc_user_space(sizeof(siginfo_t));
223 224 225 226
	compat_siginfo_t __user *si32 = compat_ptr(data);
	siginfo_t ssi;
	int ret;

227
	if (request == PTRACE_SETSIGINFO) {
228 229
		memset(&ssi, 0, sizeof(siginfo_t));
		ret = copy_siginfo_from_user32(&ssi, si32);
230 231
		if (ret)
			return ret;
232 233
		if (copy_to_user(si, &ssi, sizeof(siginfo_t)))
			return -EFAULT;
234 235 236 237
	}
	ret = sys_ptrace(request, pid, addr, (unsigned long)si);
	if (ret)
		return ret;
238 239 240 241 242
	if (request == PTRACE_GETSIGINFO) {
		if (copy_from_user(&ssi, si, sizeof(siginfo_t)))
			return -EFAULT;
		ret = copy_siginfo_to_user32(si32, &ssi);
	}
243 244 245
	return ret;
}

L
Linus Torvalds 已提交
246 247 248
asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
{
	struct task_struct *child;
249
	struct pt_regs *childregs;
L
Linus Torvalds 已提交
250 251 252 253
	void __user *datap = compat_ptr(data);
	int ret;
	__u32 val;

254
	switch (request) {
255 256 257 258 259 260 261
	case PTRACE_TRACEME:
	case PTRACE_ATTACH:
	case PTRACE_KILL:
	case PTRACE_CONT:
	case PTRACE_SINGLESTEP:
	case PTRACE_DETACH:
	case PTRACE_SYSCALL:
262
	case PTRACE_OLDSETOPTIONS:
263
	case PTRACE_SETOPTIONS:
264 265
	case PTRACE_SET_THREAD_AREA:
	case PTRACE_GET_THREAD_AREA:
266
		return sys_ptrace(request, pid, addr, data);
L
Linus Torvalds 已提交
267

268 269 270
	default:
		return -EINVAL;

L
Linus Torvalds 已提交
271 272 273 274
	case PTRACE_PEEKTEXT:
	case PTRACE_PEEKDATA:
	case PTRACE_POKEDATA:
	case PTRACE_POKETEXT:
275
	case PTRACE_POKEUSR:
L
Linus Torvalds 已提交
276 277 278 279 280 281 282 283 284 285
	case PTRACE_PEEKUSR:
	case PTRACE_GETREGS:
	case PTRACE_SETREGS:
	case PTRACE_SETFPREGS:
	case PTRACE_GETFPREGS:
	case PTRACE_SETFPXREGS:
	case PTRACE_GETFPXREGS:
	case PTRACE_GETEVENTMSG:
		break;

286 287 288 289
	case PTRACE_SETSIGINFO:
	case PTRACE_GETSIGINFO:
		return ptrace32_siginfo(request, pid, addr, data);
	}
290 291 292 293 294 295 296 297

	child = ptrace_get_task_struct(pid);
	if (IS_ERR(child))
		return PTR_ERR(child);

	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (ret < 0)
		goto out;
L
Linus Torvalds 已提交
298

A
Al Viro 已提交
299
	childregs = task_pt_regs(child);
L
Linus Torvalds 已提交
300 301 302 303 304

	switch (request) {
	case PTRACE_PEEKDATA:
	case PTRACE_PEEKTEXT:
		ret = 0;
305 306
		if (access_process_vm(child, addr, &val, sizeof(u32), 0) !=
		    sizeof(u32))
L
Linus Torvalds 已提交
307 308
			ret = -EIO;
		else
309 310
			ret = put_user(val, (unsigned int __user *)datap);
		break;
L
Linus Torvalds 已提交
311 312 313 314

	case PTRACE_POKEDATA:
	case PTRACE_POKETEXT:
		ret = 0;
315 316 317
		if (access_process_vm(child, addr, &data, sizeof(u32), 1) !=
		    sizeof(u32))
			ret = -EIO;
L
Linus Torvalds 已提交
318 319 320 321 322 323 324 325 326 327 328 329 330 331
		break;

	case PTRACE_PEEKUSR:
		ret = getreg32(child, addr, &val);
		if (ret == 0)
			ret = put_user(val, (__u32 __user *)datap);
		break;

	case PTRACE_POKEUSR:
		ret = putreg32(child, addr, data);
		break;

	case PTRACE_GETREGS: { /* Get all gp regs from the child. */
		int i;
332 333

		if (!access_ok(VERIFY_WRITE, datap, 16*4)) {
L
Linus Torvalds 已提交
334 335 336 337
			ret = -EIO;
			break;
		}
		ret = 0;
338
		for (i = 0; i <= 16*4; i += sizeof(__u32)) {
L
Linus Torvalds 已提交
339
			getreg32(child, i, &val);
340
			ret |= __put_user(val, (u32 __user *)datap);
L
Linus Torvalds 已提交
341 342 343 344 345 346 347 348
			datap += sizeof(u32);
		}
		break;
	}

	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
		unsigned long tmp;
		int i;
349 350

		if (!access_ok(VERIFY_READ, datap, 16*4)) {
L
Linus Torvalds 已提交
351 352 353
			ret = -EIO;
			break;
		}
354 355
		ret = 0;
		for (i = 0; i <= 16*4; i += sizeof(u32)) {
L
Linus Torvalds 已提交
356 357 358 359 360 361 362 363
			ret |= __get_user(tmp, (u32 __user *)datap);
			putreg32(child, i, tmp);
			datap += sizeof(u32);
		}
		break;
	}

	case PTRACE_GETFPREGS:
364 365
		ret = -EIO;
		if (!access_ok(VERIFY_READ, compat_ptr(data),
L
Linus Torvalds 已提交
366 367 368
			       sizeof(struct user_i387_struct)))
			break;
		save_i387_ia32(child, datap, childregs, 1);
369
		ret = 0;
L
Linus Torvalds 已提交
370 371 372 373
			break;

	case PTRACE_SETFPREGS:
		ret = -EIO;
374
		if (!access_ok(VERIFY_WRITE, datap,
L
Linus Torvalds 已提交
375 376 377 378 379 380 381
			       sizeof(struct user_i387_struct)))
			break;
		ret = 0;
		/* don't check EFAULT to be bug-to-bug compatible to i386 */
		restore_i387_ia32(child, datap, 1);
		break;

382
	case PTRACE_GETFPXREGS: {
L
Linus Torvalds 已提交
383
		struct user32_fxsr_struct __user *u = datap;
384 385

		init_fpu(child);
L
Linus Torvalds 已提交
386 387 388 389 390 391 392
		ret = -EIO;
		if (!access_ok(VERIFY_WRITE, u, sizeof(*u)))
			break;
			ret = -EFAULT;
		if (__copy_to_user(u, &child->thread.i387.fxsave, sizeof(*u)))
			break;
		ret = __put_user(childregs->cs, &u->fcs);
393 394 395 396
		ret |= __put_user(child->thread.ds, &u->fos);
		break;
	}
	case PTRACE_SETFPXREGS: {
L
Linus Torvalds 已提交
397
		struct user32_fxsr_struct __user *u = datap;
398

L
Linus Torvalds 已提交
399 400 401 402
		unlazy_fpu(child);
		ret = -EIO;
		if (!access_ok(VERIFY_READ, u, sizeof(*u)))
			break;
403 404 405 406
		/*
		 * no checking to be bug-to-bug compatible with i386.
		 * but silence warning
		 */
407 408
		if (__copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u)))
			;
L
Linus Torvalds 已提交
409 410
		set_stopped_child_used_math(child);
		child->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask;
411
		ret = 0;
L
Linus Torvalds 已提交
412 413 414 415
		break;
	}

	case PTRACE_GETEVENTMSG:
416 417
		ret = put_user(child->ptrace_message,
			       (unsigned int __user *)compat_ptr(data));
L
Linus Torvalds 已提交
418 419 420
		break;

	default:
421
		BUG();
L
Linus Torvalds 已提交
422 423
	}

424
 out:
L
Linus Torvalds 已提交
425 426 427 428
	put_task_struct(child);
	return ret;
}
反馈
建议
客服 返回
顶部