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/cdefs.h> 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/ktr.h> 36 #include <sys/lock.h> 37 #include <sys/malloc.h> 38 #include <sys/mman.h> 39 #include <sys/mutex.h> 40 #include <sys/priv.h> 41 #include <sys/proc.h> 42 #include <sys/ptrace.h> 43 #include <sys/syscallsubr.h> 44 45 #include <security/mac/mac_framework.h> 46 47 #include <ufs/ufs/extattr.h> 48 #include <ufs/ufs/quota.h> 49 #include <ufs/ufs/ufsmount.h> 50 51 #include <machine/frame.h> 52 #include <machine/md_var.h> 53 #include <machine/pcb.h> 54 #include <machine/psl.h> 55 #include <machine/segments.h> 56 #include <machine/specialreg.h> 57 58 #include <vm/pmap.h> 59 #include <vm/vm.h> 60 #include <vm/vm_param.h> 61 #include <vm/vm_extern.h> 62 #include <vm/vm_kern.h> 63 #include <vm/vm_map.h> 64 65 #include <x86/ifunc.h> 66 #include <x86/reg.h> 67 #include <x86/sysarch.h> 68 69 #include <amd64/linux/linux.h> 70 #include <amd64/linux/linux_proto.h> 71 #include <compat/linux/linux_fork.h> 72 #include <compat/linux/linux_misc.h> 73 #include <compat/linux/linux_mmap.h> 74 #include <compat/linux/linux_util.h> 75 76 #define LINUX_ARCH_AMD64 0xc000003e 77 78 int 79 linux_set_upcall(struct thread *td, register_t stack) 80 { 81 82 if (stack) 83 td->td_frame->tf_rsp = stack; 84 85 /* 86 * The newly created Linux thread returns 87 * to the user space by the same path that a parent does. 88 */ 89 td->td_frame->tf_rax = 0; 90 return (0); 91 } 92 93 int 94 linux_mmap2(struct thread *td, struct linux_mmap2_args *args) 95 { 96 97 return (linux_mmap_common(td, args->addr, args->len, args->prot, 98 args->flags, args->fd, args->pgoff)); 99 } 100 101 int 102 linux_mprotect(struct thread *td, struct linux_mprotect_args *uap) 103 { 104 105 return (linux_mprotect_common(td, uap->addr, uap->len, uap->prot)); 106 } 107 108 int 109 linux_madvise(struct thread *td, struct linux_madvise_args *uap) 110 { 111 112 return (linux_madvise_common(td, uap->addr, uap->len, uap->behav)); 113 } 114 115 int 116 linux_iopl(struct thread *td, struct linux_iopl_args *args) 117 { 118 int error; 119 120 LINUX_CTR(iopl); 121 122 if (args->level > 3) 123 return (EINVAL); 124 if ((error = priv_check(td, PRIV_IO)) != 0) 125 return (error); 126 if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 127 return (error); 128 td->td_frame->tf_rflags = (td->td_frame->tf_rflags & ~PSL_IOPL) | 129 (args->level * (PSL_IOPL / 3)); 130 131 return (0); 132 } 133 134 int 135 linux_pause(struct thread *td, struct linux_pause_args *args) 136 { 137 struct proc *p = td->td_proc; 138 sigset_t sigmask; 139 140 LINUX_CTR(pause); 141 142 PROC_LOCK(p); 143 sigmask = td->td_sigmask; 144 PROC_UNLOCK(p); 145 return (kern_sigsuspend(td, sigmask)); 146 } 147 148 int 149 linux_arch_prctl(struct thread *td, struct linux_arch_prctl_args *args) 150 { 151 unsigned long long cet[3]; 152 struct pcb *pcb; 153 int error; 154 155 pcb = td->td_pcb; 156 LINUX_CTR2(arch_prctl, "0x%x, %p", args->code, args->addr); 157 158 switch (args->code) { 159 case LINUX_ARCH_SET_GS: 160 if (args->addr < VM_MAXUSER_ADDRESS) { 161 update_pcb_bases(pcb); 162 pcb->pcb_gsbase = args->addr; 163 td->td_frame->tf_gs = _ugssel; 164 error = 0; 165 } else 166 error = EPERM; 167 break; 168 case LINUX_ARCH_SET_FS: 169 if (args->addr < VM_MAXUSER_ADDRESS) { 170 update_pcb_bases(pcb); 171 pcb->pcb_fsbase = args->addr; 172 td->td_frame->tf_fs = _ufssel; 173 error = 0; 174 } else 175 error = EPERM; 176 break; 177 case LINUX_ARCH_GET_FS: 178 error = copyout(&pcb->pcb_fsbase, PTRIN(args->addr), 179 sizeof(args->addr)); 180 break; 181 case LINUX_ARCH_GET_GS: 182 error = copyout(&pcb->pcb_gsbase, PTRIN(args->addr), 183 sizeof(args->addr)); 184 break; 185 case LINUX_ARCH_CET_STATUS: 186 memset(cet, 0, sizeof(cet)); 187 error = copyout(&cet, PTRIN(args->addr), sizeof(cet)); 188 break; 189 default: 190 linux_msg(td, "unsupported arch_prctl code %#x", args->code); 191 error = EINVAL; 192 } 193 return (error); 194 } 195 196 int 197 linux_set_cloned_tls(struct thread *td, void *desc) 198 { 199 struct pcb *pcb; 200 201 if ((uint64_t)desc >= VM_MAXUSER_ADDRESS) 202 return (EPERM); 203 204 pcb = td->td_pcb; 205 update_pcb_bases(pcb); 206 pcb->pcb_fsbase = (register_t)desc; 207 td->td_frame->tf_fs = _ufssel; 208 209 return (0); 210 } 211 212 int futex_xchgl_nosmap(int oparg, uint32_t *uaddr, int *oldval); 213 int futex_xchgl_smap(int oparg, uint32_t *uaddr, int *oldval); 214 DEFINE_IFUNC(, int, futex_xchgl, (int, uint32_t *, int *)) 215 { 216 217 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 218 futex_xchgl_smap : futex_xchgl_nosmap); 219 } 220 221 int futex_addl_nosmap(int oparg, uint32_t *uaddr, int *oldval); 222 int futex_addl_smap(int oparg, uint32_t *uaddr, int *oldval); 223 DEFINE_IFUNC(, int, futex_addl, (int, uint32_t *, int *)) 224 { 225 226 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 227 futex_addl_smap : futex_addl_nosmap); 228 } 229 230 int futex_orl_nosmap(int oparg, uint32_t *uaddr, int *oldval); 231 int futex_orl_smap(int oparg, uint32_t *uaddr, int *oldval); 232 DEFINE_IFUNC(, int, futex_orl, (int, uint32_t *, int *)) 233 { 234 235 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 236 futex_orl_smap : futex_orl_nosmap); 237 } 238 239 int futex_andl_nosmap(int oparg, uint32_t *uaddr, int *oldval); 240 int futex_andl_smap(int oparg, uint32_t *uaddr, int *oldval); 241 DEFINE_IFUNC(, int, futex_andl, (int, uint32_t *, int *)) 242 { 243 244 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 245 futex_andl_smap : futex_andl_nosmap); 246 } 247 248 int futex_xorl_nosmap(int oparg, uint32_t *uaddr, int *oldval); 249 int futex_xorl_smap(int oparg, uint32_t *uaddr, int *oldval); 250 DEFINE_IFUNC(, int, futex_xorl, (int, uint32_t *, int *)) 251 { 252 253 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 254 futex_xorl_smap : futex_xorl_nosmap); 255 } 256 257 void 258 bsd_to_linux_regset(const struct reg *b_reg, struct linux_pt_regset *l_regset) 259 { 260 261 l_regset->r15 = b_reg->r_r15; 262 l_regset->r14 = b_reg->r_r14; 263 l_regset->r13 = b_reg->r_r13; 264 l_regset->r12 = b_reg->r_r12; 265 l_regset->rbp = b_reg->r_rbp; 266 l_regset->rbx = b_reg->r_rbx; 267 l_regset->r11 = b_reg->r_r11; 268 l_regset->r10 = b_reg->r_r10; 269 l_regset->r9 = b_reg->r_r9; 270 l_regset->r8 = b_reg->r_r8; 271 l_regset->rax = b_reg->r_rax; 272 l_regset->rcx = b_reg->r_rcx; 273 l_regset->rdx = b_reg->r_rdx; 274 l_regset->rsi = b_reg->r_rsi; 275 l_regset->rdi = b_reg->r_rdi; 276 l_regset->orig_rax = b_reg->r_rax; 277 l_regset->rip = b_reg->r_rip; 278 l_regset->cs = b_reg->r_cs; 279 l_regset->eflags = b_reg->r_rflags; 280 l_regset->rsp = b_reg->r_rsp; 281 l_regset->ss = b_reg->r_ss; 282 l_regset->fs_base = 0; 283 l_regset->gs_base = 0; 284 l_regset->ds = b_reg->r_ds; 285 l_regset->es = b_reg->r_es; 286 l_regset->fs = b_reg->r_fs; 287 l_regset->gs = b_reg->r_gs; 288 } 289 290 void 291 linux_to_bsd_regset(struct reg *b_reg, const struct linux_pt_regset *l_regset) 292 { 293 294 b_reg->r_r15 = l_regset->r15; 295 b_reg->r_r14 = l_regset->r14; 296 b_reg->r_r13 = l_regset->r13; 297 b_reg->r_r12 = l_regset->r12; 298 b_reg->r_rbp = l_regset->rbp; 299 b_reg->r_rbx = l_regset->rbx; 300 b_reg->r_r11 = l_regset->r11; 301 b_reg->r_r10 = l_regset->r10; 302 b_reg->r_r9 = l_regset->r9; 303 b_reg->r_r8 = l_regset->r8; 304 b_reg->r_rax = l_regset->rax; 305 b_reg->r_rcx = l_regset->rcx; 306 b_reg->r_rdx = l_regset->rdx; 307 b_reg->r_rsi = l_regset->rsi; 308 b_reg->r_rdi = l_regset->rdi; 309 b_reg->r_rax = l_regset->orig_rax; 310 b_reg->r_rip = l_regset->rip; 311 b_reg->r_cs = l_regset->cs; 312 b_reg->r_rflags = l_regset->eflags; 313 b_reg->r_rsp = l_regset->rsp; 314 b_reg->r_ss = l_regset->ss; 315 b_reg->r_ds = l_regset->ds; 316 b_reg->r_es = l_regset->es; 317 b_reg->r_fs = l_regset->fs; 318 b_reg->r_gs = l_regset->gs; 319 } 320 321 void 322 linux_ptrace_get_syscall_info_machdep(const struct reg *reg, 323 struct syscall_info *si) 324 { 325 326 si->arch = LINUX_ARCH_AMD64; 327 si->instruction_pointer = reg->r_rip; 328 si->stack_pointer = reg->r_rsp; 329 } 330 331 int 332 linux_ptrace_getregs_machdep(struct thread *td, pid_t pid, 333 struct linux_pt_regset *l_regset) 334 { 335 struct ptrace_lwpinfo lwpinfo; 336 struct pcb *pcb; 337 int error; 338 339 pcb = td->td_pcb; 340 if (td == curthread) 341 update_pcb_bases(pcb); 342 343 l_regset->fs_base = pcb->pcb_fsbase; 344 l_regset->gs_base = pcb->pcb_gsbase; 345 346 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo)); 347 if (error != 0) { 348 linux_msg(td, "PT_LWPINFO failed with error %d", error); 349 return (error); 350 } 351 if ((lwpinfo.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)) != 0) { 352 /* 353 * In Linux, the syscall number - passed to the syscall 354 * as rax - is preserved in orig_rax; rax gets overwritten 355 * with syscall return value. 356 */ 357 l_regset->orig_rax = lwpinfo.pl_syscall_code; 358 } 359 360 return (0); 361 } 362 363 #define LINUX_URO(a,m) ((uintptr_t)a == offsetof(struct linux_pt_regset, m)) 364 365 int 366 linux_ptrace_peekuser(struct thread *td, pid_t pid, void *addr, void *data) 367 { 368 struct linux_pt_regset reg; 369 struct reg b_reg; 370 uint64_t val; 371 int error; 372 373 if ((uintptr_t)addr & (sizeof(data) -1) || (uintptr_t)addr < 0) 374 return (EIO); 375 if ((uintptr_t)addr >= sizeof(struct linux_pt_regset)) { 376 LINUX_RATELIMIT_MSG_OPT1("PTRACE_PEEKUSER offset %ld " 377 "not implemented; returning EINVAL", (uintptr_t)addr); 378 return (EINVAL); 379 } 380 381 if (LINUX_URO(addr, fs_base)) 382 return (kern_ptrace(td, PT_GETFSBASE, pid, data, 0)); 383 if (LINUX_URO(addr, gs_base)) 384 return (kern_ptrace(td, PT_GETGSBASE, pid, data, 0)); 385 if ((error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0)) != 0) 386 return (error); 387 bsd_to_linux_regset(&b_reg, ®); 388 val = *(®.r15 + ((uintptr_t)addr / sizeof(reg.r15))); 389 return (copyout(&val, data, sizeof(val))); 390 } 391 392 static inline bool 393 linux_invalid_selector(u_short val) 394 { 395 396 return (val != 0 && ISPL(val) != SEL_UPL); 397 } 398 399 struct linux_segreg_off { 400 uintptr_t reg; 401 bool is0; 402 }; 403 404 const struct linux_segreg_off linux_segregs_off[] = { 405 { 406 .reg = offsetof(struct linux_pt_regset, gs), 407 .is0 = true, 408 }, 409 { 410 .reg = offsetof(struct linux_pt_regset, fs), 411 .is0 = true, 412 }, 413 { 414 .reg = offsetof(struct linux_pt_regset, ds), 415 .is0 = true, 416 }, 417 { 418 .reg = offsetof(struct linux_pt_regset, es), 419 .is0 = true, 420 }, 421 { 422 .reg = offsetof(struct linux_pt_regset, cs), 423 .is0 = false, 424 }, 425 { 426 .reg = offsetof(struct linux_pt_regset, ss), 427 .is0 = false, 428 }, 429 }; 430 431 int 432 linux_ptrace_pokeuser(struct thread *td, pid_t pid, void *addr, void *data) 433 { 434 struct linux_pt_regset reg; 435 struct reg b_reg, b_reg1; 436 int error, i; 437 438 if ((uintptr_t)addr & (sizeof(data) -1) || (uintptr_t)addr < 0) 439 return (EIO); 440 if ((uintptr_t)addr >= sizeof(struct linux_pt_regset)) { 441 LINUX_RATELIMIT_MSG_OPT1("PTRACE_POKEUSER offset %ld " 442 "not implemented; returning EINVAL", (uintptr_t)addr); 443 return (EINVAL); 444 } 445 446 if (LINUX_URO(addr, fs_base)) 447 return (kern_ptrace(td, PT_SETFSBASE, pid, data, 0)); 448 if (LINUX_URO(addr, gs_base)) 449 return (kern_ptrace(td, PT_SETGSBASE, pid, data, 0)); 450 for (i = 0; i < nitems(linux_segregs_off); i++) { 451 if ((uintptr_t)addr == linux_segregs_off[i].reg) { 452 if (linux_invalid_selector((uintptr_t)data)) 453 return (EIO); 454 if (!linux_segregs_off[i].is0 && (uintptr_t)data == 0) 455 return (EIO); 456 } 457 } 458 if ((error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0)) != 0) 459 return (error); 460 bsd_to_linux_regset(&b_reg, ®); 461 *(®.r15 + ((uintptr_t)addr / sizeof(reg.r15))) = (uint64_t)data; 462 linux_to_bsd_regset(&b_reg1, ®); 463 b_reg1.r_err = b_reg.r_err; 464 b_reg1.r_trapno = b_reg.r_trapno; 465 return (kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0)); 466 } 467 #undef LINUX_URO 468