1 #ifndef __X32_SYSCALL_BIT
2 # define __X32_SYSCALL_BIT	0x40000000
3 #endif
4 
5 unsigned 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  */
17 if (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  */
48 scno = x86_64_regs.orig_rax;
49 switch (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  */
70 unsigned long call, rip = x86_64_regs.rip;
71 /* sizeof(syscall) == sizeof(int 0x80) == 2 */
72 rip -= 2;
73 errno = 0;
74 call = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)rip, (char *)0);
75 if (errno)
76 	fprintf(stderr, "ptrace_peektext failed: %s\n",
77 			strerror(errno));
78 switch (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  */
98 if (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 }
104 currpers &= ~2; /* map 2,1 to 0,1 */
105 #endif /* X32 */
106 
107 update_personality(tcp, currpers);
108