Dmitry V. Levin | d70d1c4 | 2015-03-22 22:13:55 +0000 | [diff] [blame] | 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); |