diff options
Diffstat (limited to 'sys/amd64/linux/linux_machdep.c')
-rw-r--r-- | sys/amd64/linux/linux_machdep.c | 173 |
1 files changed, 108 insertions, 65 deletions
diff --git a/sys/amd64/linux/linux_machdep.c b/sys/amd64/linux/linux_machdep.c index 1c042424f3ea..7ec1ec56bb95 100644 --- a/sys/amd64/linux/linux_machdep.c +++ b/sys/amd64/linux/linux_machdep.c @@ -29,54 +29,24 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> -#include <sys/capsicum.h> -#include <sys/clock.h> -#include <sys/dirent.h> -#include <sys/fcntl.h> -#include <sys/file.h> -#include <sys/filedesc.h> -#include <sys/kernel.h> +#include <sys/systm.h> #include <sys/ktr.h> -#include <sys/limits.h> #include <sys/lock.h> -#include <sys/malloc.h> #include <sys/mman.h> #include <sys/mutex.h> #include <sys/priv.h> #include <sys/proc.h> #include <sys/ptrace.h> -#include <sys/resource.h> -#include <sys/resourcevar.h> -#include <sys/sched.h> #include <sys/syscallsubr.h> -#include <sys/sysproto.h> -#include <sys/systm.h> -#include <sys/unistd.h> -#include <sys/vnode.h> -#include <sys/wait.h> -#include <security/mac/mac_framework.h> - -#include <ufs/ufs/extattr.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/ufsmount.h> - -#include <machine/frame.h> #include <machine/md_var.h> #include <machine/pcb.h> -#include <machine/psl.h> -#include <machine/segments.h> #include <machine/specialreg.h> #include <vm/pmap.h> #include <vm/vm.h> -#include <vm/vm_extern.h> -#include <vm/vm_kern.h> -#include <vm/vm_map.h> +#include <vm/vm_param.h> #include <x86/ifunc.h> #include <x86/reg.h> @@ -84,13 +54,8 @@ __FBSDID("$FreeBSD$"); #include <amd64/linux/linux.h> #include <amd64/linux/linux_proto.h> -#include <compat/linux/linux_emul.h> -#include <compat/linux/linux_file.h> #include <compat/linux/linux_fork.h> -#include <compat/linux/linux_ipc.h> #include <compat/linux/linux_misc.h> -#include <compat/linux/linux_mmap.h> -#include <compat/linux/linux_signal.h> #include <compat/linux/linux_util.h> #define LINUX_ARCH_AMD64 0xc000003e @@ -111,28 +76,6 @@ linux_set_upcall(struct thread *td, register_t stack) } int -linux_mmap2(struct thread *td, struct linux_mmap2_args *args) -{ - - return (linux_mmap_common(td, args->addr, args->len, args->prot, - args->flags, args->fd, args->pgoff)); -} - -int -linux_mprotect(struct thread *td, struct linux_mprotect_args *uap) -{ - - return (linux_mprotect_common(td, uap->addr, uap->len, uap->prot)); -} - -int -linux_madvise(struct thread *td, struct linux_madvise_args *uap) -{ - - return (linux_madvise_common(td, uap->addr, uap->len, uap->behav)); -} - -int linux_iopl(struct thread *td, struct linux_iopl_args *args) { int error; @@ -368,12 +311,6 @@ linux_ptrace_getregs_machdep(struct thread *td, pid_t pid, linux_msg(td, "PT_LWPINFO failed with error %d", error); return (error); } - if ((lwpinfo.pl_flags & PL_FLAG_SCE) != 0) { - /* - * Undo the mangling done in exception.S:fast_syscall_common(). - */ - l_regset->r10 = l_regset->rcx; - } if ((lwpinfo.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)) != 0) { /* * In Linux, the syscall number - passed to the syscall @@ -385,3 +322,109 @@ linux_ptrace_getregs_machdep(struct thread *td, pid_t pid, return (0); } + +#define LINUX_URO(a,m) ((uintptr_t)a == offsetof(struct linux_pt_regset, m)) + +int +linux_ptrace_peekuser(struct thread *td, pid_t pid, void *addr, void *data) +{ + struct linux_pt_regset reg; + struct reg b_reg; + uint64_t val; + int error; + + if ((uintptr_t)addr & (sizeof(data) -1) || (uintptr_t)addr < 0) + return (EIO); + if ((uintptr_t)addr >= sizeof(struct linux_pt_regset)) { + LINUX_RATELIMIT_MSG_OPT1("PTRACE_PEEKUSER offset %ld " + "not implemented; returning EINVAL", (uintptr_t)addr); + return (EINVAL); + } + + if (LINUX_URO(addr, fs_base)) + return (kern_ptrace(td, PT_GETFSBASE, pid, data, 0)); + if (LINUX_URO(addr, gs_base)) + return (kern_ptrace(td, PT_GETGSBASE, pid, data, 0)); + if ((error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0)) != 0) + return (error); + bsd_to_linux_regset(&b_reg, ®); + val = *(®.r15 + ((uintptr_t)addr / sizeof(reg.r15))); + return (copyout(&val, data, sizeof(val))); +} + +static inline bool +linux_invalid_selector(u_short val) +{ + + return (val != 0 && ISPL(val) != SEL_UPL); +} + +struct linux_segreg_off { + uintptr_t reg; + bool is0; +}; + +const struct linux_segreg_off linux_segregs_off[] = { + { + .reg = offsetof(struct linux_pt_regset, gs), + .is0 = true, + }, + { + .reg = offsetof(struct linux_pt_regset, fs), + .is0 = true, + }, + { + .reg = offsetof(struct linux_pt_regset, ds), + .is0 = true, + }, + { + .reg = offsetof(struct linux_pt_regset, es), + .is0 = true, + }, + { + .reg = offsetof(struct linux_pt_regset, cs), + .is0 = false, + }, + { + .reg = offsetof(struct linux_pt_regset, ss), + .is0 = false, + }, +}; + +int +linux_ptrace_pokeuser(struct thread *td, pid_t pid, void *addr, void *data) +{ + struct linux_pt_regset reg; + struct reg b_reg, b_reg1; + int error, i; + + if ((uintptr_t)addr & (sizeof(data) -1) || (uintptr_t)addr < 0) + return (EIO); + if ((uintptr_t)addr >= sizeof(struct linux_pt_regset)) { + LINUX_RATELIMIT_MSG_OPT1("PTRACE_POKEUSER offset %ld " + "not implemented; returning EINVAL", (uintptr_t)addr); + return (EINVAL); + } + + if (LINUX_URO(addr, fs_base)) + return (kern_ptrace(td, PT_SETFSBASE, pid, data, 0)); + if (LINUX_URO(addr, gs_base)) + return (kern_ptrace(td, PT_SETGSBASE, pid, data, 0)); + for (i = 0; i < nitems(linux_segregs_off); i++) { + if ((uintptr_t)addr == linux_segregs_off[i].reg) { + if (linux_invalid_selector((uintptr_t)data)) + return (EIO); + if (!linux_segregs_off[i].is0 && (uintptr_t)data == 0) + return (EIO); + } + } + if ((error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0)) != 0) + return (error); + bsd_to_linux_regset(&b_reg, ®); + *(®.r15 + ((uintptr_t)addr / sizeof(reg.r15))) = (uint64_t)data; + linux_to_bsd_regset(&b_reg1, ®); + b_reg1.r_err = b_reg.r_err; + b_reg1.r_trapno = b_reg.r_trapno; + return (kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0)); +} +#undef LINUX_URO |