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