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