1/* 2 * Copyright (c) 2002 Andi Kleen <ak@suse.de> 3 * Copyright (c) 2002 Michal Ludvig <mludvig@suse.cz> 4 * Copyright (c) 2002 Roland McGrath <roland@redhat.com> 5 * Copyright (c) 2008-2013 Denys Vlasenko <vda.linux@googlemail.com> 6 * Copyright (c) 2012 H.J. Lu <hongjiu.lu@intel.com> 7 * Copyright (c) 2010-2015 Dmitry V. Levin <ldv@altlinux.org> 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#ifdef X86_64 34# define X32_PERSONALITY_NUMBER 2 35#else 36# define X32_PERSONALITY_NUMBER 0 37#endif 38 39/* Return codes: 1 - ok, 0 - ignore, other - error. */ 40static int 41arch_get_scno(struct tcb *tcp) 42{ 43 kernel_ulong_t scno = 0; 44 unsigned int currpers; 45 46#ifndef __X32_SYSCALL_BIT 47# define __X32_SYSCALL_BIT 0x40000000 48#endif 49 50#if 1 51 /* 52 * GETREGSET of NT_PRSTATUS tells us regset size, 53 * which unambiguously detects i386. 54 * 55 * Linux kernel distinguishes x86-64 and x32 processes 56 * solely by looking at __X32_SYSCALL_BIT: 57 * arch/x86/include/asm/compat.h::is_x32_task(): 58 * if (task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT) 59 * return true; 60 */ 61 if (x86_io.iov_len == sizeof(i386_regs)) { 62 scno = i386_regs.orig_eax; 63 currpers = 1; 64 } else { 65 scno = x86_64_regs.orig_rax; 66 currpers = 0; 67 if (scno & __X32_SYSCALL_BIT) { 68 /* 69 * Syscall number -1 requires special treatment: 70 * it might be a side effect of SECCOMP_RET_ERRNO 71 * filtering that sets orig_rax to -1 72 * in some versions of linux kernel. 73 * If that is the case, then 74 * __X32_SYSCALL_BIT logic does not apply. 75 */ 76 if ((long long) x86_64_regs.orig_rax != -1) { 77 scno -= __X32_SYSCALL_BIT; 78 currpers = 2; 79 } else { 80# ifdef X32 81 currpers = 2; 82# endif 83 } 84 } 85 } 86 87#elif 0 88 /* 89 * cs = 0x33 for long mode (native 64 bit and x32) 90 * cs = 0x23 for compatibility mode (32 bit) 91 * ds = 0x2b for x32 mode (x86-64 in 32 bit) 92 */ 93 scno = x86_64_regs.orig_rax; 94 switch (x86_64_regs.cs) { 95 case 0x23: currpers = 1; break; 96 case 0x33: 97 if (x86_64_regs.ds == 0x2b) { 98 currpers = 2; 99 scno &= ~__X32_SYSCALL_BIT; 100 } else 101 currpers = 0; 102 break; 103 default: 104 error_msg("Unknown value CS=0x%08X while " 105 "detecting personality of process PID=%d", 106 (int)x86_64_regs.cs, tcp->pid); 107 currpers = current_personality; 108 break; 109 } 110#elif 0 111 /* 112 * This version analyzes the opcode of a syscall instruction. 113 * (int 0x80 on i386 vs. syscall on x86-64) 114 * It works, but is too complicated, and strictly speaking, unreliable. 115 */ 116 unsigned long call, rip = x86_64_regs.rip; 117 /* sizeof(syscall) == sizeof(int 0x80) == 2 */ 118 rip -= 2; 119 errno = 0; 120 call = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)rip, (char *)0); 121 if (errno) 122 perror_msg("ptrace_peektext failed"); 123 switch (call & 0xffff) { 124 /* x86-64: syscall = 0x0f 0x05 */ 125 case 0x050f: currpers = 0; break; 126 /* i386: int 0x80 = 0xcd 0x80 */ 127 case 0x80cd: currpers = 1; break; 128 default: 129 currpers = current_personality; 130 error_msg("Unknown syscall opcode (0x%04X) while " 131 "detecting personality of process PID=%d", 132 (int)call, tcp->pid); 133 break; 134 } 135#endif 136 137#ifdef X32 138 /* 139 * If we are built for a x32 system, then personality 0 is x32 140 * (not x86_64), and stracing of x86_64 apps is not supported. 141 * Stracing of i386 apps is still supported. 142 */ 143 if (currpers == 0) { 144 error_msg("syscall_%" PRI_klu "(...) in unsupported " 145 "64-bit mode of process PID=%d", scno, tcp->pid); 146 return 0; 147 } 148 currpers &= ~2; /* map 2,1 to 0,1 */ 149#endif /* X32 */ 150 151 update_personality(tcp, currpers); 152 tcp->scno = scno; 153 return 1; 154} 155