git: 050cd99a65a5 - stable/13 - linux(4): Implement ptrace_pokeusr for x86_64
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 29 Jun 2023 08:20:37 UTC
The branch stable/13 has been updated by dchagin: URL: https://cgit.FreeBSD.org/src/commit/?id=050cd99a65a565b678d47c0e6980e14f4fca9112 commit 050cd99a65a565b678d47c0e6980e14f4fca9112 Author: Dmitry Chagin <dchagin@FreeBSD.org> AuthorDate: 2023-05-18 17:02:35 +0000 Commit: Dmitry Chagin <dchagin@FreeBSD.org> CommitDate: 2023-06-29 08:15:59 +0000 linux(4): Implement ptrace_pokeusr for x86_64 Differential Revision: https://reviews.freebsd.org/D40097 MFC after: 1 week (cherry picked from commit 1d76741520c031730319ed976a6c394213991504) --- sys/amd64/linux/linux_machdep.c | 73 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 3 deletions(-) diff --git a/sys/amd64/linux/linux_machdep.c b/sys/amd64/linux/linux_machdep.c index ddb291169a03..6ac0ab0cd3d7 100644 --- a/sys/amd64/linux/linux_machdep.c +++ b/sys/amd64/linux/linux_machdep.c @@ -397,12 +397,79 @@ linux_ptrace_peekuser(struct thread *td, pid_t pid, void *addr, void *data) 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; - LINUX_RATELIMIT_MSG_OPT1("PTRACE_POKEUSER offset %ld " - "not implemented; returning EINVAL", (uintptr_t)addr); - return (EINVAL); + 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