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 bsd_to_linux_fpregset(const struct fpreg *b_fpreg, 286 struct linux_pt_fpregset *l_fpregset) 287 { 288 l_fpregset->cwd = b_fpreg->fpr_env[0]; 289 l_fpregset->swd = b_fpreg->fpr_env[0] >> 16; 290 l_fpregset->twd = b_fpreg->fpr_env[0] >> 32; 291 l_fpregset->fop = b_fpreg->fpr_env[0] >> 48; 292 l_fpregset->rip = b_fpreg->fpr_env[1]; 293 l_fpregset->rdp = b_fpreg->fpr_env[2]; 294 l_fpregset->mxcsr = b_fpreg->fpr_env[3]; 295 l_fpregset->mxcsr_mask = b_fpreg->fpr_env[3] >> 32; 296 297 memcpy(l_fpregset->st_space, b_fpreg->fpr_acc, 298 sizeof(l_fpregset->st_space)); 299 memcpy(l_fpregset->xmm_space, b_fpreg->fpr_xacc, 300 sizeof(l_fpregset->xmm_space)); 301 memset(l_fpregset->padding, 0, sizeof(l_fpregset->padding)); 302 } 303 304 void 305 linux_ptrace_get_syscall_info_machdep(const struct reg *reg, 306 struct syscall_info *si) 307 { 308 309 si->arch = LINUX_ARCH_AMD64; 310 si->instruction_pointer = reg->r_rip; 311 si->stack_pointer = reg->r_rsp; 312 } 313 314 int 315 linux_ptrace_getregs_machdep(struct thread *td, pid_t pid, 316 struct linux_pt_regset *l_regset) 317 { 318 struct ptrace_lwpinfo lwpinfo; 319 struct pcb *pcb; 320 int error; 321 322 pcb = td->td_pcb; 323 if (td == curthread) 324 update_pcb_bases(pcb); 325 326 l_regset->fs_base = pcb->pcb_fsbase; 327 l_regset->gs_base = pcb->pcb_gsbase; 328 329 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo)); 330 if (error != 0) { 331 linux_msg(td, "PT_LWPINFO failed with error %d", error); 332 return (error); 333 } 334 if ((lwpinfo.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)) != 0) { 335 /* 336 * In Linux, the syscall number - passed to the syscall 337 * as rax - is preserved in orig_rax; rax gets overwritten 338 * with syscall return value. 339 */ 340 l_regset->orig_rax = lwpinfo.pl_syscall_code; 341 } 342 343 return (0); 344 } 345 346 #define LINUX_URO(a,m) ((uintptr_t)a == offsetof(struct linux_pt_regset, m)) 347 348 int 349 linux_ptrace_peekuser(struct thread *td, pid_t pid, void *addr, void *data) 350 { 351 struct linux_pt_regset reg; 352 struct reg b_reg; 353 uint64_t val; 354 int error; 355 356 if ((uintptr_t)addr & (sizeof(data) -1) || (uintptr_t)addr < 0) 357 return (EIO); 358 if ((uintptr_t)addr >= sizeof(struct linux_pt_regset)) { 359 LINUX_RATELIMIT_MSG_OPT1("PTRACE_PEEKUSER offset %ld " 360 "not implemented; returning EINVAL", (uintptr_t)addr); 361 return (EINVAL); 362 } 363 364 if (LINUX_URO(addr, fs_base)) 365 return (kern_ptrace(td, PT_GETFSBASE, pid, data, 0)); 366 if (LINUX_URO(addr, gs_base)) 367 return (kern_ptrace(td, PT_GETGSBASE, pid, data, 0)); 368 if ((error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0)) != 0) 369 return (error); 370 bsd_to_linux_regset(&b_reg, ®); 371 val = *(®.r15 + ((uintptr_t)addr / sizeof(reg.r15))); 372 return (copyout(&val, data, sizeof(val))); 373 } 374 375 static inline bool 376 linux_invalid_selector(u_short val) 377 { 378 379 return (val != 0 && ISPL(val) != SEL_UPL); 380 } 381 382 struct linux_segreg_off { 383 uintptr_t reg; 384 bool is0; 385 }; 386 387 const struct linux_segreg_off linux_segregs_off[] = { 388 { 389 .reg = offsetof(struct linux_pt_regset, gs), 390 .is0 = true, 391 }, 392 { 393 .reg = offsetof(struct linux_pt_regset, fs), 394 .is0 = true, 395 }, 396 { 397 .reg = offsetof(struct linux_pt_regset, ds), 398 .is0 = true, 399 }, 400 { 401 .reg = offsetof(struct linux_pt_regset, es), 402 .is0 = true, 403 }, 404 { 405 .reg = offsetof(struct linux_pt_regset, cs), 406 .is0 = false, 407 }, 408 { 409 .reg = offsetof(struct linux_pt_regset, ss), 410 .is0 = false, 411 }, 412 }; 413 414 int 415 linux_ptrace_pokeuser(struct thread *td, pid_t pid, void *addr, void *data) 416 { 417 struct linux_pt_regset reg; 418 struct reg b_reg, b_reg1; 419 int error, i; 420 421 if ((uintptr_t)addr & (sizeof(data) -1) || (uintptr_t)addr < 0) 422 return (EIO); 423 if ((uintptr_t)addr >= sizeof(struct linux_pt_regset)) { 424 LINUX_RATELIMIT_MSG_OPT1("PTRACE_POKEUSER offset %ld " 425 "not implemented; returning EINVAL", (uintptr_t)addr); 426 return (EINVAL); 427 } 428 429 if (LINUX_URO(addr, fs_base)) 430 return (kern_ptrace(td, PT_SETFSBASE, pid, data, 0)); 431 if (LINUX_URO(addr, gs_base)) 432 return (kern_ptrace(td, PT_SETGSBASE, pid, data, 0)); 433 for (i = 0; i < nitems(linux_segregs_off); i++) { 434 if ((uintptr_t)addr == linux_segregs_off[i].reg) { 435 if (linux_invalid_selector((uintptr_t)data)) 436 return (EIO); 437 if (!linux_segregs_off[i].is0 && (uintptr_t)data == 0) 438 return (EIO); 439 } 440 } 441 if ((error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0)) != 0) 442 return (error); 443 bsd_to_linux_regset(&b_reg, ®); 444 *(®.r15 + ((uintptr_t)addr / sizeof(reg.r15))) = (uint64_t)data; 445 linux_to_bsd_regset(&b_reg1, ®); 446 b_reg1.r_err = b_reg.r_err; 447 b_reg1.r_trapno = b_reg.r_trapno; 448 return (kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0)); 449 } 450 #undef LINUX_URO 451