1 /*- 2 * Copyright (c) 2004 Tim J. Robbins 3 * Copyright (c) 2002 Doug Rabson 4 * Copyright (c) 2000 Marcel Moolenaar 5 * All rights reserved. 6 * Copyright (c) 2013 Dmitry Chagin <dchagin@FreeBSD.org> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer 13 * in this position and unchanged. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/ktr.h> 35 #include <sys/lock.h> 36 #include <sys/mman.h> 37 #include <sys/mutex.h> 38 #include <sys/priv.h> 39 #include <sys/proc.h> 40 #include <sys/ptrace.h> 41 #include <sys/syscallsubr.h> 42 43 #include <machine/md_var.h> 44 #include <machine/pcb.h> 45 #include <machine/specialreg.h> 46 47 #include <vm/pmap.h> 48 #include <vm/vm.h> 49 #include <vm/vm_param.h> 50 51 #include <x86/ifunc.h> 52 #include <x86/reg.h> 53 #include <x86/sysarch.h> 54 55 #include <amd64/linux/linux.h> 56 #include <amd64/linux/linux_proto.h> 57 #include <compat/linux/linux_fork.h> 58 #include <compat/linux/linux_misc.h> 59 #include <compat/linux/linux_util.h> 60 61 #define LINUX_ARCH_AMD64 0xc000003e 62 63 int 64 linux_set_upcall(struct thread *td, register_t stack) 65 { 66 67 if (stack) 68 td->td_frame->tf_rsp = stack; 69 70 /* 71 * The newly created Linux thread returns 72 * to the user space by the same path that a parent does. 73 */ 74 td->td_frame->tf_rax = 0; 75 return (0); 76 } 77 78 int 79 linux_iopl(struct thread *td, struct linux_iopl_args *args) 80 { 81 int error; 82 83 LINUX_CTR(iopl); 84 85 if (args->level > 3) 86 return (EINVAL); 87 if ((error = priv_check(td, PRIV_IO)) != 0) 88 return (error); 89 if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 90 return (error); 91 td->td_frame->tf_rflags = (td->td_frame->tf_rflags & ~PSL_IOPL) | 92 (args->level * (PSL_IOPL / 3)); 93 94 return (0); 95 } 96 97 int 98 linux_pause(struct thread *td, struct linux_pause_args *args) 99 { 100 struct proc *p = td->td_proc; 101 sigset_t sigmask; 102 103 LINUX_CTR(pause); 104 105 PROC_LOCK(p); 106 sigmask = td->td_sigmask; 107 PROC_UNLOCK(p); 108 return (kern_sigsuspend(td, sigmask)); 109 } 110 111 int 112 linux_arch_prctl(struct thread *td, struct linux_arch_prctl_args *args) 113 { 114 unsigned long long cet[3]; 115 struct pcb *pcb; 116 int error; 117 118 pcb = td->td_pcb; 119 LINUX_CTR2(arch_prctl, "0x%x, %p", args->code, args->addr); 120 121 switch (args->code) { 122 case LINUX_ARCH_SET_GS: 123 if (args->addr < VM_MAXUSER_ADDRESS) { 124 update_pcb_bases(pcb); 125 pcb->pcb_gsbase = args->addr; 126 td->td_frame->tf_gs = _ugssel; 127 error = 0; 128 } else 129 error = EPERM; 130 break; 131 case LINUX_ARCH_SET_FS: 132 if (args->addr < VM_MAXUSER_ADDRESS) { 133 update_pcb_bases(pcb); 134 pcb->pcb_fsbase = args->addr; 135 td->td_frame->tf_fs = _ufssel; 136 error = 0; 137 } else 138 error = EPERM; 139 break; 140 case LINUX_ARCH_GET_FS: 141 error = copyout(&pcb->pcb_fsbase, PTRIN(args->addr), 142 sizeof(args->addr)); 143 break; 144 case LINUX_ARCH_GET_GS: 145 error = copyout(&pcb->pcb_gsbase, PTRIN(args->addr), 146 sizeof(args->addr)); 147 break; 148 case LINUX_ARCH_CET_STATUS: 149 memset(cet, 0, sizeof(cet)); 150 error = copyout(&cet, PTRIN(args->addr), sizeof(cet)); 151 break; 152 default: 153 linux_msg(td, "unsupported arch_prctl code %#x", args->code); 154 error = EINVAL; 155 } 156 return (error); 157 } 158 159 int 160 linux_set_cloned_tls(struct thread *td, void *desc) 161 { 162 struct pcb *pcb; 163 164 if ((uint64_t)desc >= VM_MAXUSER_ADDRESS) 165 return (EPERM); 166 167 pcb = td->td_pcb; 168 update_pcb_bases(pcb); 169 pcb->pcb_fsbase = (register_t)desc; 170 td->td_frame->tf_fs = _ufssel; 171 172 return (0); 173 } 174 175 int futex_xchgl_nosmap(int oparg, uint32_t *uaddr, int *oldval); 176 int futex_xchgl_smap(int oparg, uint32_t *uaddr, int *oldval); 177 DEFINE_IFUNC(, int, futex_xchgl, (int, uint32_t *, int *)) 178 { 179 180 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 181 futex_xchgl_smap : futex_xchgl_nosmap); 182 } 183 184 int futex_addl_nosmap(int oparg, uint32_t *uaddr, int *oldval); 185 int futex_addl_smap(int oparg, uint32_t *uaddr, int *oldval); 186 DEFINE_IFUNC(, int, futex_addl, (int, uint32_t *, int *)) 187 { 188 189 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 190 futex_addl_smap : futex_addl_nosmap); 191 } 192 193 int futex_orl_nosmap(int oparg, uint32_t *uaddr, int *oldval); 194 int futex_orl_smap(int oparg, uint32_t *uaddr, int *oldval); 195 DEFINE_IFUNC(, int, futex_orl, (int, uint32_t *, int *)) 196 { 197 198 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 199 futex_orl_smap : futex_orl_nosmap); 200 } 201 202 int futex_andl_nosmap(int oparg, uint32_t *uaddr, int *oldval); 203 int futex_andl_smap(int oparg, uint32_t *uaddr, int *oldval); 204 DEFINE_IFUNC(, int, futex_andl, (int, uint32_t *, int *)) 205 { 206 207 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 208 futex_andl_smap : futex_andl_nosmap); 209 } 210 211 int futex_xorl_nosmap(int oparg, uint32_t *uaddr, int *oldval); 212 int futex_xorl_smap(int oparg, uint32_t *uaddr, int *oldval); 213 DEFINE_IFUNC(, int, futex_xorl, (int, uint32_t *, int *)) 214 { 215 216 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 217 futex_xorl_smap : futex_xorl_nosmap); 218 } 219 220 void 221 bsd_to_linux_regset(const struct reg *b_reg, struct linux_pt_regset *l_regset) 222 { 223 224 l_regset->r15 = b_reg->r_r15; 225 l_regset->r14 = b_reg->r_r14; 226 l_regset->r13 = b_reg->r_r13; 227 l_regset->r12 = b_reg->r_r12; 228 l_regset->rbp = b_reg->r_rbp; 229 l_regset->rbx = b_reg->r_rbx; 230 l_regset->r11 = b_reg->r_r11; 231 l_regset->r10 = b_reg->r_r10; 232 l_regset->r9 = b_reg->r_r9; 233 l_regset->r8 = b_reg->r_r8; 234 l_regset->rax = b_reg->r_rax; 235 l_regset->rcx = b_reg->r_rcx; 236 l_regset->rdx = b_reg->r_rdx; 237 l_regset->rsi = b_reg->r_rsi; 238 l_regset->rdi = b_reg->r_rdi; 239 l_regset->orig_rax = b_reg->r_rax; 240 l_regset->rip = b_reg->r_rip; 241 l_regset->cs = b_reg->r_cs; 242 l_regset->eflags = b_reg->r_rflags; 243 l_regset->rsp = b_reg->r_rsp; 244 l_regset->ss = b_reg->r_ss; 245 l_regset->fs_base = 0; 246 l_regset->gs_base = 0; 247 l_regset->ds = b_reg->r_ds; 248 l_regset->es = b_reg->r_es; 249 l_regset->fs = b_reg->r_fs; 250 l_regset->gs = b_reg->r_gs; 251 } 252 253 void 254 linux_to_bsd_regset(struct reg *b_reg, const struct linux_pt_regset *l_regset) 255 { 256 257 b_reg->r_r15 = l_regset->r15; 258 b_reg->r_r14 = l_regset->r14; 259 b_reg->r_r13 = l_regset->r13; 260 b_reg->r_r12 = l_regset->r12; 261 b_reg->r_rbp = l_regset->rbp; 262 b_reg->r_rbx = l_regset->rbx; 263 b_reg->r_r11 = l_regset->r11; 264 b_reg->r_r10 = l_regset->r10; 265 b_reg->r_r9 = l_regset->r9; 266 b_reg->r_r8 = l_regset->r8; 267 b_reg->r_rax = l_regset->rax; 268 b_reg->r_rcx = l_regset->rcx; 269 b_reg->r_rdx = l_regset->rdx; 270 b_reg->r_rsi = l_regset->rsi; 271 b_reg->r_rdi = l_regset->rdi; 272 b_reg->r_rax = l_regset->orig_rax; 273 b_reg->r_rip = l_regset->rip; 274 b_reg->r_cs = l_regset->cs; 275 b_reg->r_rflags = l_regset->eflags; 276 b_reg->r_rsp = l_regset->rsp; 277 b_reg->r_ss = l_regset->ss; 278 b_reg->r_ds = l_regset->ds; 279 b_reg->r_es = l_regset->es; 280 b_reg->r_fs = l_regset->fs; 281 b_reg->r_gs = l_regset->gs; 282 } 283 284 void 285 linux_ptrace_get_syscall_info_machdep(const struct reg *reg, 286 struct syscall_info *si) 287 { 288 289 si->arch = LINUX_ARCH_AMD64; 290 si->instruction_pointer = reg->r_rip; 291 si->stack_pointer = reg->r_rsp; 292 } 293 294 int 295 linux_ptrace_getregs_machdep(struct thread *td, pid_t pid, 296 struct linux_pt_regset *l_regset) 297 { 298 struct ptrace_lwpinfo lwpinfo; 299 struct pcb *pcb; 300 int error; 301 302 pcb = td->td_pcb; 303 if (td == curthread) 304 update_pcb_bases(pcb); 305 306 l_regset->fs_base = pcb->pcb_fsbase; 307 l_regset->gs_base = pcb->pcb_gsbase; 308 309 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo)); 310 if (error != 0) { 311 linux_msg(td, "PT_LWPINFO failed with error %d", error); 312 return (error); 313 } 314 if ((lwpinfo.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)) != 0) { 315 /* 316 * In Linux, the syscall number - passed to the syscall 317 * as rax - is preserved in orig_rax; rax gets overwritten 318 * with syscall return value. 319 */ 320 l_regset->orig_rax = lwpinfo.pl_syscall_code; 321 } 322 323 return (0); 324 } 325 326 #define LINUX_URO(a,m) ((uintptr_t)a == offsetof(struct linux_pt_regset, m)) 327 328 int 329 linux_ptrace_peekuser(struct thread *td, pid_t pid, void *addr, void *data) 330 { 331 struct linux_pt_regset reg; 332 struct reg b_reg; 333 uint64_t val; 334 int error; 335 336 if ((uintptr_t)addr & (sizeof(data) -1) || (uintptr_t)addr < 0) 337 return (EIO); 338 if ((uintptr_t)addr >= sizeof(struct linux_pt_regset)) { 339 LINUX_RATELIMIT_MSG_OPT1("PTRACE_PEEKUSER offset %ld " 340 "not implemented; returning EINVAL", (uintptr_t)addr); 341 return (EINVAL); 342 } 343 344 if (LINUX_URO(addr, fs_base)) 345 return (kern_ptrace(td, PT_GETFSBASE, pid, data, 0)); 346 if (LINUX_URO(addr, gs_base)) 347 return (kern_ptrace(td, PT_GETGSBASE, pid, data, 0)); 348 if ((error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0)) != 0) 349 return (error); 350 bsd_to_linux_regset(&b_reg, ®); 351 val = *(®.r15 + ((uintptr_t)addr / sizeof(reg.r15))); 352 return (copyout(&val, data, sizeof(val))); 353 } 354 355 static inline bool 356 linux_invalid_selector(u_short val) 357 { 358 359 return (val != 0 && ISPL(val) != SEL_UPL); 360 } 361 362 struct linux_segreg_off { 363 uintptr_t reg; 364 bool is0; 365 }; 366 367 const struct linux_segreg_off linux_segregs_off[] = { 368 { 369 .reg = offsetof(struct linux_pt_regset, gs), 370 .is0 = true, 371 }, 372 { 373 .reg = offsetof(struct linux_pt_regset, fs), 374 .is0 = true, 375 }, 376 { 377 .reg = offsetof(struct linux_pt_regset, ds), 378 .is0 = true, 379 }, 380 { 381 .reg = offsetof(struct linux_pt_regset, es), 382 .is0 = true, 383 }, 384 { 385 .reg = offsetof(struct linux_pt_regset, cs), 386 .is0 = false, 387 }, 388 { 389 .reg = offsetof(struct linux_pt_regset, ss), 390 .is0 = false, 391 }, 392 }; 393 394 int 395 linux_ptrace_pokeuser(struct thread *td, pid_t pid, void *addr, void *data) 396 { 397 struct linux_pt_regset reg; 398 struct reg b_reg, b_reg1; 399 int error, i; 400 401 if ((uintptr_t)addr & (sizeof(data) -1) || (uintptr_t)addr < 0) 402 return (EIO); 403 if ((uintptr_t)addr >= sizeof(struct linux_pt_regset)) { 404 LINUX_RATELIMIT_MSG_OPT1("PTRACE_POKEUSER offset %ld " 405 "not implemented; returning EINVAL", (uintptr_t)addr); 406 return (EINVAL); 407 } 408 409 if (LINUX_URO(addr, fs_base)) 410 return (kern_ptrace(td, PT_SETFSBASE, pid, data, 0)); 411 if (LINUX_URO(addr, gs_base)) 412 return (kern_ptrace(td, PT_SETGSBASE, pid, data, 0)); 413 for (i = 0; i < nitems(linux_segregs_off); i++) { 414 if ((uintptr_t)addr == linux_segregs_off[i].reg) { 415 if (linux_invalid_selector((uintptr_t)data)) 416 return (EIO); 417 if (!linux_segregs_off[i].is0 && (uintptr_t)data == 0) 418 return (EIO); 419 } 420 } 421 if ((error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0)) != 0) 422 return (error); 423 bsd_to_linux_regset(&b_reg, ®); 424 *(®.r15 + ((uintptr_t)addr / sizeof(reg.r15))) = (uint64_t)data; 425 linux_to_bsd_regset(&b_reg1, ®); 426 b_reg1.r_err = b_reg.r_err; 427 b_reg1.r_trapno = b_reg.r_trapno; 428 return (kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0)); 429 } 430 #undef LINUX_URO 431