git: 9480640957ff - stable/13 - linux(4): Make ptrace_peekusr machine dependend

From: Dmitry Chagin <dchagin_at_FreeBSD.org>
Date: Thu, 29 Jun 2023 08:20:35 UTC
The branch stable/13 has been updated by dchagin:

URL: https://cgit.FreeBSD.org/src/commit/?id=9480640957ff48c6bc7c0ea5d4f3eb5930f417e3

commit 9480640957ff48c6bc7c0ea5d4f3eb5930f417e3
Author:     Dmitry Chagin <dchagin@FreeBSD.org>
AuthorDate: 2023-05-18 17:00:12 +0000
Commit:     Dmitry Chagin <dchagin@FreeBSD.org>
CommitDate: 2023-06-29 08:15:59 +0000

    linux(4): Make ptrace_peekusr machine dependend
    
    And partially implement it for x86_64.
    
    Differential Revision:  https://reviews.freebsd.org/D40095
    MFC after:              1 week
    
    (cherry picked from commit dd2a6cd701aea5a6ced59b9947e087304f7d7238)
---
 sys/amd64/linux/linux.h             |  2 ++
 sys/amd64/linux/linux_machdep.c     | 31 ++++++++++++++++++++++++++
 sys/amd64/linux32/linux.h           |  2 ++
 sys/amd64/linux32/linux32_machdep.c |  9 ++++++++
 sys/arm64/linux/linux.h             |  2 ++
 sys/arm64/linux/linux_machdep.c     |  8 +++++++
 sys/compat/linux/linux_ptrace.c     | 43 -------------------------------------
 7 files changed, 54 insertions(+), 43 deletions(-)

diff --git a/sys/amd64/linux/linux.h b/sys/amd64/linux/linux.h
index a5682c6a980d..57f1ee0115e6 100644
--- a/sys/amd64/linux/linux.h
+++ b/sys/amd64/linux/linux.h
@@ -322,6 +322,8 @@ void	linux_ptrace_get_syscall_info_machdep(const struct reg *reg,
 	    struct syscall_info *si);
 int	linux_ptrace_getregs_machdep(struct thread *td, pid_t pid,
 	    struct linux_pt_regset *l_regset);
+int	linux_ptrace_peekuser(struct thread *td, pid_t pid,
+	    void *addr, void *data);
 #endif /* _KERNEL */
 
 #endif /* !_AMD64_LINUX_H_ */
diff --git a/sys/amd64/linux/linux_machdep.c b/sys/amd64/linux/linux_machdep.c
index 6c96dd496fdc..233d66a40899 100644
--- a/sys/amd64/linux/linux_machdep.c
+++ b/sys/amd64/linux/linux_machdep.c
@@ -367,3 +367,34 @@ 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, &reg);
+	val = *(&reg.r15 + ((uintptr_t)addr / sizeof(reg.r15)));
+	return (copyout(&val, data, sizeof(val)));
+}
+
+#undef LINUX_URO
diff --git a/sys/amd64/linux32/linux.h b/sys/amd64/linux32/linux.h
index 32f2f42b0108..a98777adeaf5 100644
--- a/sys/amd64/linux32/linux.h
+++ b/sys/amd64/linux32/linux.h
@@ -465,6 +465,8 @@ struct reg32;
 
 void	bsd_to_linux_regset32(const struct reg32 *b_reg,
 	    struct linux_pt_regset32 *l_regset);
+int	linux_ptrace_peekuser(struct thread *td, pid_t pid,
+	    void *addr, void *data);
 
 extern bool linux32_emulate_i386;
 #endif /* _KERNEL */
diff --git a/sys/amd64/linux32/linux32_machdep.c b/sys/amd64/linux32/linux32_machdep.c
index 0bd398042c3f..afc60fb7e822 100644
--- a/sys/amd64/linux32/linux32_machdep.c
+++ b/sys/amd64/linux32/linux32_machdep.c
@@ -742,3 +742,12 @@ DEFINE_IFUNC(, int, futex_xorl, (int, uint32_t *, int *))
 	return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
 	    futex_xorl_smap : futex_xorl_nosmap);
 }
+
+int
+linux_ptrace_peekuser(struct thread *td, pid_t pid, void *addr, void *data)
+{
+
+	LINUX_RATELIMIT_MSG_OPT1("PTRACE_PEEKUSER offset %ld not implemented; "
+	    "returning EINVAL", (uintptr_t)addr);
+	return (EINVAL);
+}
diff --git a/sys/arm64/linux/linux.h b/sys/arm64/linux/linux.h
index 5a391c3543d3..be6733c81d97 100644
--- a/sys/arm64/linux/linux.h
+++ b/sys/arm64/linux/linux.h
@@ -238,6 +238,8 @@ void	linux_ptrace_get_syscall_info_machdep(const struct reg *reg,
 	    struct syscall_info *si);
 int	linux_ptrace_getregs_machdep(struct thread *td, pid_t pid,
 	    struct linux_pt_regset *l_regset);
+int	linux_ptrace_peekuser(struct thread *td, pid_t pid,
+	    void *addr, void *data);
 #endif /* _KERNEL */
 
 #endif /* _ARM64_LINUX_H_ */
diff --git a/sys/arm64/linux/linux_machdep.c b/sys/arm64/linux/linux_machdep.c
index 4b12476f7865..2e472869eedb 100644
--- a/sys/arm64/linux/linux_machdep.c
+++ b/sys/arm64/linux/linux_machdep.c
@@ -152,3 +152,11 @@ linux_ptrace_getregs_machdep(struct thread *td __unused, pid_t pid __unused,
 	return (0);
 }
 
+int
+linux_ptrace_peekuser(struct thread *td, pid_t pid, void *addr, void *data)
+{
+
+	LINUX_RATELIMIT_MSG_OPT1("PTRACE_PEEKUSER offset %ld not implemented; "
+	    "returning EINVAL", (uintptr_t)addr);
+	return (EINVAL);
+}
diff --git a/sys/compat/linux/linux_ptrace.c b/sys/compat/linux/linux_ptrace.c
index 151355d2bb3f..c1c7abf70a9d 100644
--- a/sys/compat/linux/linux_ptrace.c
+++ b/sys/compat/linux/linux_ptrace.c
@@ -100,11 +100,6 @@ __FBSDID("$FreeBSD$");
 #define	LINUX_PTRACE_SYSCALL_INFO_ENTRY	1
 #define	LINUX_PTRACE_SYSCALL_INFO_EXIT	2
 
-#define LINUX_PTRACE_PEEKUSER_ORIG_RAX	120
-#define LINUX_PTRACE_PEEKUSER_RIP	128
-#define LINUX_PTRACE_PEEKUSER_CS	136
-#define LINUX_PTRACE_PEEKUSER_DS	184
-
 static int
 map_signum(int lsig, int *bsigp)
 {
@@ -179,44 +174,6 @@ linux_ptrace_peek(struct thread *td, pid_t pid, void *addr, void *data)
 	return (error);
 }
 
-static int
-linux_ptrace_peekuser(struct thread *td, pid_t pid, void *addr, void *data)
-{
-	struct reg b_reg;
-	uint64_t val;
-	int error;
-
-	error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
-	if (error != 0)
-		return (error);
-
-	switch ((uintptr_t)addr) {
-#ifdef __amd64__
-	case LINUX_PTRACE_PEEKUSER_ORIG_RAX:
-		val = b_reg.r_rax;
-		break;
-	case LINUX_PTRACE_PEEKUSER_RIP:
-		val = b_reg.r_rip;
-		break;
-	case LINUX_PTRACE_PEEKUSER_CS:
-		val = b_reg.r_cs;
-		break;
-	case LINUX_PTRACE_PEEKUSER_DS:
-		val = b_reg.r_ds;
-		break;
-#endif /* __amd64__ */
-	default:
-		linux_msg(td, "PTRACE_PEEKUSER offset %ld not implemented; "
-		    "returning EINVAL", (uintptr_t)addr);
-		return (EINVAL);
-	}
-
-	error = copyout(&val, data, sizeof(val));
-	td->td_retval[0] = error;
-
-	return (error);
-}
-
 static int
 linux_ptrace_pokeuser(struct thread *td, pid_t pid, void *addr, void *data)
 {