blob: 2eb0d5d5a24fb67331bf47011d58d09450f5ba01 [file] [log] [blame]
Dmitry V. Levind70d1c42015-03-22 22:13:55 +00001#ifndef __X32_SYSCALL_BIT
2# define __X32_SYSCALL_BIT 0x40000000
3#endif
4
5unsigned int currpers;
6
7#if 1
8/* GETREGSET of NT_PRSTATUS tells us regset size,
9 * which unambiguously detects i386.
10 *
11 * Linux kernel distinguishes x86-64 and x32 processes
12 * solely by looking at __X32_SYSCALL_BIT:
13 * arch/x86/include/asm/compat.h::is_x32_task():
14 * if (task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT)
15 * return true;
16 */
17if (x86_io.iov_len == sizeof(i386_regs)) {
18 scno = i386_regs.orig_eax;
19 currpers = 1;
20} else {
21 scno = x86_64_regs.orig_rax;
22 currpers = 0;
23 if (scno & __X32_SYSCALL_BIT) {
24 /*
25 * Syscall number -1 requires special treatment:
26 * it might be a side effect of SECCOMP_RET_ERRNO
27 * filtering that sets orig_rax to -1
28 * in some versions of linux kernel.
29 * If that is the case, then
30 * __X32_SYSCALL_BIT logic does not apply.
31 */
32 if ((long long) x86_64_regs.orig_rax != -1) {
33 scno -= __X32_SYSCALL_BIT;
34 currpers = 2;
35 } else {
36# ifdef X32
37 currpers = 2;
38# endif
39 }
40 }
41}
42
43#elif 0
44/* cs = 0x33 for long mode (native 64 bit and x32)
45 * cs = 0x23 for compatibility mode (32 bit)
46 * ds = 0x2b for x32 mode (x86-64 in 32 bit)
47 */
48scno = x86_64_regs.orig_rax;
49switch (x86_64_regs.cs) {
50 case 0x23: currpers = 1; break;
51 case 0x33:
52 if (x86_64_regs.ds == 0x2b) {
53 currpers = 2;
54 scno &= ~__X32_SYSCALL_BIT;
55 } else
56 currpers = 0;
57 break;
58 default:
59 fprintf(stderr, "Unknown value CS=0x%08X while "
60 "detecting personality of process "
61 "PID=%d\n", (int)x86_64_regs.cs, tcp->pid);
62 currpers = current_personality;
63 break;
64}
65#elif 0
66/* This version analyzes the opcode of a syscall instruction.
67 * (int 0x80 on i386 vs. syscall on x86-64)
68 * It works, but is too complicated, and strictly speaking, unreliable.
69 */
70unsigned long call, rip = x86_64_regs.rip;
71/* sizeof(syscall) == sizeof(int 0x80) == 2 */
72rip -= 2;
73errno = 0;
74call = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)rip, (char *)0);
75if (errno)
76 fprintf(stderr, "ptrace_peektext failed: %s\n",
77 strerror(errno));
78switch (call & 0xffff) {
79 /* x86-64: syscall = 0x0f 0x05 */
80 case 0x050f: currpers = 0; break;
81 /* i386: int 0x80 = 0xcd 0x80 */
82 case 0x80cd: currpers = 1; break;
83 default:
84 currpers = current_personality;
85 fprintf(stderr,
86 "Unknown syscall opcode (0x%04X) while "
87 "detecting personality of process "
88 "PID=%d\n", (int)call, tcp->pid);
89 break;
90}
91#endif
92
93#ifdef X32
94/* If we are built for a x32 system, then personality 0 is x32
95 * (not x86_64), and stracing of x86_64 apps is not supported.
96 * Stracing of i386 apps is still supported.
97 */
98if (currpers == 0) {
99 fprintf(stderr, "syscall_%lu(...) in unsupported "
100 "64-bit mode of process PID=%d\n",
101 scno, tcp->pid);
102 return 0;
103}
104currpers &= ~2; /* map 2,1 to 0,1 */
105#endif /* X32 */
106
107update_personality(tcp, currpers);