加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
0039-kpatch_ptrace-Split-function-kpatch_ptrace_waitpid.patch 12.36 KB
一键复制 编辑 原始数据 按行查看 历史
From 35b9c6934fc5c1e2ea4cf7e30b91b3b91e48074d Mon Sep 17 00:00:00 2001
From: Jiajie Li <lijiajie11@huawei.com>
Date: Mon, 12 Oct 2020 16:16:57 +0800
Subject: [PATCH 39/89] kpatch_ptrace: Split function kpatch_ptrace_waitpid
The function kpatch_ptrace_waitpid is arch related, let's
rename it with kpatch_arch_ptrace_waitpid, and make the
defination in arch/x86/arch_ptrace.c and arch/aarch64/arch_ptrace.c
Signed-off-by: Jiajie Li <lijiajie11@huawei.com>
Signed-off-by: Ying Fang <fangying1@huawei.com>
---
src/arch/aarch64/arch_ptrace.c | 145 +++++++++++++++++++++++++++++++++
src/arch/x86/arch_ptrace.c | 140 +++++++++++++++++++++++++++++++
src/include/kpatch_ptrace.h | 20 +++++
src/kpatch_ptrace.c | 130 +----------------------------
4 files changed, 307 insertions(+), 128 deletions(-)
diff --git a/src/arch/aarch64/arch_ptrace.c b/src/arch/aarch64/arch_ptrace.c
index e69de29..fb19e86 100644
--- a/src/arch/aarch64/arch_ptrace.c
+++ b/src/arch/aarch64/arch_ptrace.c
@@ -0,0 +1,145 @@
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+#include <asm/unistd.h>
+
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <linux/auxvec.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "include/kpatch_process.h"
+#include "include/kpatch_common.h"
+#include "include/kpatch_ptrace.h"
+#include "include/kpatch_log.h"
+
+#include <gelf.h>
+
+int
+kpatch_arch_ptrace_waitpid(kpatch_process_t *proc,
+ struct timespec *timeout,
+ const sigset_t *sigset)
+{
+ struct kpatch_ptrace_ctx *pctx;
+ siginfo_t siginfo;
+ int ret, status;
+ pid_t pid;
+ struct user_regs_struct regs;
+ struct iovec regs_iov;
+
+ regs_iov.iov_base = &regs;
+ regs_iov.iov_len = sizeof(regs);
+
+ /* Immediately reap one attached thread */
+ pid = waitpid(-1, &status, __WALL | WNOHANG);
+
+ if (pid < 0) {
+ kplogerror("can't wait for tracees\n");
+ return -1;
+ }
+
+ /* There is none ready, wait for notification via signal */
+ if (pid == 0) {
+ ret = sigtimedwait(sigset, &siginfo, timeout);
+ if (ret == -1 && errno == EAGAIN) {
+ /* We have timeouted */
+ return -1;
+ }
+
+ if (ret == -1 && errno == EINVAL) {
+ kperr("invalid timeout\n");
+ return -1;
+ }
+
+ /* We have got EINTR and must restart */
+ if (ret == -1 && errno == EINTR)
+ return 0;
+
+ /**
+ * Kernel stacks signals that follow too quickly.
+ * Deal with it by waiting for any child, not just
+ * one that is specified in signal
+ */
+ pid = waitpid(-1, &status, __WALL | WNOHANG);
+
+ if (pid == 0) {
+ kperr("missing waitpid for %d\n", siginfo.si_pid);
+ return 0;
+ }
+
+ if (pid < 0) {
+ kplogerror("can't wait for tracee %d\n", siginfo.si_pid);
+ return -1;
+ }
+ }
+
+ if (!WIFSTOPPED(status) && WIFSIGNALED(status)) {
+ /* Continue, resending the signal */
+ ret = ptrace(PTRACE_CONT, pid, NULL,
+ (void *)(uintptr_t)WTERMSIG(status));
+ if (ret < 0) {
+ kplogerror("can't start tracee %d\n", pid);
+ return -1;
+ }
+ return 0;
+ }
+
+ if (WIFEXITED(status)) {
+ pctx = kpatch_ptrace_find_thread(proc, pid, 0UL);
+ if (pctx == NULL) {
+ kperr("got unexpected child '%d' exit\n", pid);
+ } else {
+ /* It's dead */
+ pctx->pid = pctx->running = 0;
+ }
+ return 1;
+ }
+
+ ret = ptrace(PTRACE_GETREGSET, pid, (void *)NT_PRSTATUS, (void *)&regs_iov);
+ if (ret < 0) {
+ kplogerror("can't get regs %d\n", pid);
+ return -1;
+ }
+
+ pctx = kpatch_ptrace_find_thread(proc, pid, regs.pc);
+
+ if (pctx == NULL) {
+ /* We either don't know anything about this thread or
+ * even worse -- we stopped it in the wrong place.
+ * Bail out.
+ */
+ pctx = kpatch_ptrace_find_thread(proc, pid, 0);
+ if (pctx != NULL)
+ pctx->running = 0;
+
+ /* TODO: fix the latter by SINGLESTEPping such a thread with
+ * the original instruction in place */
+ kperr("the thread ran out: %d, pc= %llx, expected = %lx\n", pid,
+ regs.pc, pctx->execute_until);
+ errno = ESRCH;
+ return -1;
+ }
+
+ pctx->running = 0;
+
+ /* Restore thread registers, pctx is now valid */
+ kpdebug("Got thread %d at %llx\n", pctx->pid,
+ regs.pc - BREAK_INSN_LENGTH);
+
+ regs.pc = pctx->execute_until;
+
+ ret = ptrace(PTRACE_SETREGSET, pctx->pid, (void*)NT_PRSTATUS, (void*)&regs_iov);
+ if (ret < 0) {
+ kplogerror("can't set regs - %d\n", pctx->pid);
+ return -1;
+ }
+
+ return 1;
+}
diff --git a/src/arch/x86/arch_ptrace.c b/src/arch/x86/arch_ptrace.c
index e69de29..6e943fd 100644
--- a/src/arch/x86/arch_ptrace.c
+++ b/src/arch/x86/arch_ptrace.c
@@ -0,0 +1,140 @@
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+#include <asm/unistd.h>
+
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <linux/auxvec.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "include/kpatch_process.h"
+#include "include/kpatch_common.h"
+#include "include/kpatch_ptrace.h"
+#include "include/kpatch_log.h"
+
+#include <gelf.h>
+
+int kpatch_arch_ptrace_waitpid(kpatch_process_t *proc,
+ struct timespec *timeout,
+ const sigset_t *sigset)
+{
+ struct kpatch_ptrace_ctx *pctx;
+ siginfo_t siginfo;
+ int ret, status;
+ pid_t pid;
+ struct user_regs_struct regs;
+
+ /* Immediately reap one attached thread */
+ pid = waitpid(-1, &status, __WALL | WNOHANG);
+
+ if (pid < 0) {
+ kplogerror("can't wait for tracees\n");
+ return -1;
+ }
+
+ /* There is none ready, wait for notification via signal */
+ if (pid == 0) {
+ ret = sigtimedwait(sigset, &siginfo, timeout);
+ if (ret == -1 && errno == EAGAIN) {
+ /* We have timeouted */
+ return -1;
+ }
+
+ if (ret == -1 && errno == EINVAL) {
+ kperr("invalid timeout\n");
+ return -1;
+ }
+
+ /* We have got EINTR and must restart */
+ if (ret == -1 && errno == EINTR)
+ return 0;
+
+ /**
+ * Kernel stacks signals that follow too quickly.
+ * Deal with it by waiting for any child, not just
+ * one that is specified in signal
+ */
+ pid = waitpid(-1, &status, __WALL | WNOHANG);
+
+ if (pid == 0) {
+ kperr("missing waitpid for %d\n", siginfo.si_pid);
+ return 0;
+ }
+
+ if (pid < 0) {
+ kplogerror("can't wait for tracee %d\n", siginfo.si_pid);
+ return -1;
+ }
+ }
+
+ if (!WIFSTOPPED(status) && WIFSIGNALED(status)) {
+ /* Continue, resending the signal */
+ ret = ptrace(PTRACE_CONT, pid, NULL,
+ (void *)(uintptr_t)WTERMSIG(status));
+ if (ret < 0) {
+ kplogerror("can't start tracee %d\n", pid);
+ return -1;
+ }
+ return 0;
+ }
+
+ if (WIFEXITED(status)) {
+ pctx = kpatch_ptrace_find_thread(proc, pid, 0UL);
+ if (pctx == NULL) {
+ kperr("got unexpected child '%d' exit\n", pid);
+ } else {
+ /* It's dead */
+ pctx->pid = pctx->running = 0;
+ }
+ return 1;
+ }
+
+ ret = ptrace(PTRACE_GETREGS, pid, NULL, &regs);
+ if (ret < 0) {
+ kplogerror("can't get regs %d\n", pid);
+ return -1;
+ }
+
+ pctx = kpatch_ptrace_find_thread(proc, pid, regs.rip);
+
+ if (pctx == NULL) {
+ /* We either don't know anything about this thread or
+ * even worse -- we stopped it in the wrong place.
+ * Bail out.
+ */
+ pctx = kpatch_ptrace_find_thread(proc, pid, 0);
+ if (pctx != NULL)
+ pctx->running = 0;
+
+ /* TODO: fix the latter by SINGLESTEPping such a thread with
+ * the original instruction in place */
+ kperr("the thread ran out: %d, rip = %llx, expected = %lx\n", pid,
+ regs.rip, pctx->execute_until);
+ errno = ESRCH;
+ return -1;
+ }
+
+ pctx->running = 0;
+
+ /* Restore thread registers, pctx is now valid */
+ kpdebug("Got thread %d at %llx\n", pctx->pid,
+ regs.rip - BREAK_INSN_LENGTH);
+
+ regs.rip = pctx->execute_until;
+
+ ret = ptrace(PTRACE_SETREGS, pctx->pid, NULL, &regs);
+ if (ret < 0) {
+ kplogerror("can't set regs - %d\n", pctx->pid);
+ return -1;
+ }
+
+ return 1;
+}
diff --git a/src/include/kpatch_ptrace.h b/src/include/kpatch_ptrace.h
index 7557e1f..1c7d33e 100644
--- a/src/include/kpatch_ptrace.h
+++ b/src/include/kpatch_ptrace.h
@@ -102,4 +102,24 @@ kpatch_process_memcpy(kpatch_process_t *proc,
unsigned long dst,
unsigned long src,
size_t size);
+
+#define BREAK_INSN_LENGTH 1
+#define BREAK_INSN {0xcc}
+
+#define SEC_TO_MSEC 1000
+#define MSEC_TO_NSEC 1000000
+
+#define for_each_thread(proc, pctx) \
+ list_for_each_entry(pctx, &proc->ptrace.pctxs, list)
+
+struct kpatch_ptrace_ctx *
+kpatch_ptrace_find_thread(kpatch_process_t *proc,
+ pid_t pid,
+ unsigned long rip);
+
+int
+kpatch_arch_ptrace_waitpid(kpatch_process_t *proc,
+ struct timespec *timeout,
+ const sigset_t *sigset);
+
#endif
diff --git a/src/kpatch_ptrace.c b/src/kpatch_ptrace.c
index 8910aa8..3c57288 100644
--- a/src/kpatch_ptrace.c
+++ b/src/kpatch_ptrace.c
@@ -180,16 +180,8 @@ int kpatch_ptrace_get_entry_point(struct kpatch_ptrace_ctx *pctx,
return entry[0] == AT_ENTRY ? 0 : -1;
}
-#define BREAK_INSN_LENGTH 1
-#define BREAK_INSN {0xcc}
-#define SEC_TO_MSEC 1000
-#define MSEC_TO_NSEC 1000000
-
-#define for_each_thread(proc, pctx) \
- list_for_each_entry(pctx, &proc->ptrace.pctxs, list)
-
-static struct kpatch_ptrace_ctx *
+struct kpatch_ptrace_ctx *
kpatch_ptrace_find_thread(kpatch_process_t *proc,
pid_t pid,
unsigned long rip)
@@ -213,124 +205,6 @@ kpatch_ptrace_find_thread(kpatch_process_t *proc,
return NULL;
}
-static inline int
-kpatch_ptrace_waitpid(kpatch_process_t *proc,
- struct timespec *timeout,
- const sigset_t *sigset)
-{
- struct kpatch_ptrace_ctx *pctx;
- siginfo_t siginfo;
- int ret, status;
- pid_t pid;
- struct user_regs_struct regs;
-
- /* Immediately reap one attached thread */
- pid = waitpid(-1, &status, __WALL | WNOHANG);
-
- if (pid < 0) {
- kplogerror("can't wait for tracees\n");
- return -1;
- }
-
- /* There is none ready, wait for notification via signal */
- if (pid == 0) {
- ret = sigtimedwait(sigset, &siginfo, timeout);
- if (ret == -1 && errno == EAGAIN) {
- /* We have timeouted */
- return -1;
- }
-
- if (ret == -1 && errno == EINVAL) {
- kperr("invalid timeout\n");
- return -1;
- }
-
- /* We have got EINTR and must restart */
- if (ret == -1 && errno == EINTR)
- return 0;
-
- /**
- * Kernel stacks signals that follow too quickly.
- * Deal with it by waiting for any child, not just
- * one that is specified in signal
- */
- pid = waitpid(-1, &status, __WALL | WNOHANG);
-
- if (pid == 0) {
- kperr("missing waitpid for %d\n", siginfo.si_pid);
- return 0;
- }
-
- if (pid < 0) {
- kplogerror("can't wait for tracee %d\n", siginfo.si_pid);
- return -1;
- }
- }
-
- if (!WIFSTOPPED(status) && WIFSIGNALED(status)) {
- /* Continue, resending the signal */
- ret = ptrace(PTRACE_CONT, pid, NULL,
- (void *)(uintptr_t)WTERMSIG(status));
- if (ret < 0) {
- kplogerror("can't start tracee %d\n", pid);
- return -1;
- }
- return 0;
- }
-
- if (WIFEXITED(status)) {
- pctx = kpatch_ptrace_find_thread(proc, pid, 0UL);
- if (pctx == NULL) {
- kperr("got unexpected child '%d' exit\n", pid);
- } else {
- /* It's dead */
- pctx->pid = pctx->running = 0;
- }
- return 1;
- }
-
- ret = ptrace(PTRACE_GETREGS, pid, NULL, &regs);
- if (ret < 0) {
- kplogerror("can't get regs %d\n", pid);
- return -1;
- }
-
- pctx = kpatch_ptrace_find_thread(proc, pid, regs.rip);
-
- if (pctx == NULL) {
- /* We either don't know anything about this thread or
- * even worse -- we stopped it in the wrong place.
- * Bail out.
- */
- pctx = kpatch_ptrace_find_thread(proc, pid, 0);
- if (pctx != NULL)
- pctx->running = 0;
-
- /* TODO: fix the latter by SINGLESTEPping such a thread with
- * the original instruction in place */
- kperr("the thread ran out: %d, rip = %llx, expected = %lx\n", pid,
- regs.rip, pctx->execute_until);
- errno = ESRCH;
- return -1;
- }
-
- pctx->running = 0;
-
- /* Restore thread registers, pctx is now valid */
- kpdebug("Got thread %d at %llx\n", pctx->pid,
- regs.rip - BREAK_INSN_LENGTH);
-
- regs.rip = pctx->execute_until;
-
- ret = ptrace(PTRACE_SETREGS, pctx->pid, NULL, &regs);
- if (ret < 0) {
- kplogerror("can't set regs - %d\n", pctx->pid);
- return -1;
- }
-
- return 1;
-}
-
struct breakpoint {
unsigned long addr;
unsigned char orig_code[BREAK_INSN_LENGTH];
@@ -441,7 +315,7 @@ kpatch_ptrace_execute_until(kpatch_process_t *proc,
break;
}
- rv = kpatch_ptrace_waitpid(proc, &timeout, &sigset);
+ rv = kpatch_arch_ptrace_waitpid(proc, &timeout, &sigset);
if (rv < 0)
break;
--
2.23.0
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化