diff --git a/0001-Split-kpatch_storage.c-from-kpatch_user.c.patch b/0001-Split-kpatch_storage.c-from-kpatch_user.c.patch deleted file mode 100644 index 15d986849be11785fb459d0fbfe51551e034eecc..0000000000000000000000000000000000000000 --- a/0001-Split-kpatch_storage.c-from-kpatch_user.c.patch +++ /dev/null @@ -1,1149 +0,0 @@ -From 252f1bdb9a5ab1c1793e213f97389d79e55838b3 Mon Sep 17 00:00:00 2001 -From: Roman Rashchupkin -Date: Wed, 17 Jan 2018 13:34:50 +0300 -Subject: [PATCH 01/89] Split kpatch_storage.c from kpatch_user.c - ---- - src/Makefile | 4 +- - src/kpatch_storage.c | 488 +++++++++++++++++++++++++++++++++++++++++++ - src/kpatch_storage.h | 66 ++++++ - src/kpatch_user.c | 482 +----------------------------------------- - src/kpatch_user.h | 39 ---- - 5 files changed, 557 insertions(+), 522 deletions(-) - create mode 100644 src/kpatch_storage.c - create mode 100644 src/kpatch_storage.h - -diff --git a/src/Makefile b/src/Makefile -index 72ec073..c008535 100644 ---- a/src/Makefile -+++ b/src/Makefile -@@ -35,8 +35,8 @@ kpatch_make: kpatch_make.o - LIBUNWIND_LIBS := $(shell pkg-config --libs libunwind libunwind-ptrace) - - --libcare-ctl: kpatch_user.o kpatch_elf.o kpatch_ptrace.o kpatch_coro.o rbtree.o kpatch_log.o --libcare-ctl: kpatch_process.o kpatch_common.o -+libcare-ctl: kpatch_user.o kpatch_storage.o kpatch_elf.o kpatch_ptrace.o kpatch_coro.o -+libcare-ctl: kpatch_process.o kpatch_common.o rbtree.o kpatch_log.o - libcare-ctl: LDLIBS += -lelf -lrt $(LIBUNWIND_LIBS) - - libcare-client: libcare-client.o -diff --git a/src/kpatch_storage.c b/src/kpatch_storage.c -new file mode 100644 -index 0000000..a466460 ---- /dev/null -+++ b/src/kpatch_storage.c -@@ -0,0 +1,488 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "kpatch_storage.h" -+#include "kpatch_file.h" -+#include "kpatch_common.h" -+#include "kpatch_elf.h" -+#include "kpatch_ptrace.h" -+#include "list.h" -+#include "kpatch_log.h" -+ -+ -+/***************************************************************************** -+ * Patch storage subroutines. -+ ****************************************************************************/ -+ -+static int -+patch_file_verify(struct kp_file *kpfile) -+{ -+ GElf_Ehdr *hdr; -+ struct kpatch_file *k = kpfile->patch; -+ ssize_t size = kpfile->size; -+ -+ kpdebug("Verifying patch for '%s'...", k->modulename); -+ -+ if (memcmp(k->magic, KPATCH_FILE_MAGIC1, sizeof(k->magic))) { -+ kperr("'%s' patch is invalid: Invalid magic.\n", -+ k->modulename); -+ return -1; -+ } -+ if (k->total_size > size) { -+ kperr("'%s' patch is invalid: Invalid size: %u/%ld.\n", -+ k->modulename, k->total_size, size); -+ return -1; -+ } -+ hdr = (void *)k + k->kpatch_offset; -+ if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) || -+ hdr->e_type != ET_REL || -+ hdr->e_shentsize != sizeof(GElf_Shdr)) { -+ kperr("'%s' patch is invalid: Wrong ELF header or not ET_REL\n", -+ k->modulename); -+ return -1; -+ } -+ kpdebug("OK\n"); -+ return 1; -+} -+ -+int storage_init(kpatch_storage_t *storage, -+ const char *fname) -+{ -+ int patch_fd = -1; -+ struct stat stat = { .st_mode = 0 }; -+ -+ if (fname != NULL) { -+ patch_fd = open(fname, O_RDONLY | O_CLOEXEC); -+ if (patch_fd < 0) -+ goto out_err; -+ -+ if (fstat(patch_fd, &stat) < 0) -+ goto out_close; -+ } -+ -+ storage->patch_fd = patch_fd; -+ storage->is_patch_dir = S_ISDIR(stat.st_mode); -+ storage->path = NULL; -+ -+ if (storage->is_patch_dir) { -+ rb_init(&storage->tree); -+ } else { -+ int ret; -+ -+ ret = kpatch_open_fd(storage->patch_fd, &storage->patch.kpfile); -+ if (ret < 0) -+ goto out_close; -+ -+ ret = patch_file_verify(&storage->patch.kpfile); -+ if (ret < 0) { -+ kpatch_close_file(&storage->patch.kpfile); -+ goto out_close; -+ } -+ strcpy(storage->patch.buildid, storage->patch.kpfile.patch->uname); -+ } -+ -+ storage->path = strdup(fname); -+ -+ return 0; -+ -+out_close: -+ close(patch_fd); -+out_err: -+ kplogerror("cannot open storage '%s'\n", fname); -+ return -1; -+} -+ -+static void -+free_storage_patch_cb(struct rb_node *node) -+{ -+ struct kpatch_storage_patch *patch; -+ -+ patch = rb_entry(node, struct kpatch_storage_patch, node); -+ kpatch_close_file(&patch->kpfile); -+ -+ free(patch->desc); -+ free(patch); -+} -+ -+void storage_free(kpatch_storage_t *storage) -+{ -+ close(storage->patch_fd); -+ if (storage->is_patch_dir) -+ rb_destroy(&storage->tree, free_storage_patch_cb); -+ free(storage->path); -+} -+ -+static int -+cmp_buildid(struct rb_node *node, unsigned long key) -+{ -+ const char *bid = (const char *)key; -+ struct kpatch_storage_patch *patch; -+ -+ patch = rb_entry(node, struct kpatch_storage_patch, node); -+ -+ return strcmp(patch->buildid, bid); -+} -+ -+#define PATCHLEVEL_TEMPLATE_NUM 0 -+ -+static char *pathtemplates[] = { -+ "%s/latest/kpatch.bin", -+ "%s.kpatch" -+}; -+ -+static int -+readlink_patchlevel(int dirfd, const char *fname) -+{ -+ ssize_t r; -+ char buf[32]; -+ -+ *strrchr(fname, '/') = '\0'; -+ r = readlinkat(dirfd, fname, buf, sizeof(buf)); -+ if (r > 0 && r < 32) { -+ buf[r] = '\0'; -+ return atoi(buf); -+ } else if (r >= 32) { -+ r = -1; -+ errno = ERANGE; -+ } -+ -+ kplogerror("can't readlink '%s' to find patchlevel\n", -+ fname); -+ return -1; -+} -+ -+static inline int -+storage_open_patch(kpatch_storage_t *storage, -+ const char *buildid, -+ struct kpatch_storage_patch* patch) -+{ -+ char fname[96]; -+ int i, rv; -+ -+ for (i = 0; i < ARRAY_SIZE(pathtemplates); i++) { -+ sprintf(fname, pathtemplates[i], buildid); -+ -+ rv = kpatch_openat_file(storage->patch_fd, fname, &patch->kpfile); -+ if (rv == 0) { -+ rv = patch_file_verify(&patch->kpfile); -+ -+ if (rv < 0) -+ kpatch_close_file(&patch->kpfile); -+ else -+ rv = PATCH_FOUND; -+ break; -+ } -+ } -+ -+ if (rv == PATCH_FOUND && i == PATCHLEVEL_TEMPLATE_NUM) { -+ rv = readlink_patchlevel(storage->patch_fd, fname); -+ if (rv < 0) { -+ rv = PATCH_OPEN_ERROR; -+ kpatch_close_file(&patch->kpfile); -+ } else { -+ patch->patchlevel = rv; -+ patch->kpfile.patch->user_level = patch->patchlevel; -+ rv = PATCH_FOUND; -+ } -+ -+ } -+ -+ return rv; -+} -+ -+static inline int -+storage_stat_patch(kpatch_storage_t *storage, -+ const char *buildid, -+ struct kpatch_storage_patch* patch) -+{ -+ char fname[96]; -+ struct stat buf; -+ int i, rv; -+ -+ for (i = 0; i < ARRAY_SIZE(pathtemplates); i++) { -+ sprintf(fname, pathtemplates[i], buildid); -+ -+ rv = fstatat(storage->patch_fd, fname, &buf, /* flags */ 0); -+ -+ if (rv == 0) { -+ rv = PATCH_FOUND; -+ patch->kpfile.size = buf.st_size; -+ break; -+ } else if (rv < 0 && errno == ENOENT) { -+ rv = PATCH_NOT_FOUND; -+ } -+ } -+ -+ if (rv == PATCH_FOUND && i == PATCHLEVEL_TEMPLATE_NUM) { -+ rv = readlink_patchlevel(storage->patch_fd, fname); -+ if (rv < 0) { -+ rv = PATCH_OPEN_ERROR; -+ } else { -+ patch->patchlevel = rv; -+ rv = PATCH_FOUND; -+ } -+ } -+ -+ return rv; -+} -+ -+/* -+ * TODO(pboldin) I duplicate a lot of code kernel has for filesystems already. -+ * Should we avoid this caching at all? -+ */ -+#define ERR_PATCH ((struct kpatch_storage_patch *)1) -+static struct kpatch_storage_patch * -+storage_get_patch(kpatch_storage_t *storage, const char *buildid, -+ int load) -+{ -+ struct kpatch_storage_patch *patch = NULL; -+ struct rb_node *node; -+ int rv; -+ -+ if (!storage->is_patch_dir) { -+ if (!strcmp(storage->patch.buildid, buildid)) { -+ return &storage->patch; -+ } -+ return NULL; -+ } -+ -+ /* Look here, could be loaded already */ -+ node = rb_search_node(&storage->tree, cmp_buildid, -+ (unsigned long)buildid); -+ if (node != NULL) -+ return rb_entry(node, struct kpatch_storage_patch, node); -+ -+ /* OK, look at the filesystem */ -+ patch = malloc(sizeof(*patch)); -+ if (patch == NULL) -+ return ERR_PATCH; -+ -+ memset(patch, 0, sizeof(*patch)); -+ patch->patchlevel = -1; -+ init_kp_file(&patch->kpfile); -+ -+ if (load) -+ rv = storage_open_patch(storage, buildid, patch); -+ else -+ rv = storage_stat_patch(storage, buildid, patch); -+ -+ if (rv == PATCH_OPEN_ERROR) { -+ free(patch); -+ return ERR_PATCH; -+ } -+ -+ strcpy(patch->buildid, buildid); -+ -+ rb_insert_node(&storage->tree, -+ &patch->node, -+ cmp_buildid, -+ (unsigned long)patch->buildid); -+ -+ return patch; -+} -+ -+int storage_patch_found(struct kpatch_storage_patch *patch) -+{ -+ return patch && patch->kpfile.size >= 0; -+} -+ -+static int -+storage_load_patch(kpatch_storage_t *storage, const char *buildid, -+ struct kp_file **pkpfile) -+{ -+ struct kpatch_storage_patch *patch = NULL; -+ -+ if (pkpfile == NULL) { -+ kperr("pkpfile == NULL\n"); -+ return PATCH_OPEN_ERROR; -+ } -+ -+ patch = storage_get_patch(storage, buildid, /* load */ 1); -+ if (patch == ERR_PATCH) -+ return PATCH_OPEN_ERROR; -+ if (patch == NULL) -+ return PATCH_NOT_FOUND; -+ -+ *pkpfile = &patch->kpfile; -+ -+ return storage_patch_found(patch) ? PATCH_FOUND : PATCH_NOT_FOUND; -+} -+ -+int storage_have_patch(kpatch_storage_t *storage, const char *buildid, -+ struct kpatch_storage_patch **ppatch) -+{ -+ struct kpatch_storage_patch *patch = NULL; -+ -+ if (ppatch) -+ *ppatch = NULL; -+ -+ patch = storage_get_patch(storage, buildid, /* load */ 0); -+ if (patch == ERR_PATCH) -+ return PATCH_OPEN_ERROR; -+ -+ if (!storage_patch_found(patch)) -+ return PATCH_NOT_FOUND; -+ -+ if (ppatch) -+ *ppatch = patch; -+ return PATCH_FOUND; -+} -+ -+char *storage_get_description(kpatch_storage_t *storage, -+ struct kpatch_storage_patch *patch) -+{ -+ char *desc = NULL; -+ char path[PATH_MAX]; -+ int fd, rv, alloc = 0, sz = 0; -+ -+ if (!storage->is_patch_dir) -+ return NULL; -+ -+ if (patch->desc) -+ return patch->desc; -+ -+ sprintf(path, "%s/%d/description", patch->buildid, patch->patchlevel); -+ fd = openat(storage->patch_fd, path, O_RDONLY); -+ if (fd == -1) -+ return NULL; -+ -+ while (1) { -+ if (sz + 1024 >= alloc) { -+ char *olddesc = desc; -+ alloc += PAGE_SIZE; -+ -+ desc = malloc(alloc); -+ -+ if (olddesc != NULL) { -+ memcpy(desc, olddesc, sz); -+ free(olddesc); -+ } -+ -+ olddesc = desc; -+ } -+ -+ rv = read(fd, desc + sz, alloc - sz); -+ if (rv == -1 && errno == EINTR) -+ continue; -+ -+ if (rv == -1) -+ goto err_free; -+ -+ if (rv == 0) -+ break; -+ -+ sz += rv; -+ } -+ -+ patch->desc = desc; -+ -+ return desc; -+ -+err_free: -+ free(desc); -+ close(fd); -+ return NULL; -+} -+ -+int storage_lookup_patches(kpatch_storage_t *storage, kpatch_process_t *proc) -+{ -+ struct kp_file *pkpfile; -+ struct object_file *o; -+ const char *bid; -+ int found = 0, ret; -+ -+ list_for_each_entry(o, &proc->objs, list) { -+ if (!o->is_elf || is_kernel_object_name(o->name)) -+ continue; -+ -+ bid = kpatch_get_buildid(o); -+ if (bid == NULL) { -+ kpinfo("can't get buildid for %s\n", -+ o->name); -+ continue; -+ } -+ -+ ret = storage_load_patch(storage, bid, &pkpfile); -+ if (ret == PATCH_OPEN_ERROR) { -+ if (errno != ENOENT) -+ kplogerror("error finding patch for %s (%s)\n", -+ o->name, bid); -+ continue; -+ } -+ -+ if (ret == PATCH_FOUND) { -+ o->skpfile = pkpfile; -+ found++; -+ } -+ } -+ -+ kpinfo("%d object(s) have valid patch(es)\n", found); -+ -+ kpdebug("Object files dump:\n"); -+ list_for_each_entry(o, &proc->objs, list) -+ kpatch_object_dump(o); -+ -+ return found; -+} -+ -+static int -+storage_execute_script(kpatch_storage_t *storage, -+ kpatch_process_t *proc, -+ const char *name) -+{ -+ int childpid, rv = 0, status; -+ char pidbuf[16], pathbuf[PATH_MAX]; -+ -+ if (!storage->is_patch_dir) -+ return 0; -+ -+ sprintf(pathbuf, "%s/%s", storage->path, name); -+ -+ rv = access(pathbuf, X_OK); -+ /* No file -- no problems */ -+ if (rv < 0) -+ return errno == ENOENT ? 0 : -1; -+ -+ sprintf(pidbuf, "%d", proc->pid); -+ -+ childpid = fork(); -+ if (childpid == 0) { -+ rv = execl(pathbuf, name, pidbuf, NULL); -+ if (rv < 0) -+ kplogerror("execl failed\n"); -+ exit(EXIT_FAILURE); -+ } else { -+ rv = waitpid(childpid, &status, 0); -+ if (rv < 0) -+ kplogerror("waitpid failed for %d\n", childpid); -+ -+ if (WIFEXITED(status)) -+ rv = WEXITSTATUS(status); -+ else if (WIFSIGNALED(status)) -+ rv = WTERMSIG(status); -+ if (rv) -+ kperr("child script failed %d\n", rv); -+ } -+ -+ return -rv; -+} -+ -+int storage_execute_before_script(kpatch_storage_t *storage, kpatch_process_t *proc) -+{ -+ return storage_execute_script(storage, proc, "before"); -+} -+ -+int storage_execute_after_script(kpatch_storage_t *storage, kpatch_process_t *proc) -+{ -+ return storage_execute_script(storage, proc, "after"); -+} -+ -diff --git a/src/kpatch_storage.h b/src/kpatch_storage.h -new file mode 100644 -index 0000000..eb8064b ---- /dev/null -+++ b/src/kpatch_storage.h -@@ -0,0 +1,66 @@ -+#ifndef __KPATCH_STORAGE__ -+#define __KPATCH_STORAGE__ -+ -+#include "kpatch_common.h" -+#include "kpatch_file.h" -+#include "kpatch_process.h" -+#include "rbtree.h" -+ -+struct kpatch_storage_patch { -+ /* Pointer to the object's patch (if any) */ -+ struct kp_file kpfile; -+ -+ /* Build id kept here for negative caching */ -+ char buildid[41]; -+ -+ /* Patch level */ -+ int patchlevel; -+ -+ /* Description cache */ -+ char *desc; -+ -+ /* Node for rb_root */ -+ struct rb_node node; -+}; -+ -+struct kpatch_storage { -+ /* Patch storage path */ -+ char *path; -+ -+ /* Patch file (or directory) descriptor */ -+ int patch_fd; -+ -+ /* Is patch_fd a directory or a file? */ -+ char is_patch_dir; -+ -+ union { -+ /* Tree with BuildID keyed `kp_file's, -+ * is_patch_dir = 1 */ -+ struct rb_root tree; -+ -+ /* A single file, is_patch_dir = 0 */ -+ struct kpatch_storage_patch patch; -+ }; -+}; -+ -+typedef struct kpatch_storage kpatch_storage_t; -+ -+int storage_init(kpatch_storage_t *storage, -+ const char *fname); -+void storage_free(kpatch_storage_t *storage); -+ -+enum { -+ PATCH_OPEN_ERROR = -1, -+ PATCH_NOT_FOUND = 0, -+ PATCH_FOUND = 1, -+}; -+int storage_lookup_patches(kpatch_storage_t *storage, kpatch_process_t *proc); -+int storage_have_patch(kpatch_storage_t *storage, const char *buildid, -+ struct kpatch_storage_patch **ppatch); -+int storage_patch_found(struct kpatch_storage_patch *patch); -+int storage_execute_before_script(kpatch_storage_t *storage, kpatch_process_t *proc); -+int storage_execute_after_script(kpatch_storage_t *storage, kpatch_process_t *proc); -+char *storage_get_description(kpatch_storage_t *storage, -+ struct kpatch_storage_patch *patch); -+ -+#endif -diff --git a/src/kpatch_user.c b/src/kpatch_user.c -index 21a90ab..672b4d4 100644 ---- a/src/kpatch_user.c -+++ b/src/kpatch_user.c -@@ -19,6 +19,7 @@ - #include - - #include "kpatch_user.h" -+#include "kpatch_storage.h" - #include "kpatch_process.h" - #include "kpatch_file.h" - #include "kpatch_common.h" -@@ -41,487 +42,6 @@ typedef int (callback_t)(int pid, void *data); - static int - processes_do(int pid, callback_t callback, void *data); - --/***************************************************************************** -- * Patch storage subroutines. -- ****************************************************************************/ -- --static int --patch_file_verify(struct kp_file *kpfile) --{ -- GElf_Ehdr *hdr; -- struct kpatch_file *k = kpfile->patch; -- ssize_t size = kpfile->size; -- -- kpdebug("Verifying patch for '%s'...", k->modulename); -- -- if (memcmp(k->magic, KPATCH_FILE_MAGIC1, sizeof(k->magic))) { -- kperr("'%s' patch is invalid: Invalid magic.\n", -- k->modulename); -- return -1; -- } -- if (k->total_size > size) { -- kperr("'%s' patch is invalid: Invalid size: %u/%ld.\n", -- k->modulename, k->total_size, size); -- return -1; -- } -- hdr = (void *)k + k->kpatch_offset; -- if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) || -- hdr->e_type != ET_REL || -- hdr->e_shentsize != sizeof(GElf_Shdr)) { -- kperr("'%s' patch is invalid: Wrong ELF header or not ET_REL\n", -- k->modulename); -- return -1; -- } -- kpdebug("OK\n"); -- return 1; --} -- --static int --storage_init(kpatch_storage_t *storage, -- const char *fname) --{ -- int patch_fd = -1; -- struct stat stat = { .st_mode = 0 }; -- -- if (fname != NULL) { -- patch_fd = open(fname, O_RDONLY | O_CLOEXEC); -- if (patch_fd < 0) -- goto out_err; -- -- if (fstat(patch_fd, &stat) < 0) -- goto out_close; -- } -- -- storage->patch_fd = patch_fd; -- storage->is_patch_dir = S_ISDIR(stat.st_mode); -- storage->path = NULL; -- -- if (storage->is_patch_dir) { -- rb_init(&storage->tree); -- } else { -- int ret; -- -- ret = kpatch_open_fd(storage->patch_fd, &storage->patch.kpfile); -- if (ret < 0) -- goto out_close; -- -- ret = patch_file_verify(&storage->patch.kpfile); -- if (ret < 0) { -- kpatch_close_file(&storage->patch.kpfile); -- goto out_close; -- } -- strcpy(storage->patch.buildid, storage->patch.kpfile.patch->uname); -- } -- -- storage->path = strdup(fname); -- -- return 0; -- --out_close: -- close(patch_fd); --out_err: -- kplogerror("cannot open storage '%s'\n", fname); -- return -1; --} -- --static void --free_storage_patch_cb(struct rb_node *node) --{ -- struct kpatch_storage_patch *patch; -- -- patch = rb_entry(node, struct kpatch_storage_patch, node); -- kpatch_close_file(&patch->kpfile); -- -- free(patch->desc); -- free(patch); --} -- --static void --storage_free(kpatch_storage_t *storage) --{ -- close(storage->patch_fd); -- if (storage->is_patch_dir) -- rb_destroy(&storage->tree, free_storage_patch_cb); -- free(storage->path); --} -- --static int --cmp_buildid(struct rb_node *node, unsigned long key) --{ -- const char *bid = (const char *)key; -- struct kpatch_storage_patch *patch; -- -- patch = rb_entry(node, struct kpatch_storage_patch, node); -- -- return strcmp(patch->buildid, bid); --} -- --#define PATCHLEVEL_TEMPLATE_NUM 0 -- --static char *pathtemplates[] = { -- "%s/latest/kpatch.bin", -- "%s.kpatch" --}; -- --static int --readlink_patchlevel(int dirfd, const char *fname) --{ -- ssize_t r; -- char buf[32]; -- -- *strrchr(fname, '/') = '\0'; -- r = readlinkat(dirfd, fname, buf, sizeof(buf)); -- if (r > 0 && r < 32) { -- buf[r] = '\0'; -- return atoi(buf); -- } else if (r >= 32) { -- r = -1; -- errno = ERANGE; -- } -- -- kplogerror("can't readlink '%s' to find patchlevel\n", -- fname); -- return -1; --} -- --enum { -- PATCH_OPEN_ERROR = -1, -- PATCH_NOT_FOUND = 0, -- PATCH_FOUND = 1, --}; -- --static inline int --storage_open_patch(kpatch_storage_t *storage, -- const char *buildid, -- struct kpatch_storage_patch* patch) --{ -- char fname[96]; -- int i, rv; -- -- for (i = 0; i < ARRAY_SIZE(pathtemplates); i++) { -- sprintf(fname, pathtemplates[i], buildid); -- -- rv = kpatch_openat_file(storage->patch_fd, fname, &patch->kpfile); -- if (rv == 0) { -- rv = patch_file_verify(&patch->kpfile); -- -- if (rv < 0) -- kpatch_close_file(&patch->kpfile); -- else -- rv = PATCH_FOUND; -- break; -- } -- } -- -- if (rv == PATCH_FOUND && i == PATCHLEVEL_TEMPLATE_NUM) { -- rv = readlink_patchlevel(storage->patch_fd, fname); -- if (rv < 0) { -- rv = PATCH_OPEN_ERROR; -- kpatch_close_file(&patch->kpfile); -- } else { -- patch->patchlevel = rv; -- patch->kpfile.patch->user_level = patch->patchlevel; -- rv = PATCH_FOUND; -- } -- -- } -- -- return rv; --} -- --static inline int --storage_stat_patch(kpatch_storage_t *storage, -- const char *buildid, -- struct kpatch_storage_patch* patch) --{ -- char fname[96]; -- struct stat buf; -- int i, rv; -- -- for (i = 0; i < ARRAY_SIZE(pathtemplates); i++) { -- sprintf(fname, pathtemplates[i], buildid); -- -- rv = fstatat(storage->patch_fd, fname, &buf, /* flags */ 0); -- -- if (rv == 0) { -- rv = PATCH_FOUND; -- patch->kpfile.size = buf.st_size; -- break; -- } else if (rv < 0 && errno == ENOENT) { -- rv = PATCH_NOT_FOUND; -- } -- } -- -- if (rv == PATCH_FOUND && i == PATCHLEVEL_TEMPLATE_NUM) { -- rv = readlink_patchlevel(storage->patch_fd, fname); -- if (rv < 0) { -- rv = PATCH_OPEN_ERROR; -- } else { -- patch->patchlevel = rv; -- rv = PATCH_FOUND; -- } -- } -- -- return rv; --} -- --/* -- * TODO(pboldin) I duplicate a lot of code kernel has for filesystems already. -- * Should we avoid this caching at all? -- */ --#define ERR_PATCH ((struct kpatch_storage_patch *)1) --static struct kpatch_storage_patch * --storage_get_patch(kpatch_storage_t *storage, const char *buildid, -- int load) --{ -- struct kpatch_storage_patch *patch = NULL; -- struct rb_node *node; -- int rv; -- -- if (!storage->is_patch_dir) { -- if (!strcmp(storage->patch.buildid, buildid)) { -- return &storage->patch; -- } -- return NULL; -- } -- -- /* Look here, could be loaded already */ -- node = rb_search_node(&storage->tree, cmp_buildid, -- (unsigned long)buildid); -- if (node != NULL) -- return rb_entry(node, struct kpatch_storage_patch, node); -- -- /* OK, look at the filesystem */ -- patch = malloc(sizeof(*patch)); -- if (patch == NULL) -- return ERR_PATCH; -- -- memset(patch, 0, sizeof(*patch)); -- patch->patchlevel = -1; -- init_kp_file(&patch->kpfile); -- -- if (load) -- rv = storage_open_patch(storage, buildid, patch); -- else -- rv = storage_stat_patch(storage, buildid, patch); -- -- if (rv == PATCH_OPEN_ERROR) { -- free(patch); -- return ERR_PATCH; -- } -- -- strcpy(patch->buildid, buildid); -- -- rb_insert_node(&storage->tree, -- &patch->node, -- cmp_buildid, -- (unsigned long)patch->buildid); -- -- return patch; --} -- --static int --storage_patch_found(struct kpatch_storage_patch *patch) --{ -- return patch && patch->kpfile.size >= 0; --} -- --static int --storage_load_patch(kpatch_storage_t *storage, const char *buildid, -- struct kp_file **pkpfile) --{ -- struct kpatch_storage_patch *patch = NULL; -- -- if (pkpfile == NULL) { -- kperr("pkpfile == NULL\n"); -- return PATCH_OPEN_ERROR; -- } -- -- patch = storage_get_patch(storage, buildid, /* load */ 1); -- if (patch == ERR_PATCH) -- return PATCH_OPEN_ERROR; -- if (patch == NULL) -- return PATCH_NOT_FOUND; -- -- *pkpfile = &patch->kpfile; -- -- return storage_patch_found(patch) ? PATCH_FOUND : PATCH_NOT_FOUND; --} -- --static int --storage_have_patch(kpatch_storage_t *storage, const char *buildid, -- struct kpatch_storage_patch **ppatch) --{ -- struct kpatch_storage_patch *patch = NULL; -- -- if (ppatch) -- *ppatch = NULL; -- -- patch = storage_get_patch(storage, buildid, /* load */ 0); -- if (patch == ERR_PATCH) -- return PATCH_OPEN_ERROR; -- -- if (!storage_patch_found(patch)) -- return PATCH_NOT_FOUND; -- -- if (ppatch) -- *ppatch = patch; -- return PATCH_FOUND; --} -- --static char * --storage_get_description(kpatch_storage_t *storage, -- struct kpatch_storage_patch *patch) --{ -- char *desc = NULL; -- char path[PATH_MAX]; -- int fd, rv, alloc = 0, sz = 0; -- -- if (!storage->is_patch_dir) -- return NULL; -- -- if (patch->desc) -- return patch->desc; -- -- sprintf(path, "%s/%d/description", patch->buildid, patch->patchlevel); -- fd = openat(storage->patch_fd, path, O_RDONLY); -- if (fd == -1) -- return NULL; -- -- while (1) { -- if (sz + 1024 >= alloc) { -- char *olddesc = desc; -- alloc += PAGE_SIZE; -- -- desc = malloc(alloc); -- -- if (olddesc != NULL) { -- memcpy(desc, olddesc, sz); -- free(olddesc); -- } -- -- olddesc = desc; -- } -- -- rv = read(fd, desc + sz, alloc - sz); -- if (rv == -1 && errno == EINTR) -- continue; -- -- if (rv == -1) -- goto err_free; -- -- if (rv == 0) -- break; -- -- sz += rv; -- } -- -- patch->desc = desc; -- -- return desc; -- --err_free: -- free(desc); -- close(fd); -- return NULL; --} -- --static int --storage_lookup_patches(kpatch_storage_t *storage, kpatch_process_t *proc) --{ -- struct kp_file *pkpfile; -- struct object_file *o; -- const char *bid; -- int found = 0, ret; -- -- list_for_each_entry(o, &proc->objs, list) { -- if (!o->is_elf || is_kernel_object_name(o->name)) -- continue; -- -- bid = kpatch_get_buildid(o); -- if (bid == NULL) { -- kpinfo("can't get buildid for %s\n", -- o->name); -- continue; -- } -- -- ret = storage_load_patch(storage, bid, &pkpfile); -- if (ret == PATCH_OPEN_ERROR) { -- if (errno != ENOENT) -- kplogerror("error finding patch for %s (%s)\n", -- o->name, bid); -- continue; -- } -- -- if (ret == PATCH_FOUND) { -- o->skpfile = pkpfile; -- found++; -- } -- } -- -- kpinfo("%d object(s) have valid patch(es)\n", found); -- -- kpdebug("Object files dump:\n"); -- list_for_each_entry(o, &proc->objs, list) -- kpatch_object_dump(o); -- -- return found; --} -- --static int --storage_execute_script(kpatch_storage_t *storage, -- kpatch_process_t *proc, -- const char *name) --{ -- int childpid, rv = 0, status; -- char pidbuf[16], pathbuf[PATH_MAX]; -- -- if (!storage->is_patch_dir) -- return 0; -- -- sprintf(pathbuf, "%s/%s", storage->path, name); -- -- rv = access(pathbuf, X_OK); -- /* No file -- no problems */ -- if (rv < 0) -- return errno == ENOENT ? 0 : -1; -- -- sprintf(pidbuf, "%d", proc->pid); -- -- childpid = fork(); -- if (childpid == 0) { -- rv = execl(pathbuf, name, pidbuf, NULL); -- if (rv < 0) -- kplogerror("execl failed\n"); -- exit(EXIT_FAILURE); -- } else { -- rv = waitpid(childpid, &status, 0); -- if (rv < 0) -- kplogerror("waitpid failed for %d\n", childpid); -- -- if (WIFEXITED(status)) -- rv = WEXITSTATUS(status); -- else if (WIFSIGNALED(status)) -- rv = WTERMSIG(status); -- if (rv) -- kperr("child script failed %d\n", rv); -- } -- -- return -rv; --} -- --static int --storage_execute_before_script(kpatch_storage_t *storage, kpatch_process_t *proc) --{ -- return storage_execute_script(storage, proc, "before"); --} -- --static int --storage_execute_after_script(kpatch_storage_t *storage, kpatch_process_t *proc) --{ -- return storage_execute_script(storage, proc, "after"); --} -- - enum { - ACTION_APPLY_PATCH, - ACTION_UNAPPLY_PATCH -diff --git a/src/kpatch_user.h b/src/kpatch_user.h -index 091c463..c0b52ff 100644 ---- a/src/kpatch_user.h -+++ b/src/kpatch_user.h -@@ -5,45 +5,6 @@ - #include "kpatch_file.h" - #include "rbtree.h" - --struct kpatch_storage_patch { -- /* Pointer to the object's patch (if any) */ -- struct kp_file kpfile; -- -- /* Build id kept here for negative caching */ -- char buildid[41]; -- -- /* Patch level */ -- int patchlevel; -- -- /* Description cache */ -- char *desc; -- -- /* Node for rb_root */ -- struct rb_node node; --}; -- --struct kpatch_storage { -- /* Patch storage path */ -- char *path; -- -- /* Patch file (or directory) descriptor */ -- int patch_fd; -- -- /* Is patch_fd a directory or a file? */ -- char is_patch_dir; -- -- union { -- /* Tree with BuildID keyed `kp_file's, -- * is_patch_dir = 1 */ -- struct rb_root tree; -- -- /* A single file, is_patch_dir = 0 */ -- struct kpatch_storage_patch patch; -- }; --}; -- --typedef struct kpatch_storage kpatch_storage_t; -- - int cmd_patch_user(int argc, char *argv[]); - int cmd_unpatch_user(int argc, char *argv[]); - --- -2.23.0 - diff --git a/0002-Split-kpatch_patch.c-from-kpatch_user.c.patch b/0002-Split-kpatch_patch.c-from-kpatch_user.c.patch deleted file mode 100644 index 922b0554047bce8ad1c766d4f7d202327648f75c..0000000000000000000000000000000000000000 --- a/0002-Split-kpatch_patch.c-from-kpatch_user.c.patch +++ /dev/null @@ -1,1633 +0,0 @@ -From 03cbe62f9376144991f5593c89500174b86341e7 Mon Sep 17 00:00:00 2001 -From: Roman Rashchupkin -Date: Wed, 17 Jan 2018 13:45:34 +0300 -Subject: [PATCH 02/89] Split kpatch_patch.c from kpatch_user.c - ---- - .gitignore | 1 + - src/Makefile | 2 +- - src/kpatch_patch.c | 761 +++++++++++++++++++++++++++++++++++++++++++++ - src/kpatch_patch.h | 28 ++ - src/kpatch_user.c | 757 +------------------------------------------- - 5 files changed, 792 insertions(+), 757 deletions(-) - create mode 100644 .gitignore - create mode 100644 src/kpatch_patch.c - create mode 100644 src/kpatch_patch.h - -diff --git a/.gitignore b/.gitignore -new file mode 100644 -index 0000000..5761abc ---- /dev/null -+++ b/.gitignore -@@ -0,0 +1 @@ -+*.o -diff --git a/src/Makefile b/src/Makefile -index c008535..cd766e1 100644 ---- a/src/Makefile -+++ b/src/Makefile -@@ -35,7 +35,7 @@ kpatch_make: kpatch_make.o - LIBUNWIND_LIBS := $(shell pkg-config --libs libunwind libunwind-ptrace) - - --libcare-ctl: kpatch_user.o kpatch_storage.o kpatch_elf.o kpatch_ptrace.o kpatch_coro.o -+libcare-ctl: kpatch_user.o kpatch_storage.o kpatch_patch.c kpatch_elf.o kpatch_ptrace.o kpatch_coro.o - libcare-ctl: kpatch_process.o kpatch_common.o rbtree.o kpatch_log.o - libcare-ctl: LDLIBS += -lelf -lrt $(LIBUNWIND_LIBS) - -diff --git a/src/kpatch_patch.c b/src/kpatch_patch.c -new file mode 100644 -index 0000000..e32c702 ---- /dev/null -+++ b/src/kpatch_patch.c -@@ -0,0 +1,761 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "kpatch_patch.h" -+#include "kpatch_user.h" -+#include "kpatch_storage.h" -+#include "kpatch_process.h" -+#include "kpatch_file.h" -+#include "kpatch_common.h" -+#include "kpatch_elf.h" -+#include "kpatch_ptrace.h" -+#include "list.h" -+#include "kpatch_log.h" -+ -+ -+static inline int -+is_addr_in_info(unsigned long addr, -+ struct kpatch_info *info, -+ int direction) -+{ -+#define IS_ADDR_IN_HALF_INTERVAL(addr, start, len) ((addr >= start) && (addr < start + len)) -+ if (direction == ACTION_APPLY_PATCH) -+ return IS_ADDR_IN_HALF_INTERVAL(addr, info->daddr, info->dlen); -+ if (direction == ACTION_UNAPPLY_PATCH) -+ return IS_ADDR_IN_HALF_INTERVAL(addr, info->saddr, info->slen); -+ return 0; -+} -+ -+static void print_address_closest_func(int log_level, struct object_file *o, unw_cursor_t *cur, int in_oldpatch) -+{ -+ unsigned long address, offset; -+ char fname[128]; -+ -+ unw_get_reg(cur, UNW_REG_IP, &address); -+ -+ if (in_oldpatch) -+ if (address >= o->kpta && address < o->kpta + o->kpfile.size) { -+ kplog(log_level, "\t[0x%lx](patch)\n", address); -+ return; -+ } -+ -+ if (!unw_get_proc_name(cur, fname, 128, &offset)) -+ kplog(log_level, "\t[0x%lx] %s+0x%lx\n", address, fname, offset); -+ else -+ kplog(log_level, "\t[0x%lx]\n", address); -+} -+ -+/** -+ * Verify that the function from file `o' is safe to be patched. -+ * -+ * If retip is given then the safe address is returned in it. -+ * What is considered a safe address depends on the `paranoid' value. When it -+ * is true, safe address is the upper of ALL functions that do have a patch. -+ * When it is false, safe address is the address of the first function -+ * instruction that have no patch. -+ * -+ * That is, for the call chain from left to right with functions that have -+ * patch marked with '+': -+ * -+ * foo -> bar+ -> baz -> qux+ -+ * -+ * With `paranoid=true' this function will return address of the `bar+' -+ * instruction being executed with *retip pointing to the `foo' instruction -+ * that comes after the call to `bar+'. With `paranoid=false' this function -+ * will return address of the `qux+' instruction being executed with *retip -+ * pointing to the `baz' instruction that comes after call to `qux+'. -+ */ -+static unsigned long -+object_patch_verify_safety_single(struct object_file *o, -+ unw_cursor_t *cur, -+ unsigned long *retip, -+ int paranoid, -+ int direction) -+{ -+ unw_word_t ip; -+ struct kpatch_info *info = o->info; -+ size_t i, ninfo = o->ninfo; -+ int prev = 0, rv; -+ unsigned long last = 0; -+ -+ if (direction != ACTION_APPLY_PATCH && -+ direction != ACTION_UNAPPLY_PATCH) -+ kpfatal("unknown direction"); -+ -+ do { -+ print_address_closest_func(LOG_INFO, o, cur, direction == ACTION_UNAPPLY_PATCH); -+ -+ unw_get_reg(cur, UNW_REG_IP, &ip); -+ -+ for (i = 0; i < ninfo; i++) { -+ if (is_new_func(&info[i])) -+ continue; -+ -+ if (is_addr_in_info((long)ip, &info[i], direction)) { -+ if (direction == ACTION_APPLY_PATCH) -+ last = info[i].daddr; -+ else if (direction == ACTION_UNAPPLY_PATCH) -+ last = info[i].saddr; -+ prev = 1; -+ break; -+ } -+ } -+ -+ if (prev && i == ninfo) { -+ prev = 0; -+ if (retip) -+ *retip = ip; -+ if (!paranoid) -+ break; -+ } -+ -+ rv = unw_step(cur); -+ } while (rv > 0); -+ -+ if (rv < 0) -+ kperr("unw_step = %d\n", rv); -+ -+ return last; -+} -+ -+#define KPATCH_CORO_STACK_UNSAFE (1 << 20) -+ -+static int -+patch_verify_safety(struct object_file *o, -+ unsigned long *retips, -+ int direction) -+{ -+ size_t nr = 0, failed = 0, count = 0; -+ struct kpatch_ptrace_ctx *p; -+ struct kpatch_coro *c; -+ unsigned long retip, ret; -+ unw_cursor_t cur; -+ -+ list_for_each_entry(c, &o->proc->coro.coros, list) { -+ void *ucoro; -+ -+ kpdebug("Verifying safety for coroutine %zd...\n", count); -+ kpinfo("Stacktrace to verify safety for coroutine %zd:\n", count); -+ ucoro = _UCORO_create(c, proc2pctx(o->proc)->pid); -+ if (!ucoro) { -+ kplogerror("can't create unwind coro context\n"); -+ return -1; -+ } -+ -+ ret = unw_init_remote(&cur, o->proc->coro.unwd, ucoro); -+ if (ret) { -+ kplogerror("can't create unwind remote context\n"); -+ _UCORO_destroy(ucoro); -+ return -1; -+ } -+ -+ ret = object_patch_verify_safety_single(o, &cur, NULL, 0, direction); -+ _UCORO_destroy(ucoro); -+ if (ret) { -+ kperr("safety check failed to %lx\n", ret); -+ failed++; -+ } else { -+ kpdebug("OK\n"); -+ } -+ count++; -+ } -+ if (failed) -+ return failed | KPATCH_CORO_STACK_UNSAFE; -+ -+ list_for_each_entry(p, &o->proc->ptrace.pctxs, list) { -+ void *upt; -+ -+ kpdebug("Verifying safety for pid %d...\n", p->pid); -+ kpinfo("Stacktrace to verify safety for pid %d:\n", p->pid); -+ upt = _UPT_create(p->pid); -+ if (!upt) { -+ kplogerror("can't create unwind ptrace context\n"); -+ return -1; -+ } -+ -+ ret = unw_init_remote(&cur, o->proc->ptrace.unwd, upt); -+ if (ret) { -+ kplogerror("can't create unwind remote context\n"); -+ _UPT_destroy(upt); -+ return -1; -+ } -+ -+ ret = object_patch_verify_safety_single(o, &cur, &retip, 0, direction); -+ _UPT_destroy(upt); -+ if (ret) { -+ /* TODO: dump full backtrace, with symbols where possible (shared libs) */ -+ if (retips) { -+ kperr("safety check failed for %lx, will continue until %lx\n", -+ ret, retip); -+ retips[nr] = retip; -+ } else { -+ kperr("safety check failed for %lx\n", ret); -+ errno = -EBUSY; -+ } -+ failed++; -+ } -+ kpdebug("OK\n"); -+ nr++; -+ } -+ -+ return failed; -+} -+ -+/* -+ * Ensure that it is safe to apply/unapply patch for the object file `o`. -+ * -+ * First, we verify the safety of the patch. -+ * -+ * It is safe to apply patch (ACTION_APPLY_PATCH) when no threads or coroutines -+ * are executing the functions to be patched. -+ * -+ * It is safe to unapply patch (ACTION_UNAPPLY_PATCH) when no threads or -+ * coroutines are executing the patched functions. -+ * -+ * If it is not safe to do the action we continue threads execution until they -+ * are out of the functions that we want to patch/unpatch. This is done using -+ * `kpatch_ptrace_execute_until` function with default timeout of 3000 seconds -+ * and checking for action safety again. -+ */ -+static int -+patch_ensure_safety(struct object_file *o, -+ int action) -+{ -+ struct kpatch_ptrace_ctx *p; -+ unsigned long ret, *retips; -+ size_t nr = 0, i; -+ -+ list_for_each_entry(p, &o->proc->ptrace.pctxs, list) -+ nr++; -+ retips = malloc(nr * sizeof(unsigned long)); -+ if (retips == NULL) -+ return -1; -+ -+ memset(retips, 0, nr * sizeof(unsigned long)); -+ -+ ret = patch_verify_safety(o, retips, action); -+ /* -+ * For coroutines we can't "execute until" -+ */ -+ if (ret && !(ret & KPATCH_CORO_STACK_UNSAFE)) { -+ i = 0; -+ list_for_each_entry(p, &o->proc->ptrace.pctxs, list) { -+ p->execute_until = retips[i]; -+ i++; -+ } -+ -+ ret = kpatch_ptrace_execute_until(o->proc, 3000, 0); -+ -+ /* OK, at this point we may have new threads, discover them */ -+ if (ret == 0) -+ ret = kpatch_process_attach(o->proc); -+ if (ret == 0) -+ ret = patch_verify_safety(o, NULL, action); -+ } -+ -+ free(retips); -+ -+ return ret ? -1 : 0; -+} -+ -+/***************************************************************************** -+ * Patch application subroutines -+ ****************************************************************************/ -+/* -+ * This flag is local, i.e. it is never stored to the -+ * patch applied to patient's memory. -+ */ -+#define PATCH_APPLIED (1 << 31) -+ -+#define HUNK_SIZE 5 -+ -+static int -+patch_apply_hunk(struct object_file *o, size_t nhunk) -+{ -+ int ret; -+ char code[HUNK_SIZE] = {0xe9, 0x00, 0x00, 0x00, 0x00}; /* jmp IMM */ -+ struct kpatch_info *info = &o->info[nhunk]; -+ unsigned long pundo; -+ -+ if (is_new_func(info)) -+ return 0; -+ -+ pundo = o->kpta + o->kpfile.patch->user_undo + nhunk * HUNK_SIZE; -+ kpinfo("%s origcode from 0x%lx+0x%x to 0x%lx\n", -+ o->name, info->daddr, HUNK_SIZE, pundo); -+ ret = kpatch_process_memcpy(o->proc, pundo, -+ info->daddr, HUNK_SIZE); -+ if (ret < 0) -+ return ret; -+ -+ kpinfo("%s hunk 0x%lx+0x%x -> 0x%lx+0x%x\n", -+ o->name, info->daddr, info->dlen, info->saddr, info->slen); -+ *(unsigned int *)(code + 1) = (unsigned int)(info->saddr - info->daddr - 5); -+ ret = kpatch_process_mem_write(o->proc, -+ code, -+ info->daddr, -+ sizeof(code)); -+ /* -+ * NOTE(pboldin): This is only stored locally, as information have -+ * been copied to patient's memory already. -+ */ -+ info->flags |= PATCH_APPLIED; -+ return ret ? -1 : 0; -+} -+ -+static int -+duplicate_kp_file(struct object_file *o) -+{ -+ struct kpatch_file *patch; -+ -+ patch = malloc(o->skpfile->size); -+ if (patch == NULL) -+ return -1; -+ -+ memcpy(patch, o->skpfile->patch, o->skpfile->size); -+ o->kpfile.patch = patch; -+ o->kpfile.size = o->skpfile->size; -+ -+ return 0; -+} -+ -+static int -+object_apply_patch(struct object_file *o) -+{ -+ struct kpatch_file *kp; -+ size_t sz, i; -+ int undef, ret; -+ -+ if (o->skpfile == NULL || o->is_patch) -+ return 0; -+ -+ if (o->applied_patch) { -+ kpinfo("Object '%s' already have a patch, not patching\n", -+ o->name); -+ return 0; -+ } -+ -+ ret = duplicate_kp_file(o); -+ if (ret < 0) { -+ kplogerror("can't duplicate kp_file\n"); -+ return -1; -+ } -+ -+ ret = kpatch_elf_load_kpatch_info(o); -+ if (ret < 0) -+ return ret; -+ -+ kp = o->kpfile.patch; -+ -+ sz = ROUND_UP(kp->total_size, 8); -+ undef = kpatch_count_undefined(o); -+ if (undef) { -+ o->jmp_table = kpatch_new_jmp_table(undef); -+ kp->jmp_offset = sz; -+ kpinfo("Jump table %d bytes for %d syms at offset 0x%x\n", -+ o->jmp_table->size, undef, kp->jmp_offset); -+ sz = ROUND_UP(sz + o->jmp_table->size, 128); -+ } -+ -+ kp->user_info = (unsigned long)o->info - -+ (unsigned long)o->kpfile.patch; -+ kp->user_undo = sz; -+ sz = ROUND_UP(sz + HUNK_SIZE * o->ninfo, 16); -+ -+ sz = ROUND_UP(sz, 4096); -+ -+ /* -+ * Map patch as close to the original code as possible. -+ * Otherwise we can't use 32-bit jumps. -+ */ -+ ret = kpatch_object_allocate_patch(o, sz); -+ if (ret < 0) -+ return ret; -+ ret = kpatch_resolve(o); -+ if (ret < 0) -+ return ret; -+ ret = kpatch_relocate(o); -+ if (ret < 0) -+ return ret; -+ ret = kpatch_process_mem_write(o->proc, -+ kp, -+ o->kpta, -+ kp->total_size); -+ if (ret < 0) -+ return -1; -+ if (o->jmp_table) { -+ ret = kpatch_process_mem_write(o->proc, -+ o->jmp_table, -+ o->kpta + kp->jmp_offset, -+ o->jmp_table->size); -+ if (ret < 0) -+ return ret; -+ } -+ -+ ret = patch_ensure_safety(o, ACTION_APPLY_PATCH); -+ if (ret < 0) -+ return ret; -+ -+ for (i = 0; i < o->ninfo; i++) { -+ ret = patch_apply_hunk(o, i); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return 1; -+} -+ -+static int -+object_unapply_patch(struct object_file *o, int check_flag); -+ -+static int -+object_unapply_old_patch(struct object_file *o) -+{ -+ struct kpatch_file *kpatch_applied, *kpatch_storage; -+ int ret; -+ -+ if (o->skpfile == NULL || o->is_patch || o->applied_patch == NULL) -+ return 0; -+ -+ kpatch_applied = o->applied_patch->kpfile.patch; -+ kpatch_storage = o->skpfile->patch; -+ -+ if (kpatch_applied->user_level >= kpatch_storage->user_level) { -+ kpinfo("'%s' applied patch level is %d (storage has %d\n)\n", -+ o->name, -+ kpatch_applied->user_level, -+ kpatch_storage->user_level); -+ return 1; -+ } -+ -+ printf("%s: replacing patch level %d with level %d\n", -+ o->name, -+ kpatch_applied->user_level, -+ kpatch_storage->user_level); -+ ret = object_unapply_patch(o, /* check_flag */ 0); -+ if (ret < 0) -+ kperr("can't unapply patch for %s\n", o->name); -+ else { -+ /* TODO(pboldin): handle joining the holes here */ -+ o->applied_patch = NULL; -+ o->info = NULL; -+ o->ninfo = 0; -+ } -+ -+ return ret; -+} -+ -+static int -+kpatch_apply_patches(kpatch_process_t *proc) -+{ -+ struct object_file *o; -+ int applied = 0, ret; -+ -+ list_for_each_entry(o, &proc->objs, list) { -+ -+ ret = object_unapply_old_patch(o); -+ if (ret < 0) -+ break; -+ -+ ret = object_apply_patch(o); -+ if (ret < 0) -+ goto unpatch; -+ if (ret) -+ applied++; -+ } -+ return applied; -+ -+unpatch: -+ kperr("Patching %s failed, unapplying partially applied patch\n", o->name); -+ /* -+ * TODO(pboldin): close the holes so the state is the same -+ * after unpatch -+ */ -+ ret = object_unapply_patch(o, /* check_flag */ 1); -+ if (ret < 0) { -+ kperr("Can't unapply patch for %s\n", o->name); -+ } -+ return -1; -+} -+ -+int process_patch(int pid, void *_data) -+{ -+ int ret; -+ kpatch_process_t _proc, *proc = &_proc; -+ struct patch_data *data = _data; -+ -+ kpatch_storage_t *storage = data->storage; -+ int is_just_started = data->is_just_started; -+ int send_fd = data->send_fd; -+ -+ ret = kpatch_process_init(proc, pid, is_just_started, send_fd); -+ if (ret < 0) { -+ kperr("cannot init process %d\n", pid); -+ goto out; -+ } -+ -+ kpatch_process_print_short(proc); -+ -+ ret = kpatch_process_mem_open(proc, MEM_READ); -+ if (ret < 0) -+ goto out_free; -+ -+ /* -+ * In case the process was just started we continue execution up to the -+ * entry point of a program just to allow ld.so to load up libraries -+ */ -+ ret = kpatch_process_load_libraries(proc); -+ if (ret < 0) -+ goto out_free; -+ -+ /* -+ * In case we got there from startup send_fd != -1. -+ */ -+ ret = kpatch_process_kick_send_fd(proc); -+ if (ret < 0) -+ goto out_free; -+ -+ /* -+ * For each object file that we want to patch (either binary itself or -+ * shared library) we need its ELF structure to perform relocations. -+ * Because we know uniq BuildID of the object the section addresses -+ * stored in the patch are valid for the original object. -+ */ -+ ret = kpatch_process_map_object_files(proc); -+ if (ret < 0) -+ goto out_free; -+ -+ /* -+ * Lookup for patches appicable for proc in storage. -+ */ -+ ret = storage_lookup_patches(storage, proc); -+ if (ret <= 0) -+ goto out_free; -+ -+ /* Finally, attach to process */ -+ ret = kpatch_process_attach(proc); -+ if (ret < 0) -+ goto out_free; -+ -+ ret = kpatch_coroutines_find(proc); -+ if (ret < 0) -+ goto out_free; -+ -+ ret = storage_execute_before_script(storage, proc); -+ if (ret < 0) -+ goto out_free; -+ -+ ret = kpatch_apply_patches(proc); -+ -+ if (storage_execute_after_script(storage, proc) < 0) -+ kperr("after script failed\n"); -+ -+ -+out_free: -+ kpatch_process_free(proc); -+ -+out: -+ if (ret < 0) { -+ printf("Failed to apply patch '%s'\n", storage->path); -+ kperr("Failed to apply patch '%s'\n", storage->path); -+ } else if (ret == 0) -+ printf("No patch(es) applicable to PID '%d' have been found\n", pid); -+ else { -+ printf("%d patch hunk(s) have been successfully applied to PID '%d'\n", ret, pid); -+ ret = 0; -+ } -+ -+ return ret; -+} -+ -+ -+/***************************************************************************** -+ * Patch cancellcation subroutines and cmd_unpatch_user -+ ****************************************************************************/ -+static int -+object_find_applied_patch_info(struct object_file *o) -+{ -+ struct kpatch_info tmpinfo; -+ struct kpatch_info *remote_info; -+ size_t nalloc = 0; -+ struct process_mem_iter *iter; -+ int ret; -+ -+ if (o->info != NULL) -+ return 0; -+ -+ iter = kpatch_process_mem_iter_init(o->proc); -+ if (iter == NULL) -+ return -1; -+ -+ remote_info = (void *)o->kpta + o->kpfile.patch->user_info; -+ do { -+ ret = REMOTE_PEEK(iter, tmpinfo, remote_info); -+ if (ret < 0) -+ goto err; -+ -+ if (is_end_info(&tmpinfo)) -+ break; -+ -+ if (o->ninfo == nalloc) { -+ nalloc += 16; -+ o->info = realloc(o->info, nalloc * sizeof(tmpinfo)); -+ } -+ -+ o->info[o->ninfo] = tmpinfo; -+ -+ remote_info++; -+ o->ninfo++; -+ } while (1); -+ -+ o->applied_patch->info = o->info; -+ o->applied_patch->ninfo = o->ninfo; -+ -+err: -+ kpatch_process_mem_iter_free(iter); -+ -+ return ret; -+} -+ -+static int -+object_unapply_patch(struct object_file *o, int check_flag) -+{ -+ int ret; -+ size_t i; -+ unsigned long orig_code_addr; -+ -+ ret = object_find_applied_patch_info(o); -+ if (ret < 0) -+ return ret; -+ -+ ret = patch_ensure_safety(o, ACTION_UNAPPLY_PATCH); -+ if (ret < 0) -+ return ret; -+ -+ orig_code_addr = o->kpta + o->kpfile.patch->user_undo; -+ -+ for (i = 0; i < o->ninfo; i++) { -+ if (is_new_func(&o->info[i])) -+ continue; -+ -+ if (check_flag && !(o->info[i].flags & PATCH_APPLIED)) -+ continue; -+ -+ ret = kpatch_process_memcpy(o->proc, -+ o->info[i].daddr, -+ orig_code_addr + i * HUNK_SIZE, -+ HUNK_SIZE); -+ /* XXX(pboldin) We are in deep trouble here, handle it -+ * by restoring the patch back */ -+ if (ret < 0) -+ return ret; -+ } -+ -+ ret = kpatch_munmap_remote(proc2pctx(o->proc), -+ o->kpta, -+ o->kpfile.size); -+ -+ return ret; -+} -+ -+static int -+kpatch_should_unapply_patch(struct object_file *o, -+ char *buildids[], -+ int nbuildids) -+{ -+ int i; -+ const char *bid; -+ -+ if (nbuildids == 0) -+ return 1; -+ -+ bid = kpatch_get_buildid(o); -+ -+ for (i = 0; i < nbuildids; i++) { -+ if (!strcmp(bid, buildids[i]) || -+ !strcmp(o->name, buildids[i])) -+ return 1; -+ } -+ -+ return 0; -+} -+ -+static int -+kpatch_unapply_patches(kpatch_process_t *proc, -+ char *buildids[], -+ int nbuildids) -+{ -+ struct object_file *o; -+ int ret; -+ size_t unapplied = 0; -+ -+ ret = kpatch_process_associate_patches(proc); -+ if (ret < 0) -+ return ret; -+ -+ list_for_each_entry(o, &proc->objs, list) { -+ if (o->applied_patch == NULL) -+ continue; -+ -+ if (!kpatch_should_unapply_patch(o, buildids, nbuildids)) -+ continue; -+ -+ ret = object_unapply_patch(o, /* check_flag */ 0); -+ if (ret < 0) -+ return ret; -+ unapplied++; -+ } -+ -+ return unapplied; -+} -+ -+int process_unpatch(int pid, void *_data) -+{ -+ int ret; -+ kpatch_process_t _proc, *proc = &_proc; -+ struct unpatch_data *data = _data; -+ char **buildids = data->buildids; -+ int nbuildids = data->nbuildids; -+ -+ ret = kpatch_process_init(proc, pid, /* start */ 0, /* send_fd */ -1); -+ if (ret < 0) -+ return -1; -+ -+ kpatch_process_print_short(proc); -+ -+ ret = kpatch_process_attach(proc); -+ if (ret < 0) -+ goto out; -+ -+ ret = kpatch_process_map_object_files(proc); -+ if (ret < 0) -+ goto out; -+ -+ ret = kpatch_coroutines_find(proc); -+ if (ret < 0) -+ goto out; -+ -+ ret = kpatch_unapply_patches(proc, buildids, nbuildids); -+ -+out: -+ kpatch_process_free(proc); -+ -+ if (ret < 0) -+ printf("Failed to cancel patches for %d\n", pid); -+ else if (ret == 0) -+ printf("No patch(es) cancellable from PID '%d' were found\n", pid); -+ else -+ printf("%d patch hunk(s) were successfully cancelled from PID '%d'\n", ret, pid); -+ -+ return ret; -+} -+ -diff --git a/src/kpatch_patch.h b/src/kpatch_patch.h -new file mode 100644 -index 0000000..44806ab ---- /dev/null -+++ b/src/kpatch_patch.h -@@ -0,0 +1,28 @@ -+#ifndef __KPATCH_PATCH__ -+#define __KPATCH_PATCH__ -+ -+#include "kpatch_common.h" -+#include "kpatch_storage.h" -+#include "kpatch_file.h" -+#include "rbtree.h" -+ -+enum { -+ ACTION_APPLY_PATCH, -+ ACTION_UNAPPLY_PATCH -+}; -+ -+struct patch_data { -+ kpatch_storage_t *storage; -+ int is_just_started; -+ int send_fd; -+}; -+ -+struct unpatch_data { -+ char **buildids; -+ int nbuildids; -+}; -+ -+int process_patch(int pid, void *_data); -+int process_unpatch(int pid, void *_data); -+ -+#endif -diff --git a/src/kpatch_user.c b/src/kpatch_user.c -index 672b4d4..9ab77b9 100644 ---- a/src/kpatch_user.c -+++ b/src/kpatch_user.c -@@ -7,9 +7,6 @@ - #include - #include - #include --#include --#include --#include - #include - #include - #include -@@ -20,11 +17,11 @@ - - #include "kpatch_user.h" - #include "kpatch_storage.h" -+#include "kpatch_patch.h" - #include "kpatch_process.h" - #include "kpatch_file.h" - #include "kpatch_common.h" - #include "kpatch_elf.h" --#include "kpatch_ptrace.h" - #include "list.h" - #include "kpatch_log.h" - -@@ -42,571 +39,6 @@ typedef int (callback_t)(int pid, void *data); - static int - processes_do(int pid, callback_t callback, void *data); - --enum { -- ACTION_APPLY_PATCH, -- ACTION_UNAPPLY_PATCH --}; -- --static inline int --is_addr_in_info(unsigned long addr, -- struct kpatch_info *info, -- int direction) --{ --#define IS_ADDR_IN_HALF_INTERVAL(addr, start, len) ((addr >= start) && (addr < start + len)) -- if (direction == ACTION_APPLY_PATCH) -- return IS_ADDR_IN_HALF_INTERVAL(addr, info->daddr, info->dlen); -- if (direction == ACTION_UNAPPLY_PATCH) -- return IS_ADDR_IN_HALF_INTERVAL(addr, info->saddr, info->slen); -- return 0; --} -- --static void print_address_closest_func(int log_level, struct object_file *o, unw_cursor_t *cur, int in_oldpatch) --{ -- unsigned long address, offset; -- char fname[128]; -- -- unw_get_reg(cur, UNW_REG_IP, &address); -- -- if (in_oldpatch) -- if (address >= o->kpta && address < o->kpta + o->kpfile.size) { -- kplog(log_level, "\t[0x%lx](patch)\n", address); -- return; -- } -- -- if (!unw_get_proc_name(cur, fname, 128, &offset)) -- kplog(log_level, "\t[0x%lx] %s+0x%lx\n", address, fname, offset); -- else -- kplog(log_level, "\t[0x%lx]\n", address); --} -- --/** -- * Verify that the function from file `o' is safe to be patched. -- * -- * If retip is given then the safe address is returned in it. -- * What is considered a safe address depends on the `paranoid' value. When it -- * is true, safe address is the upper of ALL functions that do have a patch. -- * When it is false, safe address is the address of the first function -- * instruction that have no patch. -- * -- * That is, for the call chain from left to right with functions that have -- * patch marked with '+': -- * -- * foo -> bar+ -> baz -> qux+ -- * -- * With `paranoid=true' this function will return address of the `bar+' -- * instruction being executed with *retip pointing to the `foo' instruction -- * that comes after the call to `bar+'. With `paranoid=false' this function -- * will return address of the `qux+' instruction being executed with *retip -- * pointing to the `baz' instruction that comes after call to `qux+'. -- */ --static unsigned long --object_patch_verify_safety_single(struct object_file *o, -- unw_cursor_t *cur, -- unsigned long *retip, -- int paranoid, -- int direction) --{ -- unw_word_t ip; -- struct kpatch_info *info = o->info; -- size_t i, ninfo = o->ninfo; -- int prev = 0, rv; -- unsigned long last = 0; -- -- if (direction != ACTION_APPLY_PATCH && -- direction != ACTION_UNAPPLY_PATCH) -- kpfatal("unknown direction"); -- -- do { -- print_address_closest_func(LOG_INFO, o, cur, direction == ACTION_UNAPPLY_PATCH); -- -- unw_get_reg(cur, UNW_REG_IP, &ip); -- -- for (i = 0; i < ninfo; i++) { -- if (is_new_func(&info[i])) -- continue; -- -- if (is_addr_in_info((long)ip, &info[i], direction)) { -- if (direction == ACTION_APPLY_PATCH) -- last = info[i].daddr; -- else if (direction == ACTION_UNAPPLY_PATCH) -- last = info[i].saddr; -- prev = 1; -- break; -- } -- } -- -- if (prev && i == ninfo) { -- prev = 0; -- if (retip) -- *retip = ip; -- if (!paranoid) -- break; -- } -- -- rv = unw_step(cur); -- } while (rv > 0); -- -- if (rv < 0) -- kperr("unw_step = %d\n", rv); -- -- return last; --} -- --#define KPATCH_CORO_STACK_UNSAFE (1 << 20) -- --static int --patch_verify_safety(struct object_file *o, -- unsigned long *retips, -- int direction) --{ -- size_t nr = 0, failed = 0, count = 0; -- struct kpatch_ptrace_ctx *p; -- struct kpatch_coro *c; -- unsigned long retip, ret; -- unw_cursor_t cur; -- -- list_for_each_entry(c, &o->proc->coro.coros, list) { -- void *ucoro; -- -- kpdebug("Verifying safety for coroutine %zd...\n", count); -- kpinfo("Stacktrace to verify safety for coroutine %zd:\n", count); -- ucoro = _UCORO_create(c, proc2pctx(o->proc)->pid); -- if (!ucoro) { -- kplogerror("can't create unwind coro context\n"); -- return -1; -- } -- -- ret = unw_init_remote(&cur, o->proc->coro.unwd, ucoro); -- if (ret) { -- kplogerror("can't create unwind remote context\n"); -- _UCORO_destroy(ucoro); -- return -1; -- } -- -- ret = object_patch_verify_safety_single(o, &cur, NULL, 0, direction); -- _UCORO_destroy(ucoro); -- if (ret) { -- kperr("safety check failed to %lx\n", ret); -- failed++; -- } else { -- kpdebug("OK\n"); -- } -- count++; -- } -- if (failed) -- return failed | KPATCH_CORO_STACK_UNSAFE; -- -- list_for_each_entry(p, &o->proc->ptrace.pctxs, list) { -- void *upt; -- -- kpdebug("Verifying safety for pid %d...\n", p->pid); -- kpinfo("Stacktrace to verify safety for pid %d:\n", p->pid); -- upt = _UPT_create(p->pid); -- if (!upt) { -- kplogerror("can't create unwind ptrace context\n"); -- return -1; -- } -- -- ret = unw_init_remote(&cur, o->proc->ptrace.unwd, upt); -- if (ret) { -- kplogerror("can't create unwind remote context\n"); -- _UPT_destroy(upt); -- return -1; -- } -- -- ret = object_patch_verify_safety_single(o, &cur, &retip, 0, direction); -- _UPT_destroy(upt); -- if (ret) { -- /* TODO: dump full backtrace, with symbols where possible (shared libs) */ -- if (retips) { -- kperr("safety check failed for %lx, will continue until %lx\n", -- ret, retip); -- retips[nr] = retip; -- } else { -- kperr("safety check failed for %lx\n", ret); -- errno = -EBUSY; -- } -- failed++; -- } -- kpdebug("OK\n"); -- nr++; -- } -- -- return failed; --} -- --/* -- * Ensure that it is safe to apply/unapply patch for the object file `o`. -- * -- * First, we verify the safety of the patch. -- * -- * It is safe to apply patch (ACTION_APPLY_PATCH) when no threads or coroutines -- * are executing the functions to be patched. -- * -- * It is safe to unapply patch (ACTION_UNAPPLY_PATCH) when no threads or -- * coroutines are executing the patched functions. -- * -- * If it is not safe to do the action we continue threads execution until they -- * are out of the functions that we want to patch/unpatch. This is done using -- * `kpatch_ptrace_execute_until` function with default timeout of 3000 seconds -- * and checking for action safety again. -- */ --static int --patch_ensure_safety(struct object_file *o, -- int action) --{ -- struct kpatch_ptrace_ctx *p; -- unsigned long ret, *retips; -- size_t nr = 0, i; -- -- list_for_each_entry(p, &o->proc->ptrace.pctxs, list) -- nr++; -- retips = malloc(nr * sizeof(unsigned long)); -- if (retips == NULL) -- return -1; -- -- memset(retips, 0, nr * sizeof(unsigned long)); -- -- ret = patch_verify_safety(o, retips, action); -- /* -- * For coroutines we can't "execute until" -- */ -- if (ret && !(ret & KPATCH_CORO_STACK_UNSAFE)) { -- i = 0; -- list_for_each_entry(p, &o->proc->ptrace.pctxs, list) { -- p->execute_until = retips[i]; -- i++; -- } -- -- ret = kpatch_ptrace_execute_until(o->proc, 3000, 0); -- -- /* OK, at this point we may have new threads, discover them */ -- if (ret == 0) -- ret = kpatch_process_attach(o->proc); -- if (ret == 0) -- ret = patch_verify_safety(o, NULL, action); -- } -- -- free(retips); -- -- return ret ? -1 : 0; --} -- --/***************************************************************************** -- * Patch application subroutines and cmd_patch_user -- ****************************************************************************/ --/* -- * This flag is local, i.e. it is never stored to the -- * patch applied to patient's memory. -- */ --#define PATCH_APPLIED (1 << 31) -- --#define HUNK_SIZE 5 -- --static int --patch_apply_hunk(struct object_file *o, size_t nhunk) --{ -- int ret; -- char code[HUNK_SIZE] = {0xe9, 0x00, 0x00, 0x00, 0x00}; /* jmp IMM */ -- struct kpatch_info *info = &o->info[nhunk]; -- unsigned long pundo; -- -- if (is_new_func(info)) -- return 0; -- -- pundo = o->kpta + o->kpfile.patch->user_undo + nhunk * HUNK_SIZE; -- kpinfo("%s origcode from 0x%lx+0x%x to 0x%lx\n", -- o->name, info->daddr, HUNK_SIZE, pundo); -- ret = kpatch_process_memcpy(o->proc, pundo, -- info->daddr, HUNK_SIZE); -- if (ret < 0) -- return ret; -- -- kpinfo("%s hunk 0x%lx+0x%x -> 0x%lx+0x%x\n", -- o->name, info->daddr, info->dlen, info->saddr, info->slen); -- *(unsigned int *)(code + 1) = (unsigned int)(info->saddr - info->daddr - 5); -- ret = kpatch_process_mem_write(o->proc, -- code, -- info->daddr, -- sizeof(code)); -- /* -- * NOTE(pboldin): This is only stored locally, as information have -- * been copied to patient's memory already. -- */ -- info->flags |= PATCH_APPLIED; -- return ret ? -1 : 0; --} -- --static int --duplicate_kp_file(struct object_file *o) --{ -- struct kpatch_file *patch; -- -- patch = malloc(o->skpfile->size); -- if (patch == NULL) -- return -1; -- -- memcpy(patch, o->skpfile->patch, o->skpfile->size); -- o->kpfile.patch = patch; -- o->kpfile.size = o->skpfile->size; -- -- return 0; --} -- --static int --object_apply_patch(struct object_file *o) --{ -- struct kpatch_file *kp; -- size_t sz, i; -- int undef, ret; -- -- if (o->skpfile == NULL || o->is_patch) -- return 0; -- -- if (o->applied_patch) { -- kpinfo("Object '%s' already have a patch, not patching\n", -- o->name); -- return 0; -- } -- -- ret = duplicate_kp_file(o); -- if (ret < 0) { -- kplogerror("can't duplicate kp_file\n"); -- return -1; -- } -- -- ret = kpatch_elf_load_kpatch_info(o); -- if (ret < 0) -- return ret; -- -- kp = o->kpfile.patch; -- -- sz = ROUND_UP(kp->total_size, 8); -- undef = kpatch_count_undefined(o); -- if (undef) { -- o->jmp_table = kpatch_new_jmp_table(undef); -- kp->jmp_offset = sz; -- kpinfo("Jump table %d bytes for %d syms at offset 0x%x\n", -- o->jmp_table->size, undef, kp->jmp_offset); -- sz = ROUND_UP(sz + o->jmp_table->size, 128); -- } -- -- kp->user_info = (unsigned long)o->info - -- (unsigned long)o->kpfile.patch; -- kp->user_undo = sz; -- sz = ROUND_UP(sz + HUNK_SIZE * o->ninfo, 16); -- -- sz = ROUND_UP(sz, 4096); -- -- /* -- * Map patch as close to the original code as possible. -- * Otherwise we can't use 32-bit jumps. -- */ -- ret = kpatch_object_allocate_patch(o, sz); -- if (ret < 0) -- return ret; -- ret = kpatch_resolve(o); -- if (ret < 0) -- return ret; -- ret = kpatch_relocate(o); -- if (ret < 0) -- return ret; -- ret = kpatch_process_mem_write(o->proc, -- kp, -- o->kpta, -- kp->total_size); -- if (ret < 0) -- return -1; -- if (o->jmp_table) { -- ret = kpatch_process_mem_write(o->proc, -- o->jmp_table, -- o->kpta + kp->jmp_offset, -- o->jmp_table->size); -- if (ret < 0) -- return ret; -- } -- -- ret = patch_ensure_safety(o, ACTION_APPLY_PATCH); -- if (ret < 0) -- return ret; -- -- for (i = 0; i < o->ninfo; i++) { -- ret = patch_apply_hunk(o, i); -- if (ret < 0) -- return ret; -- } -- -- return 1; --} -- --static int --object_unapply_patch(struct object_file *o, int check_flag); -- --static int --object_unapply_old_patch(struct object_file *o) --{ -- struct kpatch_file *kpatch_applied, *kpatch_storage; -- int ret; -- -- if (o->skpfile == NULL || o->is_patch || o->applied_patch == NULL) -- return 0; -- -- kpatch_applied = o->applied_patch->kpfile.patch; -- kpatch_storage = o->skpfile->patch; -- -- if (kpatch_applied->user_level >= kpatch_storage->user_level) { -- kpinfo("'%s' applied patch level is %d (storage has %d\n)\n", -- o->name, -- kpatch_applied->user_level, -- kpatch_storage->user_level); -- return 1; -- } -- -- printf("%s: replacing patch level %d with level %d\n", -- o->name, -- kpatch_applied->user_level, -- kpatch_storage->user_level); -- ret = object_unapply_patch(o, /* check_flag */ 0); -- if (ret < 0) -- kperr("can't unapply patch for %s\n", o->name); -- else { -- /* TODO(pboldin): handle joining the holes here */ -- o->applied_patch = NULL; -- o->info = NULL; -- o->ninfo = 0; -- } -- -- return ret; --} -- --static int --kpatch_apply_patches(kpatch_process_t *proc) --{ -- struct object_file *o; -- int applied = 0, ret; -- -- list_for_each_entry(o, &proc->objs, list) { -- -- ret = object_unapply_old_patch(o); -- if (ret < 0) -- break; -- -- ret = object_apply_patch(o); -- if (ret < 0) -- goto unpatch; -- if (ret) -- applied++; -- } -- return applied; -- --unpatch: -- kperr("Patching %s failed, unapplying partially applied patch\n", o->name); -- /* -- * TODO(pboldin): close the holes so the state is the same -- * after unpatch -- */ -- ret = object_unapply_patch(o, /* check_flag */ 1); -- if (ret < 0) { -- kperr("Can't unapply patch for %s\n", o->name); -- } -- return -1; --} -- --struct patch_data { -- kpatch_storage_t *storage; -- int is_just_started; -- int send_fd; --}; -- --static int process_patch(int pid, void *_data) --{ -- int ret; -- kpatch_process_t _proc, *proc = &_proc; -- struct patch_data *data = _data; -- -- kpatch_storage_t *storage = data->storage; -- int is_just_started = data->is_just_started; -- int send_fd = data->send_fd; -- -- ret = kpatch_process_init(proc, pid, is_just_started, send_fd); -- if (ret < 0) { -- kperr("cannot init process %d\n", pid); -- goto out; -- } -- -- kpatch_process_print_short(proc); -- -- ret = kpatch_process_mem_open(proc, MEM_READ); -- if (ret < 0) -- goto out_free; -- -- /* -- * In case the process was just started we continue execution up to the -- * entry point of a program just to allow ld.so to load up libraries -- */ -- ret = kpatch_process_load_libraries(proc); -- if (ret < 0) -- goto out_free; -- -- /* -- * In case we got there from startup send_fd != -1. -- */ -- ret = kpatch_process_kick_send_fd(proc); -- if (ret < 0) -- goto out_free; -- -- /* -- * For each object file that we want to patch (either binary itself or -- * shared library) we need its ELF structure to perform relocations. -- * Because we know uniq BuildID of the object the section addresses -- * stored in the patch are valid for the original object. -- */ -- ret = kpatch_process_map_object_files(proc); -- if (ret < 0) -- goto out_free; -- -- /* -- * Lookup for patches appicable for proc in storage. -- */ -- ret = storage_lookup_patches(storage, proc); -- if (ret <= 0) -- goto out_free; -- -- /* Finally, attach to process */ -- ret = kpatch_process_attach(proc); -- if (ret < 0) -- goto out_free; -- -- ret = kpatch_coroutines_find(proc); -- if (ret < 0) -- goto out_free; -- -- ret = storage_execute_before_script(storage, proc); -- if (ret < 0) -- goto out_free; -- -- ret = kpatch_apply_patches(proc); -- -- if (storage_execute_after_script(storage, proc) < 0) -- kperr("after script failed\n"); -- -- --out_free: -- kpatch_process_free(proc); -- --out: -- if (ret < 0) { -- printf("Failed to apply patch '%s'\n", storage->path); -- kperr("Failed to apply patch '%s'\n", storage->path); -- } else if (ret == 0) -- printf("No patch(es) applicable to PID '%d' have been found\n", pid); -- else { -- printf("%d patch hunk(s) have been successfully applied to PID '%d'\n", ret, pid); -- ret = 0; -- } -- -- return ret; --} - - static int - processes_patch(kpatch_storage_t *storage, -@@ -690,193 +122,6 @@ out_err: - return ret; - } - --/***************************************************************************** -- * Patch cancellcation subroutines and cmd_unpatch_user -- ****************************************************************************/ --static int --object_find_applied_patch_info(struct object_file *o) --{ -- struct kpatch_info tmpinfo; -- struct kpatch_info *remote_info; -- size_t nalloc = 0; -- struct process_mem_iter *iter; -- int ret; -- -- if (o->info != NULL) -- return 0; -- -- iter = kpatch_process_mem_iter_init(o->proc); -- if (iter == NULL) -- return -1; -- -- remote_info = (void *)o->kpta + o->kpfile.patch->user_info; -- do { -- ret = REMOTE_PEEK(iter, tmpinfo, remote_info); -- if (ret < 0) -- goto err; -- -- if (is_end_info(&tmpinfo)) -- break; -- -- if (o->ninfo == nalloc) { -- nalloc += 16; -- o->info = realloc(o->info, nalloc * sizeof(tmpinfo)); -- } -- -- o->info[o->ninfo] = tmpinfo; -- -- remote_info++; -- o->ninfo++; -- } while (1); -- -- o->applied_patch->info = o->info; -- o->applied_patch->ninfo = o->ninfo; -- --err: -- kpatch_process_mem_iter_free(iter); -- -- return ret; --} -- --static int --object_unapply_patch(struct object_file *o, int check_flag) --{ -- int ret; -- size_t i; -- unsigned long orig_code_addr; -- -- ret = object_find_applied_patch_info(o); -- if (ret < 0) -- return ret; -- -- ret = patch_ensure_safety(o, ACTION_UNAPPLY_PATCH); -- if (ret < 0) -- return ret; -- -- orig_code_addr = o->kpta + o->kpfile.patch->user_undo; -- -- for (i = 0; i < o->ninfo; i++) { -- if (is_new_func(&o->info[i])) -- continue; -- -- if (check_flag && !(o->info[i].flags & PATCH_APPLIED)) -- continue; -- -- ret = kpatch_process_memcpy(o->proc, -- o->info[i].daddr, -- orig_code_addr + i * HUNK_SIZE, -- HUNK_SIZE); -- /* XXX(pboldin) We are in deep trouble here, handle it -- * by restoring the patch back */ -- if (ret < 0) -- return ret; -- } -- -- ret = kpatch_munmap_remote(proc2pctx(o->proc), -- o->kpta, -- o->kpfile.size); -- -- return ret; --} -- --static int --kpatch_should_unapply_patch(struct object_file *o, -- char *buildids[], -- int nbuildids) --{ -- int i; -- const char *bid; -- -- if (nbuildids == 0) -- return 1; -- -- bid = kpatch_get_buildid(o); -- -- for (i = 0; i < nbuildids; i++) { -- if (!strcmp(bid, buildids[i]) || -- !strcmp(o->name, buildids[i])) -- return 1; -- } -- -- return 0; --} -- --static int --kpatch_unapply_patches(kpatch_process_t *proc, -- char *buildids[], -- int nbuildids) --{ -- struct object_file *o; -- int ret; -- size_t unapplied = 0; -- -- ret = kpatch_process_associate_patches(proc); -- if (ret < 0) -- return ret; -- -- list_for_each_entry(o, &proc->objs, list) { -- if (o->applied_patch == NULL) -- continue; -- -- if (!kpatch_should_unapply_patch(o, buildids, nbuildids)) -- continue; -- -- ret = object_unapply_patch(o, /* check_flag */ 0); -- if (ret < 0) -- return ret; -- unapplied++; -- } -- -- return unapplied; --} -- --struct unpatch_data { -- char **buildids; -- int nbuildids; --}; -- --static int --process_unpatch(int pid, void *_data) --{ -- int ret; -- kpatch_process_t _proc, *proc = &_proc; -- struct unpatch_data *data = _data; -- char **buildids = data->buildids; -- int nbuildids = data->nbuildids; -- -- ret = kpatch_process_init(proc, pid, /* start */ 0, /* send_fd */ -1); -- if (ret < 0) -- return -1; -- -- kpatch_process_print_short(proc); -- -- ret = kpatch_process_attach(proc); -- if (ret < 0) -- goto out; -- -- ret = kpatch_process_map_object_files(proc); -- if (ret < 0) -- goto out; -- -- ret = kpatch_coroutines_find(proc); -- if (ret < 0) -- goto out; -- -- ret = kpatch_unapply_patches(proc, buildids, nbuildids); -- --out: -- kpatch_process_free(proc); -- -- if (ret < 0) -- printf("Failed to cancel patches for %d\n", pid); -- else if (ret == 0) -- printf("No patch(es) cancellable from PID '%d' were found\n", pid); -- else -- printf("%d patch hunk(s) were successfully cancelled from PID '%d'\n", ret, pid); -- -- return ret; --} -- - static int - processes_unpatch(int pid, char *buildids[], int nbuildids) - { --- -2.23.0 - diff --git a/0003-cmd_patch-pass-arguments-directly.patch b/0003-cmd_patch-pass-arguments-directly.patch deleted file mode 100644 index 7283818b65ed6d5b570d612bae5f1b873554f774..0000000000000000000000000000000000000000 --- a/0003-cmd_patch-pass-arguments-directly.patch +++ /dev/null @@ -1,152 +0,0 @@ -From 98833d06737a9a1128f548d15344b1cbaeed049f Mon Sep 17 00:00:00 2001 -From: Pavel Boldin -Date: Wed, 24 Jan 2018 13:14:10 +0200 -Subject: [PATCH 03/89] cmd_patch: pass arguments directly - -Signed-off-by: Pavel Boldin ---- - src/kpatch_user.c | 84 ++++++++++++++++------------------------------- - 1 file changed, 29 insertions(+), 55 deletions(-) - -diff --git a/src/kpatch_user.c b/src/kpatch_user.c -index 9ab77b9..d257b67 100644 ---- a/src/kpatch_user.c -+++ b/src/kpatch_user.c -@@ -63,19 +63,36 @@ static int usage_patch(const char *err) - { - if (err) - fprintf(stderr, "err: %s\n", err); -- fprintf(stderr, "usage: libcare-ctl patch [options] <-p PID> <-r fd> \n"); -+ fprintf(stderr, "usage: libcare-ctl patch [options] <-p PID> \n"); - fprintf(stderr, "\nOptions:\n"); - fprintf(stderr, " -h - this message\n"); -- fprintf(stderr, " -s - process was just executed\n"); - fprintf(stderr, " -p - target process\n"); -- fprintf(stderr, " -r fd - fd used with LD_PRELOAD=execve.so.\n"); - return err ? 0 : -1; - } - --int cmd_patch_user(int argc, char *argv[]) -+static int -+patch_user(const char *storage_path, int pid, -+ int is_just_started, int send_fd) - { -+ int ret; - kpatch_storage_t storage; -- int opt, pid = -1, is_pid_set = 0, ret, start = 0, send_fd = -1; -+ -+ ret = storage_init(&storage, storage_path); -+ if (ret < 0) -+ return ret; -+ -+ ret = processes_patch(&storage, pid, is_just_started, send_fd); -+ -+ storage_free(&storage); -+ -+ return ret; -+} -+ -+ -+int cmd_patch_user(int argc, char *argv[]) -+{ -+ int opt, pid = -1, is_pid_set = 0, ret; -+ const char *storage_path; - - if (argc < 4) - return usage_patch(NULL); -@@ -89,12 +106,6 @@ int cmd_patch_user(int argc, char *argv[]) - pid = atoi(optarg); - is_pid_set = 1; - break; -- case 'r': -- send_fd = atoi(optarg); -- break; -- case 's': -- start = 1; -- break; - default: - return usage_patch("unknown option"); - } -@@ -109,14 +120,9 @@ int cmd_patch_user(int argc, char *argv[]) - if (!kpatch_check_system()) - goto out_err; - -- ret = storage_init(&storage, argv[argc - 1]); -- if (ret < 0) -- goto out_err; -- -- -- ret = processes_patch(&storage, pid, start, send_fd); -- -- storage_free(&storage); -+ storage_path = argv[argc - 1]; -+ ret = patch_user(storage_path, pid, -+ /* is_just_started */ 0, /* send_fd */ -1); - - out_err: - return ret; -@@ -474,24 +480,6 @@ static int - cmd_execve_startup(int fd, int argc, char *argv[], int is_just_started) - { - int rv, pid; -- char pid_str[64], send_fd_str[64]; -- char *patch_pid_argv_execve[] = { -- "patch", -- "-s", -- "-p", -- pid_str, -- "-r", -- send_fd_str, -- storage_dir -- }; -- char *patch_pid_argv_startup[] = { -- "patch", -- "-p", -- pid_str, -- "-r", -- send_fd_str, -- storage_dir -- }; - - rv = sscanf(argv[1], "%d", &pid); - if (rv != 1) { -@@ -499,16 +487,8 @@ cmd_execve_startup(int fd, int argc, char *argv[], int is_just_started) - return -1; - } - -- sprintf(pid_str, "%d", pid); -- sprintf(send_fd_str, "%d", fd); -- - optind = 1; -- if (is_just_started) -- rv = cmd_patch_user(ARRAY_SIZE(patch_pid_argv_execve), -- patch_pid_argv_execve); -- else -- rv = cmd_patch_user(ARRAY_SIZE(patch_pid_argv_startup), -- patch_pid_argv_startup); -+ rv = patch_user(storage_dir, pid, is_just_started, fd); - - if (rv < 0) - kperr("can't patch pid %d\n", pid); -@@ -578,15 +558,9 @@ cmd_storage(int argc, char *argv[]) - static int - cmd_update(int argc, char *argv[]) - { -- char *patch_all[] = { -- "patch", -- "-p", -- "all", -- storage_dir -- }; -- -- optind = 1; -- return cmd_patch_user(ARRAY_SIZE(patch_all), patch_all); -+ return patch_user(storage_dir, /* pid */ -1, -+ /* is_just_started */ 0, -+ /* send_fd */ -1); - } - - static int --- -2.23.0 - diff --git a/0004-travis-use-VM-for-now.patch b/0004-travis-use-VM-for-now.patch deleted file mode 100644 index c286c1de55ea752ea9170ab91b744d395865ddb6..0000000000000000000000000000000000000000 --- a/0004-travis-use-VM-for-now.patch +++ /dev/null @@ -1,71 +0,0 @@ -From f4b6b37575e514f3e54f08166dc14e35815a8ebb Mon Sep 17 00:00:00 2001 -From: Pavel Boldin -Date: Tue, 30 Jan 2018 08:15:11 +0200 -Subject: [PATCH 04/89] travis: use VM for now - -Attaching even to a children process is broken in travis's Docker. -Use VM until https://github.com/travis-ci/travis-ci/issues/9033 -is fixed. - -Signed-off-by: Pavel Boldin ---- - .travis.yml | 2 +- - Makefile | 2 +- - tests/run_tests.sh | 18 +++++++++++++++++- - 3 files changed, 19 insertions(+), 3 deletions(-) - -diff --git a/.travis.yml b/.travis.yml -index 4bb2614..f3ccb4e 100644 ---- a/.travis.yml -+++ b/.travis.yml -@@ -3,7 +3,7 @@ script: make tests - language: c - - dist: trusty --sudo: false -+sudo: required - - addons: - apt: -diff --git a/Makefile b/Makefile -index 2da227f..c5a2837 100644 ---- a/Makefile -+++ b/Makefile -@@ -1,4 +1,4 @@ -- -+#dummy - - all: src - -diff --git a/tests/run_tests.sh b/tests/run_tests.sh -index fcfcd56..fbfb273 100755 ---- a/tests/run_tests.sh -+++ b/tests/run_tests.sh -@@ -3,7 +3,23 @@ - set -e - - wait_file() { -- while ! test -s $1; do sleep ${2-1}; done -+ local file="$1" -+ local pause="${2-1}" -+ local i=0 -+ local timeout=60 -+ -+ while test $i -lt $timeout; do -+ if test -s $file; then -+ break -+ fi -+ sleep $pause -+ i=$((i + 1)) -+ done -+ -+ if test $i -eq $timeout; then -+ return 1 -+ fi -+ - return 0 - } - --- -2.23.0 - diff --git a/0005-scripts-pkgbuild-add-prepare_env-hook.patch b/0005-scripts-pkgbuild-add-prepare_env-hook.patch deleted file mode 100644 index cf607af01ce643a4c384eb4c84167619d882ffc8..0000000000000000000000000000000000000000 --- a/0005-scripts-pkgbuild-add-prepare_env-hook.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 8e1d1d24e39464e88e92695ea5951639e789f72d Mon Sep 17 00:00:00 2001 -From: Pavel Boldin -Date: Sat, 28 Oct 2017 03:47:48 +0300 -Subject: [PATCH 05/89] scripts/pkgbuild: add prepare_env hook - -Change-Id: Iabb96a1b9f9cd8d1415029380f825da29156a840 -Signed-off-by: Pavel Boldin ---- - scripts/pkgbuild | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/scripts/pkgbuild b/scripts/pkgbuild -index ea1f411..3697594 100755 ---- a/scripts/pkgbuild -+++ b/scripts/pkgbuild -@@ -73,6 +73,11 @@ clean_dirs() { - rm -rf $KP_PROJECT_BUILD_ROOT /root/root.original /root/root.patched - } - -+kp_prepare_env_hook() { -+ # use this to add repos -+ : -+} -+ - kp_pack_prebuilt() { - echo " packing prebuilt $KP_PROJECT into $KP_PROJECT_PREBUILT" - pushd $KP_PROJECT_BUILD_ROOT -@@ -386,6 +391,8 @@ main() { - - overwrite_utils - -+ kp_prepare_env_hook -+ - if [ "$ACTION" == "prebuild" ]; then - kp_prepare_source - kp_prebuild_hook --- -2.23.0 - diff --git a/0006-pkgbuild-fix-for-non-root-rpmbuild-built-root.patch b/0006-pkgbuild-fix-for-non-root-rpmbuild-built-root.patch deleted file mode 100644 index 3d93ea1273702206505632cc665427bf9edeb01f..0000000000000000000000000000000000000000 --- a/0006-pkgbuild-fix-for-non-root-rpmbuild-built-root.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 859be3502b57c87f3241c11d36059313cbdde46a Mon Sep 17 00:00:00 2001 -From: Pavel Boldin -Date: Tue, 31 Oct 2017 04:04:58 +0100 -Subject: [PATCH 06/89] pkgbuild: fix for non-/root/rpmbuild built root - ---- - scripts/pkgbuild | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/scripts/pkgbuild b/scripts/pkgbuild -index 3697594..e2ac7c7 100755 ---- a/scripts/pkgbuild -+++ b/scripts/pkgbuild -@@ -120,7 +120,8 @@ kp_prepare_source_rpm() { - - sed -i 's/.rpm$//g' $KP_PROJECT_BUILD_ROOT/dependencies.txt - -- rpm -ivh /kcdata/$KP_PROJECT_SOURCE -+ rpm -ivh /kcdata/$KP_PROJECT_SOURCE \ -+ --define "_topdir $KP_PROJECT_BUILD_ROOT" - } - - kp_prepare_source_deb() { -@@ -152,6 +153,7 @@ kp_prebuild_rpm() { - eval rpmbuild --nocheck --noclean \ - -bc \ - $KP_RPMBUILD_FLAGS \ -+ '--define "_topdir $KP_PROJECT_BUILD_ROOT"' \ - $KP_PROJECT_BUILD_ROOT/SPECS/$KP_PROJECT_SPEC 2>&1 | \ - tee $KP_PROJECT_BUILD_ROOT/prebuild.log - } -@@ -237,6 +239,7 @@ kp_build_rpm() { - --short-circuit \ - -bc \ - $KP_RPMBUILD_FLAGS \ -+ '--define "_topdir $KP_PROJECT_BUILD_ROOT"' \ - $KP_PROJECT_BUILD_ROOT/SPECS/$KP_PROJECT_SPEC - } - --- -2.23.0 - diff --git a/0007-Toil-package-builder.patch b/0007-Toil-package-builder.patch deleted file mode 100644 index df51f15832fdecd5521fc94be92965093ef9e465..0000000000000000000000000000000000000000 --- a/0007-Toil-package-builder.patch +++ /dev/null @@ -1,1327 +0,0 @@ -From 2d1416fc62016533e159f27352f17a7d97f022b1 Mon Sep 17 00:00:00 2001 -From: Pavel Boldin -Date: Fri, 13 Oct 2017 11:52:32 +0300 -Subject: [PATCH 07/89] Toil package builder - -Introduce a toil[1]-based workflow to automate patch building for -a package. - -[1] https://toil.readthedocs.io/ - -Change-Id: I7e3a11ad95781b8989d24fbf3992dcb49e4c8dba -Signed-off-by: Pavel Boldin ---- - packages/rhel7/glibc/glibc-2.17-55.el7/info | 23 +- - .../glibc/glibc-2.17-55.el7/pkgfile.yaml | 5 + - scripts/pkgbuild | 28 +- - scripts/toil/README.md | 1 + - scripts/toil/build-patch.sh | 18 + - scripts/toil/pkgbuild.py | 894 ++++++++++++++++++ - scripts/toil/requirements.txt | 4 + - scripts/toil/tests_pkgbuild.py | 218 +++++ - 8 files changed, 1175 insertions(+), 16 deletions(-) - create mode 100644 packages/rhel7/glibc/glibc-2.17-55.el7/pkgfile.yaml - create mode 100644 scripts/toil/README.md - create mode 100755 scripts/toil/build-patch.sh - create mode 100755 scripts/toil/pkgbuild.py - create mode 100644 scripts/toil/requirements.txt - create mode 100644 scripts/toil/tests_pkgbuild.py - -diff --git a/packages/rhel7/glibc/glibc-2.17-55.el7/info b/packages/rhel7/glibc/glibc-2.17-55.el7/info -index 9b13a12..8cebabb 100644 ---- a/packages/rhel7/glibc/glibc-2.17-55.el7/info -+++ b/packages/rhel7/glibc/glibc-2.17-55.el7/info -@@ -72,7 +72,16 @@ _install_originals() { - } - - _run_tests() { -- export LD_PRELOAD=/libcare/tests/execve/execve.so -+ if test -f $LIBCARE_DIR/execve/execve.so; then -+ LD_PRELOAD=$LIBCARE_DIR/execve/execve.so -+ elif test -f $LIBCARE_DIR/tests/execve/execve.so; then -+ LD_PRELOAD=$LIBCARE_DIR/tests/execve/execve.so -+ else -+ echo "Can't find execve.so required to run tests" -+ exit 1 -+ fi -+ -+ export LD_PRELOAD - - local ld_linux="$KP_PROJECT_BUILD_DIR/elf/ld*" - -@@ -110,9 +119,11 @@ kp_patch_test() { - rm -f /var/run/libcare.sock - - PATCH_ROOT=/root/${KP_PROJECT_PATCH%.*} -- /libcare/src/libcare-ctl -v server /var/run/libcare.sock $PATCH_ROOT \ -- >/root/test.log 2>&1 & : -+ $KPATCH_PATH/libcare-ctl -v server /var/run/libcare.sock $PATCH_ROOT \ -+ >/data/test.log 2>&1 & : - LISTENER_PID=$! -+ sleep 1 -+ kill -0 $LISTENER_PID - - pushd $KP_PROJECT_BUILD_DIR - -@@ -123,11 +134,11 @@ kp_patch_test() { - - popd - -- local patched=$(awk '/kpatch_ctl targeting/ { n++ } END { print n }' /root/test.log) -+ local patched=$(awk '/kpatch_ctl targeting/ { n++ } END { print n }' /data/test.log) - - test $patched -ge $executed - -- grep -vq 'No patch(es) applicable to' /root/test.log -- grep 'patch hunk(s) have been successfully applied' /root/test.log \ -+ grep -vq 'No patch(es) applicable to' /data/test.log -+ grep 'patch hunk(s) have been successfully applied' /data/test.log \ - | wc -l - } -diff --git a/packages/rhel7/glibc/glibc-2.17-55.el7/pkgfile.yaml b/packages/rhel7/glibc/glibc-2.17-55.el7/pkgfile.yaml -new file mode 100644 -index 0000000..51028ed ---- /dev/null -+++ b/packages/rhel7/glibc/glibc-2.17-55.el7/pkgfile.yaml -@@ -0,0 +1,5 @@ -+image: kernelcare/centos7:gcc-4.8.2-16.el7 -+prebuild: /tmp/build.orig-glibc-2.17-55.el7.x86_64.rpm.tgz -+input: -+- package: . -+- patches: ../../../../patches/ -diff --git a/scripts/pkgbuild b/scripts/pkgbuild -index e2ac7c7..8803db3 100755 ---- a/scripts/pkgbuild -+++ b/scripts/pkgbuild -@@ -54,8 +54,9 @@ prepare() { - - # Export env vars that are needed during the build - SCRIPTS="$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)" -- SPWD="$(realpath $SCRIPTS/../)" -- export KPATCH_PATH=$SPWD/src -+ LIBCARE_DIR="${LIBCARE_DIR:-$SCRIPTS/..}" -+ KPATCH_PATH="${KPATCH_PATH:-$LIBCARE_DIR/src}" -+ export LIBCARE_DIR KPATCH_PATH - export OLDPATH=$PATH - export KPATCH_PASSTHROUGH_ASM=1 - CPUS=`cat /proc/cpuinfo | grep ^processor | wc -l` -@@ -130,18 +131,20 @@ kp_prepare_source_deb() { - } - - kp_prepare_source() { -- echo " downloading source for $KP_PROJECT" -- kp_download_source_$KP_PROJECT_FORMAT -+ if ! test -f /kcdata/$KP_PROJECT_SOURCE; then -+ echo " downloading source for $KP_PROJECT" -+ kp_download_source_$KP_PROJECT_FORMAT -+ fi - echo " preparing source for $KP_PROJECT" - kp_prepare_source_$KP_PROJECT_FORMAT - } - - kp_patch_source() { - echo " patching project" -- PATCH_DIR=$SPWD/patches -+ PATCH_DIR=$LIBCARE_DIR/patches - #patch_list_apply requires this dir - mkdir -p /tmp/build.kpatch -- $SPWD/scripts/patch_list_apply $KP_PROJECT_DIR $PDIR/plist $PATCH_DIR -+ $SCRIPTS/patch_list_apply $KP_PROJECT_DIR $PDIR/plist $PATCH_DIR - } - - kp_prebuild_rpm() { -@@ -364,10 +367,10 @@ overwrite_utils() { - TMPBIN=$(mktemp -d --tmpdir) - - mkdir $TMPBIN/bin -- ln -fs /libcare/src/libcare-cc $TMPBIN/gcc -- ln -fs /libcare/src/libcare-cc $TMPBIN/cc -- ln -fs /libcare/src/libcare-cc $TMPBIN/g++ -- ln -fs /libcare/src/libcare-cc $TMPBIN/c++ -+ ln -fs $KPATCH_PATH/libcare-cc $TMPBIN/gcc -+ ln -fs $KPATCH_PATH/libcare-cc $TMPBIN/cc -+ ln -fs $KPATCH_PATH/libcare-cc $TMPBIN/g++ -+ ln -fs $KPATCH_PATH/libcare-cc $TMPBIN/c++ - if ! test -x /usr/bin/g++; then - rm -f $TMPBIN/g++ - fi -@@ -379,6 +382,11 @@ overwrite_utils() { - fi - - export PATH=$TMPBIN:$PATH -+ -+ if test "$(command -v cc)" != "$TMPBIN/cc"; then -+ echo "Can't install our wrappers, missing?" -+ exit 1 -+ fi - } - - kp_patch_test() { -diff --git a/scripts/toil/README.md b/scripts/toil/README.md -new file mode 100644 -index 0000000..5bc77b6 ---- /dev/null -+++ b/scripts/toil/README.md -@@ -0,0 +1 @@ -+This is where [toil](https://toil.readthedocs.io/)-based scripts do live. -diff --git a/scripts/toil/build-patch.sh b/scripts/toil/build-patch.sh -new file mode 100755 -index 0000000..0e12de4 ---- /dev/null -+++ b/scripts/toil/build-patch.sh -@@ -0,0 +1,18 @@ -+#!/bin/sh -e -+ -+exec 1>&2 -+ -+ln -fs /data /kcdata -+ -+ls -lR /data -+ -+yum install -y rpm-build -+ -+LIBCARE_DIR="/data" -+KPATCH_PATH="/data/src" -+export LIBCARE_DIR KPATCH_PATH -+make -C $KPATCH_PATH clean all -+make -C /data/execve clean all -+ -+/kcdata/scripts/pkgbuild $@ /kcdata/package -+ls /kcdata -lR -diff --git a/scripts/toil/pkgbuild.py b/scripts/toil/pkgbuild.py -new file mode 100755 -index 0000000..c4b009a ---- /dev/null -+++ b/scripts/toil/pkgbuild.py -@@ -0,0 +1,894 @@ -+#!/usr/bin/python -+""" -+Build package patches for libcare using toil[1] workflow framework. -+The basic components are the following: -+ -+#. `Storage` class that works like a filesystem directory. Changes made to it -+ are passed down the chain to all the jobs via `Promise` mechanism. The -+ `Storage` class is also responsible for importing and exporting local files. -+ -+#. `FileFetcherJob` job that downloads specified files from the net and puts them in -+ the storage. Supported are AWS S3, HTTP and FTP files. This is usually the -+ first job. -+ -+#. `DoBuild` checks presence of the object in the Storage and runs -+ `prebuildJob` chained with `uploadJob` and `buildJob` if the object is missing. -+ Only `buildJob` is run otherwise. -+ -+ This is used to build missing parts such as an archive with the baseline -+ source code called `prebuilt` which is listed as optional for the -+ `FileFetcherJob` job. -+ -+#. `DockerScriptJob` that brings up a Docker container from the specified image -+ and runs the Storage-suplied script with Storage content exposed into the -+ `/data` directory. -+ -+#. `UploadJob` that uploads specified objects from the Storage. -+ -+#. `DoIfMissing` checks presence of the object in the Storage and runs -+ specified job if it is missing. -+ -+#. `ChainJobs` is used to chain the jobs at the runtime. -+ -+ -+ -+All the updates to the Storage are carried from the children to the followOns -+via `Promise` mechanism. The root job returns Storage from the last followOn, -+this storage is then exported to a directory. -+ -+[1] https://toil.readthedocs.io/ -+""" -+ -+from __future__ import print_function -+ -+import boto3 -+import contextlib -+import collections -+import datetime -+import dateutil -+import errno -+import logging -+import os -+import requests -+import shutil -+import tarfile -+import tempfile -+import time -+import urlparse -+import yaml -+ -+from toil.common import Toil -+from toil.job import Job as toilJob -+from toil.lib.docker import dockerCall, dockerCheckOutput, STOP, RM, FORGO -+ -+ -+def myabspath(path_or_url, root=None): -+ """Return absolute path for an url or path.""" -+ if '://' not in path_or_url or path_or_url.startswith('file://'): -+ path_or_url = path_or_url.replace('file://', '') -+ if (path_or_url[0] == '.' or '/' not in path_or_url) and root: -+ path_or_url = os.path.join(root, path_or_url) -+ path_or_url = os.path.abspath(path_or_url) -+ return path_or_url -+ return -+ -+FileInfo = collections.namedtuple('FileInfo', ('fileName', 'url', 'required')) -+ -+def parseFileInfo(fileInfo): -+ """Parse fileInfo which is either an URL or a dictionary of form -+ {"fileName": "url"}. When url is prefixed with '*' the file is optional. -+ -+ Samples: -+ >>> parseFileInfo('http://kernel.org/index.html') -+ ... "index.html", "http://kernel.org/index.html", True -+ >>> parseFileInfo('*http://kernel.org/index.html') -+ ... "index.html", "http://kernel.org/index.html", False -+ >>> parseFileInfo({'foobar.html': '*http://kernel.org/index.html'}) -+ ... "foobar.html", "http://kernel.org/index.html", False -+ """ -+ if isinstance(fileInfo, basestring): -+ url = fileInfo -+ fileName = os.path.basename(url) -+ elif isinstance(fileInfo, dict): -+ items = fileInfo.items() -+ if len(items) != 1: -+ raise ValueError("only one-entry dicts are allowed as fileInfo") -+ fileName, url = items[0] -+ -+ required = True -+ if url.startswith('*'): -+ url = url.lstrip('*') -+ required = False -+ return FileInfo(fileName, url, required) -+ -+ -+class WorkflowToFileStoreProxy(object): -+ """ -+ Make File.copy and Directory.copy work with toil.common.Toil object. -+ """ -+ def __init__(self, workflow): -+ self.workflow = workflow -+ -+ def readGlobalFile(self, fileId): -+ tmpfile = tempfile.mktemp() -+ self.workflow.exportFile(fileId, 'file://' + tmpfile) -+ return tmpfile -+ -+ def writeGlobalFile(self, path): -+ return self.workflow.importFile('file:///' + path) -+ -+ def getLocalTempFile(self): -+ return tempfile.mktemp() -+ -+ -+class Storage(dict): -+ """Keeps files organized for the workflow. -+ -+ This is a dictionary that associates fileName with a file object such -+ as `File` or `Directory` class. -+ -+ Additional field `promised_updates` is used to keep track of updates -+ resulting from `Promise`s of children. -+ """ -+ def __init__(self, *args, **kwargs): -+ self.promised_updates = [] -+ if args: -+ self.promised_updates = list(args[0].promised_updates) -+ -+ super(Storage, self).__init__(*args, **kwargs) -+ -+ def update(self, other): -+ """Update this Storage with files from another.""" -+ if isinstance(other, Storage): -+ self.promised_updates.extend(other.promised_updates) -+ -+ if isinstance(other, dict): -+ super(Storage, self).update(other) -+ else: -+ self.promised_updates.append(other) -+ -+ def __setstate__(self, state): -+ """Unfold finished promised_updates.""" -+ self.promised_updates = [] -+ for promise in state['promised_updates']: -+ self.update(promise) -+ -+ def __repr__(self): -+ s = super(Storage, self).__repr__() -+ return s + (" %r" % self.promised_updates) -+ -+ @contextlib.contextmanager -+ def expose(self, rootDir=None): -+ """Expose Storage to a directory and pick up changes from it.""" -+ if rootDir is None: -+ rootDir = self.fileStore.getLocalTempDir() -+ try: -+ self.toDirectory(rootDir) -+ yield rootDir -+ finally: -+ self.cleanupDirectory(rootDir) -+ self.pickupDirectory(rootDir) -+ -+ def toDirectory(self, rootDir, export=False): -+ """Copy Storage content to the specified directory.""" -+ for fileObj in self.values(): -+ if export and isinstance(fileObj, (ImportedFile, ImportedDirectory)): -+ continue -+ fileObj.copy(self.fileStore, rootDir) -+ -+ def pickupDirectory(self, directory): -+ """Pick up content of the specified directory into the Storage.""" -+ files = ((name, os.path.join(directory, name)) -+ for name in os.listdir(directory)) -+ return self.pickupFiles(self.fileStore, files) -+ -+ def cleanupDirectory(self, rootDir): -+ """Remove storage files from the directory.""" -+ return -+ for fileName in self: -+ path = os.path.join(rootDir, fileName) -+ -+ if os.path.isdir(path): -+ shutil.rmtree(path) -+ else: -+ os.remove(path) -+ -+ def pickupFiles(self, fileStore, files): -+ """Pick up listed files into the Storage.""" -+ for fileName, path in files: -+ if fileName in self: -+ continue -+ -+ if os.path.isdir(path): -+ self[fileName] = Directory.fromFiles( -+ fileStore, [(fileName, path)]) -+ else: -+ self[fileName] = File.fromLocalFile( -+ fileStore, fileName, path) -+ -+ def importLocalFiles(self, workflow, inputs, rootDir=None): -+ """Import local files at the start of the workflow. -+ -+ This is usually a first step and is done: -+ >>> with Toil(options) as toil: -+ ... storage = Storage.importLocalFiles( -+ ... toil, -+ ... ['localfile.tar', 'secondfile', 'ascript.sh']) -+ ... rootJob = RootJob(storage) -+ """ -+ -+ localFiles = [] -+ remoteFiles = [] -+ -+ for fileInfo in inputs: -+ -+ fileName, url, required = parseFileInfo(fileInfo) -+ -+ path = myabspath(url, rootDir) -+ if path: -+ localFiles.append((fileName, path)) -+ else: -+ remoteFiles.append(fileInfo) -+ -+ for fileName, path in localFiles: -+ if fileName in self: -+ continue -+ -+ if os.path.isdir(path): -+ self[fileName] = ImportedDirectory.fromFiles( -+ workflow, fileName, [(fileName, path)]) -+ else: -+ try: -+ self[fileName] = ImportedFile.fromLocalFile( -+ workflow, fileName, path) -+ except IOError as ioerr: -+ if ioerr.errno != errno.ENOENT: -+ raise -+ -+ print("imported localFiles %s" % (", ".join(self))) -+ -+ inputs[:] = remoteFiles -+ -+ return self -+ -+ @classmethod -+ def fromLocalFiles(cls, workflow, inputs, rootDir=None): -+ storage = cls() -+ storage.importLocalFiles(workflow, inputs, rootDir) -+ return storage -+ -+ def exportLocalFiles(self, workflow, outputDir): -+ """Export local files at the end of workflow. -+ -+ This is the last step: -+ >>> with Toil(options) as toil: -+ ... ... -+ ... storage = toil.start(rootJob) -+ ... storage.exportLocalFiles(toil, 'outputDir') -+ """ -+ try: -+ self.fileStore = WorkflowToFileStoreProxy(workflow) -+ return self.toDirectory(outputDir, export=True) -+ finally: -+ del self.fileStore -+ -+ -+class File(object): -+ """A file in Storage.""" -+ def __init__(self, fileName, fileId, mode=None): -+ super(File, self).__init__() -+ self.fileName = fileName -+ self.fileId = fileId -+ self.mode = mode -+ -+ def copy(self, fileStore, dest): -+ localCopy = self.localCopy(fileStore) -+ if os.path.isdir(dest): -+ dest = os.path.join(dest, self.fileName) -+ shutil.copy(localCopy, dest) -+ if self.mode: -+ os.chmod(dest, self.mode) -+ -+ def localCopy(self, fileStore): -+ return fileStore.readGlobalFile(self.fileId) -+ -+ @contextlib.contextmanager -+ def open(self, fileStore): -+ localFile = self.localCopy(fileStore) -+ with open(localFile) as fh: -+ yield fh -+ -+ @classmethod -+ def fromLocalFile(cls, fileStore, fileName, path): -+ return cls(fileName, fileStore.writeGlobalFile(path), -+ mode=os.stat(path).st_mode) -+ -+ def __str__(self): -+ return "" % (self.fileName, self.fileId) -+ -+ __repr__ = __str__ -+ -+ -+class ImportedFile(object): -+ def __init__(self, fileName, mode=None): -+ super(ImportedFile, self).__init__() -+ self.fileName = fileName -+ self.mode = mode -+ -+ def copy(self, fileStore, dest): -+ if os.path.isdir(dest): -+ dest = os.path.join(dest, self.fileName) -+ with self.open(fileStore) as fhin: -+ with open(dest, 'w') as fhout: -+ shutil.copyfileobj(fhin, fhout) -+ if self.mode: -+ os.chmod(dest, self.mode) -+ -+ def localCopy(self, fileStore): -+ fileName = fileStore.getLocalTempFile() -+ self.copy(fileStore, fileName) -+ return fileName -+ -+ @contextlib.contextmanager -+ def open(self, fileStore): -+ with fileStore.jobStore.readSharedFileStream(self.fileName) as fh: -+ yield fh -+ -+ @classmethod -+ def fromLocalFile(cls, workflow, fileName, path): -+ workflow.importFile('file://' + path, sharedFileName=fileName) -+ -+ return cls( -+ fileName, -+ mode=os.stat(path).st_mode) -+ -+ def __str__(self): -+ return "" % self.fileName -+ -+ __repr__ = __str__ -+ -+ -+class Directory(object): -+ """A directory in Storage. Kept as an archive file.""" -+ def __init__(self, fileId): -+ super(Directory, self).__init__() -+ self.fileId = fileId -+ -+ def localCopy(self, fileStore, outDir=None): -+ localDir = outDir or fileStore.getLocalTempDir() -+ localFile = fileStore.readGlobalFile(self.fileId) -+ -+ tar = tarfile.TarFile.taropen(localFile) -+ tar.extractall(path=localDir) -+ -+ return localDir -+ -+ def copy(self, fileStore, dest): -+ self.localCopy(fileStore, dest) -+ -+ @classmethod -+ def fromFiles(cls, fileStore, files): -+ -+ with fileStore.writeGlobalFileStream() as (fh, fileId): -+ tar = tarfile.TarFile.open(fileobj=fh, mode='w') -+ -+ for fileName, path in files: -+ tar.add(path, arcname=fileName) -+ -+ return cls(fileId) -+ -+ def __str__(self): -+ return "" % self.fileId -+ -+ __repr__ = __str__ -+ -+ -+class ImportedDirectory(Directory): -+ -+ def localCopy(self, fileStore, outDir=None): -+ localDir = outDir or fileStore.getLocalTempDir() -+ -+ with fileStore.jobStore.readSharedFileStream(self.fileId) as fh: -+ tar = tarfile.TarFile(fileobj=fh, mode='r') -+ tar.extractall(path=localDir) -+ -+ return localDir -+ -+ @classmethod -+ def fromFiles(cls, workflow, dirName, files): -+ tmpfile = tempfile.mktemp() -+ -+ tar = tarfile.TarFile.open(tmpfile, mode='w') -+ -+ for fileName, path in files: -+ tar.add(path, arcname=fileName) -+ -+ tar.close() -+ -+ workflow.importFile('file://' + tmpfile, sharedFileName=dirName) -+ os.unlink(tmpfile) -+ -+ return cls(dirName) -+ -+ -+class IncorrectStorageUse(Exception): -+ message = "Child `Job`s with storage added outside of running parent " \ -+ "wont influence parent's storage. If this is not required " \ -+ "consider using addChildNoStorage and setting child's " \ -+ "storage via `self._storage = child.resultStorage`." -+ -+ def __init__(self): -+ super(IncorrectStorageUse, self).__init__(self.message) -+ -+ -+class Job(toilJob): -+ """Job with a Storage. -+ -+ This Job passes Storage down the workflow via `Promise` mechanism. -+ Updates to Storage from the children are merged and passed to the -+ followOns. -+ """ -+ -+ _running = False -+ def __init__(self, *args, **kwargs): -+ super(Job, self).__init__(*args, **kwargs) -+ self._storage = Storage() -+ self._childStorage = Storage() -+ -+ def rv(self, *path): -+ return super(Job, self).rv('rv', *path) -+ -+ @property -+ def storage(self): -+ if self._running: -+ return self._storage -+ else: -+ return super(Job, self).rv('storage') -+ -+ @property -+ def resultStorage(self): -+ return super(Job, self).rv('childStorage') -+ -+ def _updateStorage(self, succ, promise, ourStorage): -+ if not isinstance(succ, Job): -+ return -+ -+ succ._storage = promise -+ -+ if ourStorage is not None: -+ if self._running: -+ ourStorage.update(succ.storage) -+ else: -+ raise IncorrectStorageUse() -+ -+ def addChild(self, child): -+ """Add a child and update storage with it's promised storage""" -+ rv = super(Job, self).addChild(child) -+ self._updateStorage(child, self.storage, self._childStorage) -+ return rv -+ -+ def addFollowOn(self, followOn): -+ "Add a followOn. FollowOns receive storages with updates from children" -+ rv = super(Job, self).addFollowOn(followOn) -+ self._updateStorage(followOn, self.resultStorage, None) -+ return rv -+ -+ def addChildNoStorage(self, child): -+ """Add a child that won't contribute to the Storage. -+ -+ Typically used to add a child whose Storage will be used as a -+ predecessor' result. -+ """ -+ rv = super(Job, self).addChild(child) -+ self._updateStorage(child, self.storage, None) -+ return rv -+ -+ def _run(self, jobGraph, fileStore): -+ -+ self._running = True -+ -+ storage = self.storage -+ storage.fileStore = fileStore -+ -+ rv = super(Job, self)._run(jobGraph, fileStore) -+ -+ try: -+ del storage.fileStore -+ except AttributeError: -+ pass -+ self._running = False -+ -+ self._childStorage.update(self._storage) -+ -+ return { -+ 'rv': rv, -+ 'storage': self._storage, -+ 'childStorage': self._childStorage -+ } -+ -+ -+class NoSuchFile(Exception): -+ pass -+ -+ -+class FileFetcherJob(Job): -+ """Fetches files from the Web into the Storage. -+ -+ Accepts a list `fileInfo`s to download. There must be no local filesystem -+ files. Instead, fetcher should be primed with a Storage having them -+ imported via `importLocalFiles`. -+ """ -+ def __init__(self, files, storage=None, localRootDir=None): -+ super(FileFetcherJob, self).__init__(cores=1, memory="256M") -+ -+ if storage is not None: -+ self._storage = storage -+ -+ self.files = files -+ if localRootDir is None: -+ localRootDir = os.path.dirname(os.path.realpath(__file__)) -+ self.localRootDir = localRootDir -+ -+ remoteFiles = self.remoteFiles = [] -+ localFiles = [] -+ -+ for fileInfo in self.files: -+ -+ fileName, url, required = parseFileInfo(fileInfo) -+ if fileName in self._storage: -+ continue -+ -+ path = myabspath(url, self.localRootDir) -+ if path: -+ localFiles.append((fileName, path)) -+ else: -+ remoteFiles.append((fileName, url, required)) -+ -+ if localFiles: -+ raise Exception("Non-empty localFiles, did you forgot to importLocalFiles: %s?" % localFiles) -+ -+ -+ def run(self, fileStore): -+ -+ for fileInfo in self.remoteFiles: -+ -+ fileName, url, required = fileInfo -+ if fileName in self.storage: -+ continue -+ -+ try: -+ if url.startswith('s3://'): -+ child = S3DownloadJob(fileName, url) -+ else: -+ child = DownloadJob(fileName, url) -+ self.addChild(child) -+ except NoSuchFile: -+ if required: -+ raise -+ -+ -+class DownloadJob(Job): -+ """Download a HTTP or FTP file.""" -+ def __init__(self, fileName, url): -+ self.url = url -+ -+ request = requests.get(self.url, stream=True) -+ if request.status_code != 200: -+ raise NoSuchFile(self.url) -+ -+ disk = request.headers.get('Content-Length', '1G') -+ request.close() -+ self.fileName = fileName -+ -+ Job.__init__(self, unitName=url, memory="128M", cores=1, disk=disk) -+ -+ def run(self, fileStore): -+ r = requests.get(self.url, stream=True) -+ -+ with fileStore.writeGlobalFileStream() as (fh, fileId): -+ for chunk in r.iter_content(4096): -+ fh.write(chunk) -+ self.storage[self.fileName] = File(self.fileName, fileId) -+ -+ -+_CLIENT = None -+class S3FileJob(Job): -+ -+ def parseurl(self, desturl): -+ url = urlparse.urlparse(desturl) -+ if url.scheme != "s3": -+ raise Exception("URL %s is not S3 url" % desturl) -+ -+ self.url = url -+ self.bucket = self.url.netloc -+ self.key = self.url.path[1:] -+ self.desturl = desturl -+ -+ def client(cls): -+ -+ global _CLIENT -+ if _CLIENT is None: -+ _CLIENT = boto3.client('s3') -+ return _CLIENT -+ -+ -+class S3DownloadJob(S3FileJob): -+ """Download a file from AWS S3.""" -+ def __init__(self, fileName, url): -+ self.parseurl(url) -+ -+ try: -+ self.obj = self.client().get_object(Bucket=self.bucket, Key=self.key) -+ except self.client().exceptions.NoSuchKey: -+ raise NoSuchFile(url) -+ -+ self.fileName = fileName -+ super(S3DownloadJob, self).__init__( -+ memory="1M", cores=1, unitName="download %s" % url, -+ disk=self.obj['ContentLength']) -+ -+ def run(self, fileStore): -+ with fileStore.writeGlobalFileStream() as (fh, fileId): -+ self.client().download_fileobj(Bucket=self.bucket, Key=self.key, -+ Fileobj=fh) -+ self.storage[self.fileName] = File(self.fileName, fileId) -+ -+ -+class S3UploadJob(S3FileJob): -+ """Upload a file to AWS S3.""" -+ def __init__(self, fileId, url): -+ self.parseurl(url) -+ self.fileId = fileId -+ -+ super(S3UploadJob, self).__init__(memory="1M", cores=1, unitName="upload %s" % url) -+ -+ -+ def run(self, fileStore): -+ localFile = fileStore.readGlobalFile(self.fileId) -+ self.client().upload_file(localFile, self.bucket, self.key) -+ -+ -+class DockerScriptJob(Job): -+ """Run docker script on top of an exposed Storage.""" -+ -+ def __init__(self, script, image, -+ args=[], cores=4, disk="4G", -+ logfileName="docker-logfile"): -+ unitName = "image={image} script={script} args={args!r}".format( -+ image=image, script=script, args=args) -+ Job.__init__(self, cores=cores, disk=disk, unitName=unitName) -+ -+ self.script = script -+ -+ self.image = image -+ self.args = args -+ self.logfileName = logfileName -+ -+ def run(self, fileStore): -+ -+ e = None -+ with self.storage.expose() as dockerRoot: -+ logfilePath = os.path.join(dockerRoot, self.logfileName) -+ with open(logfilePath, "a") as logfilefh: -+ dockerDefer = fileStore.jobStore.config.dockerDefer -+ -+ dockerParameters = [] -+ if dockerDefer == RM: -+ dockerParameters.append('--rm') -+ -+ dockerParameters += ['-t', '-v', os.path.abspath(dockerRoot) + ':/data'] -+ #dockerParameters += ['--privileged'] -+ dockerParameters += ['--cap-add=SYS_PTRACE'] -+ -+ dockerCall(self, -+ tool=self.image, workDir=dockerRoot, -+ defer=dockerDefer, outfile=logfilefh, -+ parameters=["/data/build"] -+ + self.args, -+ dockerParameters=dockerParameters) -+ -+ return str(e) -+ -+ def __str__(self): -+ name = "build--script=%s--image=%s" % ( -+ os.path.basename(self.script), self.image) -+ return name.replace(':', '-').replace('=', '-').replace('/', '-') -+ -+ -+ -+DEFAULT_SCRIPT = './build-patch.sh' -+DEFAULT_IMAGE = 'centos:centos7' -+ -+UploadInfo = collections.namedtuple('UploadInfo', ('fileName', 'url')) -+ -+class UploadJob(Job): -+ """Upload files from the Storage. -+ -+ URLs passed are `uploadInfo` instances. -+ """ -+ def __init__(self, urls): -+ self.urls = [UploadInfo(*url) for url in urls] -+ -+ super(UploadJob, self).__init__() -+ -+ def run(self, fileStore): -+ for url in self.urls: -+ fileName, url = url -+ -+ fileObj = self.storage.get(fileName) -+ if fileObj is None: -+ continue -+ -+ path = myabspath(url) -+ if not path: -+ self.addChild(S3UploadJob(fileObj.fileId, url)) -+ else: -+ localFile = fileStore.readGlobalFile(fileObj.fileId) -+ shutil.copy(localFile, path) -+ -+ -+class DoBuild(Job): -+ """If prebuild archive is not in storage do a prebuild and upload it to the -+ specified location. Otherwise just do a build.""" -+ -+ def __init__(self, fileName, prebuildJob, uploadJob, buildJob): -+ super(DoBuild, self).__init__(memory="256M") -+ -+ self.fileName = fileName -+ self.prebuildJob = prebuildJob -+ self.buildJob = buildJob -+ self.uploadJob = uploadJob -+ -+ def run(self, fileStore): -+ if self.fileName not in self.storage: -+ self.addChild(self.prebuildJob) -+ -+ self.prebuildJob.addChildNoStorage(self.buildJob) -+ self.prebuildJob.addChildNoStorage(self.uploadJob) -+ else: -+ self.addChild(self.buildJob) -+ -+ self._storage = self.buildJob.storage -+ -+ -+class BuildPatchJob(toilJob): -+ """Root job for patch building. Fetches files and runs Docker jobs. -+ -+ The algorithm is the following: -+ 1. FileFetcherJob(inputs + optional prebuild). -+ -+ 2. If prebuild is there, just run DockerScriptJob with a build job. -+ -+ 3. If prebuild is missing, run DockerScriptJob. Chain UploadJob for it. -+ Start build job DockerScriptJob it. -+ """ -+ def __init__(self, storage, packageDescription): -+ super(BuildPatchJob, self).__init__(memory="256M") -+ -+ self.storage = storage -+ self.packageDescription = packageDescription -+ -+ self.script = packageDescription.get('script', DEFAULT_SCRIPT) -+ self.image = packageDescription.get('image', DEFAULT_IMAGE) -+ -+ self.inputs = list(packageDescription.get('input')) -+ -+ def run(self, fileStore): -+ -+ tail = self -+ -+ fetcher = FileFetcherJob(self.inputs, storage=self.storage) -+ tail.addFollowOn(fetcher) -+ tail = fetcher -+ -+ prebuildUrl = self.packageDescription['prebuild'] -+ prebuildName = os.path.basename(prebuildUrl) -+ -+ prebuildJob = DockerScriptJob( -+ script=self.script, -+ image=self.image, -+ args=['-p'], -+ logfileName="prebuild.log") -+ uploadJob = UploadJob([(prebuildName, prebuildUrl)]) -+ -+ buildJob = DockerScriptJob( -+ script=self.script, -+ image=self.image, -+ logfileName="build.log") -+ -+ -+ doBuild = DoBuild(fileName=prebuildName, prebuildJob=prebuildJob, -+ uploadJob=uploadJob, buildJob=buildJob) -+ tail.addFollowOn(doBuild) -+ tail = doBuild -+ -+ return tail.storage -+ -+ -+def get_default_outputDir(): -+ outputDir = os.path.join(os.getcwd(), 'libcare-output') -+ outputDir = os.path.join(outputDir, datetime.datetime.utcnow().isoformat()) -+ return outputDir -+ -+def readPackageDescription(packageFile): -+ with open(packageFile) as fh: -+ packageDescription = yaml.load(fh) -+ -+ inputs = packageDescription['input'] -+ -+ cwd = os.path.dirname(os.path.realpath(__file__)) -+ -+ script = packageDescription.get( -+ 'script', os.path.join(cwd, DEFAULT_SCRIPT)) -+ -+ inputs.append({'build': script}) -+ inputs.append({'scripts': os.path.join(cwd, '../../scripts')}) -+ inputs.append({'src': os.path.join(cwd, '../../src/')}) -+ inputs.append({'execve': os.path.join(cwd, '../../tests/execve')}) -+ -+ prebuildUrl = packageDescription['prebuild'] -+ if not prebuildUrl.startswith('*'): -+ prebuildUrl = '*' + prebuildUrl -+ inputs.append(prebuildUrl) -+ -+ return packageDescription -+ -+def start(toil): -+ -+ options = toil.options -+ -+ packageDescription = readPackageDescription(options.packageFile) -+ -+ path = myabspath(options.outputDir) -+ if path: -+ print("output directory is", path) -+ options.outputDir = path -+ else: -+ print("output url is", options.outputDir) -+ -+ rootDir = os.path.realpath(os.path.dirname(options.packageFile)) -+ -+ storage = Storage() -+ storage.importLocalFiles(toil, packageDescription['input'], rootDir=rootDir) -+ theJob = BuildPatchJob(storage, packageDescription) -+ -+ return toil.start(theJob) -+ -+def restart(toil): -+ packageDescription = readPackageDescription(toil.options.packageFile) -+ -+ rootDir = os.path.realpath(os.path.dirname(toil.options.packageFile)) -+ -+ Storage.fromLocalFiles(toil, packageDescription['input'], rootDir=rootDir) -+ -+ return toil.restart() -+ -+def main(): -+ parser = Job.Runner.getDefaultArgumentParser() -+ parser.add_argument('packageFile') -+ parser.add_argument('--outputDir', required=False, -+ default=get_default_outputDir()) -+ parser.add_argument('--dockerDefer', required=False, -+ default='RM') -+ options = parser.parse_args() -+ -+ options.disableCaching = True -+ -+ with Toil(options) as toil: -+ toil.config.dockerDefer = globals()[options.dockerDefer.upper()] -+ toil._jobStore.writeConfig() -+ -+ if not toil.options.restart: -+ storage = start(toil) -+ else: -+ storage = restart(toil) -+ -+ try: -+ os.makedirs(options.outputDir) -+ except OSError as e: -+ if e.errno != errno.EEXIST: -+ raise -+ storage.exportLocalFiles(toil, options.outputDir) -+ -+if __name__ == "__main__": -+ main() -diff --git a/scripts/toil/requirements.txt b/scripts/toil/requirements.txt -new file mode 100644 -index 0000000..ea481fa ---- /dev/null -+++ b/scripts/toil/requirements.txt -@@ -0,0 +1,4 @@ -+toil==3.10.1 -+boto3 -+requests -+pyyaml -diff --git a/scripts/toil/tests_pkgbuild.py b/scripts/toil/tests_pkgbuild.py -new file mode 100644 -index 0000000..f60643d ---- /dev/null -+++ b/scripts/toil/tests_pkgbuild.py -@@ -0,0 +1,218 @@ -+#!/usr/bin/python -+ -+import contextlib -+import functools -+import os -+import shutil -+from StringIO import StringIO -+import tempfile -+ -+from toil.common import Toil -+ -+import pkgbuild -+ -+def test_storage_update(): -+ Storage = pkgbuild.Storage -+ -+ storage = Storage(**{'test.sh': 'nothing'}) -+ newStorage = Storage(**{'test2.sh': 'nothing'}) -+ -+ storage.update('promised_value2') -+ newStorage.update('promised_value') -+ -+ newStorage.update(storage) -+ -+ assert newStorage == {'test.sh': 'nothing', 'test2.sh': 'nothing'} -+ assert newStorage.promised_updates == ['promised_value', 'promised_value2'] -+ assert Storage(newStorage) == newStorage -+ -+def test_storage_pickle(): -+ import cPickle -+ Storage = pkgbuild.Storage -+ -+ storage = Storage() -+ storage['abc'] = 'test' -+ storage.update('promised_value') -+ -+ storage = cPickle.loads(cPickle.dumps(storage, protocol=-1)) -+ assert storage['abc'] == 'test' -+ assert storage.promised_updates == ['promised_value'] -+ -+def test_parseFileInfo(): -+ parseFileInfo = pkgbuild.parseFileInfo -+ -+ info = parseFileInfo('http://kernel.org/index.html') -+ assert info == pkgbuild.FileInfo( -+ fileName='index.html', -+ url='http://kernel.org/index.html', -+ required=True) -+ -+ info = parseFileInfo('*http://kernel.org/index.html') -+ assert info == pkgbuild.FileInfo( -+ fileName='index.html', -+ url='http://kernel.org/index.html', -+ required=False) -+ -+ info = parseFileInfo({'foobar.html': 'http://kernel.org/index.html'}) -+ assert info == pkgbuild.FileInfo( -+ fileName='foobar.html', -+ url='http://kernel.org/index.html', -+ required=True) -+ -+ info = parseFileInfo({'foobar.html': '*http://kernel.org/index.html'}) -+ assert info == pkgbuild.FileInfo( -+ fileName='foobar.html', -+ url='http://kernel.org/index.html', -+ required=False) -+ -+ try: -+ info = parseFileInfo({ -+ 'foobar.html': '*http://kernel.org/index.html', -+ 'other': 'things'}) -+ except ValueError: -+ pass -+ else: -+ assert False -+ -+class FakeJobStorage(object): -+ def __init__(self, imported): -+ self.imported = imported -+ -+ @contextlib.contextmanager -+ def readSharedFileStream(self, fileId): -+ buf = fileId -+ if self.imported and fileId in self.imported: -+ buf = self.imported[fileId] -+ yield StringIO(buf) -+ -+class FakeFileStorage(object): -+ def __init__(self, imported=None): -+ self.localTempDir = tempfile.mkdtemp() -+ self.jobStore = FakeJobStorage(imported) -+ -+ def getLocalTempDir(self): -+ return self.localTempDir -+ -+ def readGlobalFile(self, fileId): -+ fileName = tempfile.mktemp() -+ with open(fileName, "w") as fh: -+ print(fileId) -+ fh.write(fileId) -+ return fileName -+ -+ def writeGlobalFile(self, path): -+ with open(path) as fh: -+ return fh.read() -+ -+ @contextlib.contextmanager -+ def writeGlobalFileStream(self): -+ fh_and_fileId = StringIO() -+ yield fh_and_fileId, fh_and_fileId -+ -+class FakeWorkflow(object): -+ def __init__(self): -+ self.imported = {} -+ -+ def importFile(self, path, sharedFileName): -+ self.imported[sharedFileName] = slurp(path.replace('file://', '')) -+ -+def slurp(fileName): -+ return open(fileName).read() -+ -+def test_storage(): -+ storage = pkgbuild.Storage( -+ **{ -+ 'file.txt': pkgbuild.File('file.txt', 'some content'), -+ 'imported.txt': pkgbuild.ImportedFile('imported.txt') -+ } -+ ) -+ storage.fileStore = FakeFileStorage() -+ -+ with storage.expose() as dirname: -+ -+ assert set(os.listdir(dirname)) == set(['file.txt', 'imported.txt']) -+ -+ assert slurp(os.path.join(dirname, 'file.txt')) == 'some content' -+ assert slurp(os.path.join(dirname, 'imported.txt')) == 'imported.txt' -+ -+ with open(os.path.join(dirname, 'newfile.txt'), 'w') as fh: -+ fh.write('and some content here') -+ -+ -+ assert storage['newfile.txt'].fileId == 'and some content here' -+ -+ with storage.expose() as dirname: -+ -+ -+ newdir = os.path.join(dirname, 'testdir') -+ os.mkdir(newdir) -+ with open(os.path.join(newdir, 'subfile'), "w") as fh: -+ fh.write('foobar') -+ -+ inputs = os.listdir(dirname) + ['http://somefile.com/index.html'] -+ workflow = FakeWorkflow() -+ newStorage = pkgbuild.Storage.fromLocalFiles( -+ workflow, inputs, dirname) -+ assert inputs == ['http://somefile.com/index.html'] -+ -+ -+ assert isinstance(newStorage['testdir'], pkgbuild.ImportedDirectory) -+ -+ newStorage.fileStore = FakeFileStorage(workflow.imported) -+ with newStorage.expose() as dirname: -+ -+ assert slurp(os.path.join(dirname, 'file.txt')) == 'some content' -+ assert slurp(os.path.join(dirname, 'imported.txt')) == 'imported.txt' -+ assert slurp(os.path.join(dirname, 'newfile.txt')) == 'and some content here' -+ assert slurp(os.path.join(dirname, 'testdir', 'subfile')) == 'foobar' -+ -+ -+class DummyStorageUpdate(pkgbuild.Job): -+ def __init__(self, filename): -+ super(DummyStorageUpdate, self).__init__(unitName=filename) -+ self.filename = filename -+ -+ def run(self, fileStore): -+ self.storage[self.filename] = 'something' -+ -+class DummyStorageAsChild(pkgbuild.Job): -+ def run(self, fileStore): -+ a = DummyStorageUpdate('bar') -+ self.addChild(a) -+ -+class RootJob(pkgbuild.Job): -+ def __init__(self, storage): -+ super(RootJob, self).__init__() -+ self._storage = storage -+ -+ def run(self, fileStore): -+ -+ tail = self -+ -+ a = DummyStorageUpdate('foo') -+ self.addChild(a) -+ tail = a -+ -+ b = DummyStorageAsChild() -+ tail.addFollowOn(b) -+ tail = b -+ -+ return tail.resultStorage -+ -+def test_job_storage(): -+ parser = pkgbuild.Job.Runner.getDefaultArgumentParser() -+ options = parser.parse_args(['test_job_storage']) -+ -+ options.workDir = tempfile.mkdtemp() -+ options.jobStore = os.path.join(options.workDir, 'workdir') -+ -+ storage = pkgbuild.Storage(foobar='here i go') -+ root = RootJob(storage=storage) -+ -+ try: -+ with Toil(options) as toil: -+ storage = toil.start(root) -+ finally: -+ shutil.rmtree(options.workDir) -+ -+ assert storage == {'foo': 'something', 'bar': 'something', 'foobar': 'here i go'} --- -2.23.0 - diff --git a/0008-pkgbuild-use-yumdownloader-if-source-url-is-missing.patch b/0008-pkgbuild-use-yumdownloader-if-source-url-is-missing.patch deleted file mode 100644 index 12416ff2acb82738b7ef6b4ef0aea6250c5c4c7a..0000000000000000000000000000000000000000 --- a/0008-pkgbuild-use-yumdownloader-if-source-url-is-missing.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 066da27aaf6b153c215bee353e7190fe226f5b3b Mon Sep 17 00:00:00 2001 -From: Pavel Boldin -Date: Thu, 14 Dec 2017 18:02:15 +0200 -Subject: [PATCH 08/89] pkgbuild: use yumdownloader if source url is missing - -Signed-off-by: Pavel Boldin ---- - scripts/pkgbuild | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/scripts/pkgbuild b/scripts/pkgbuild -index 8803db3..97c78a9 100755 ---- a/scripts/pkgbuild -+++ b/scripts/pkgbuild -@@ -105,7 +105,11 @@ kp_prepare_source_raw() { - - kp_download_source_rpm() { - mkdir -p /kcdata -- curl $KP_PROJECT_SOURCE_URL -o /kcdata/$KP_PROJECT_SOURCE -+ if test -n "$KP_PROJECT_SOURCE_URL"; then -+ curl $KP_PROJECT_SOURCE_URL -o /kcdata/$KP_PROJECT_SOURCE -+ else -+ yumdownloader --source --destdir /kcdata ${KP_PROJECT_SOURCE%.src.rpm} -+ fi - } - - kp_prepare_source_rpm() { --- -2.23.0 - diff --git a/0009-execve-abort-on-failure.patch b/0009-execve-abort-on-failure.patch deleted file mode 100644 index df6707d363783005257e811fabb9ab12e9be08b2..0000000000000000000000000000000000000000 --- a/0009-execve-abort-on-failure.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 2343fef023a8cd64473161fa82a0d81cb5007cf9 Mon Sep 17 00:00:00 2001 -From: Pavel Boldin -Date: Tue, 30 Jan 2018 00:04:54 +0200 -Subject: [PATCH 09/89] execve: abort() on failure - -Signed-off-by: Pavel Boldin ---- - tests/execve/execve.c | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/tests/execve/execve.c b/tests/execve/execve.c -index b3df0e4..eb3e9d3 100644 ---- a/tests/execve/execve.c -+++ b/tests/execve/execve.c -@@ -81,7 +81,7 @@ notify_listener(void) - sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (sock == -1) { - dprintf("socket() error: %s(%d)\n", strerror(errno), errno); -- return; -+ abort(); - } - dprintf("socket()\n"); - -@@ -96,7 +96,7 @@ notify_listener(void) - if (rv == -1) { - fprintf(stderr, "libcare-execve: connect() error: %s(%d)\n", strerror(errno), errno); - (void) close(sock); -- return; -+ abort(); - } - dprintf("connect()\n"); - -@@ -113,7 +113,7 @@ notify_listener(void) - if (rv == -1) { - fprintf(stderr, "send() error: %s(%d)\n", strerror(errno), errno); - (void) close(sock); -- return; -+ abort(); - } - dprintf("send()\n"); - -@@ -123,6 +123,7 @@ notify_listener(void) - - if (rv == -1) { - fprintf(stderr, "recv() error: %s(%d)\n", strerror(errno), errno); -+ abort(); - } - dprintf("recv()\n"); - --- -2.23.0 - diff --git a/0010-Add-test-stage-to-pkgbuild.patch b/0010-Add-test-stage-to-pkgbuild.patch deleted file mode 100644 index 55f72dd36fa1657d7a362072ccf94f1246a25aa9..0000000000000000000000000000000000000000 --- a/0010-Add-test-stage-to-pkgbuild.patch +++ /dev/null @@ -1,379 +0,0 @@ -From 7d431211063a9bf6c789bb67a2ed216025279a66 Mon Sep 17 00:00:00 2001 -From: Roman Rashchupkin -Date: Tue, 23 Jan 2018 13:41:38 +0300 -Subject: [PATCH 10/89] Add --test stage to pkgbuild - -Signed-off-by: Roman Rashchupkin ---- - packages/rhel7/glibc/glibc-2.17-55.el7/info | 36 ++++----- - .../glibc/glibc-2.17-55.el7/pkgfile.yaml | 1 + - scripts/pkgbuild | 81 ++++++++++++++++--- - scripts/toil/build-patch.sh | 1 - - scripts/toil/pkgbuild.py | 57 +++++++++---- - 5 files changed, 126 insertions(+), 50 deletions(-) - -diff --git a/packages/rhel7/glibc/glibc-2.17-55.el7/info b/packages/rhel7/glibc/glibc-2.17-55.el7/info -index 8cebabb..e5805c3 100644 ---- a/packages/rhel7/glibc/glibc-2.17-55.el7/info -+++ b/packages/rhel7/glibc/glibc-2.17-55.el7/info -@@ -55,21 +55,6 @@ kp_build_hook() { - $KP_PROJECT_BUILD_ROOT/SPECS/$KP_PROJECT_SPEC - } - --# Replace patch build results with original libraries for testing --_install_originals() { -- eval set -- $KP_INSTALL_FILES -- while test -n "$1"; do -- local buildpath="$1" -- local installpath="$2" -- shift 2 -- -- if test "$installpath" = "IGNORE"; then -- continue -- fi -- -- /bin/cp -r /root/root.original/$installpath $KP_PROJECT_BUILD_DIR/$buildpath -- done --} - - _run_tests() { - if test -f $LIBCARE_DIR/execve/execve.so; then -@@ -113,15 +98,22 @@ _run_tests() { - export PATH=$KCPATH - } - --kp_patch_test() { -- _install_originals -+kp_prepare_test_binaries() { -+ # Replace patch build results with original libraries for testing -+ kp_install_files /root/root.original \ -+ $KP_PROJECT_BUILD_DIR \ -+ "to_prebuild" \ -+ "$KP_INSTALL_FILES" -+} - -+kp_patch_test() { - rm -f /var/run/libcare.sock - -- PATCH_ROOT=/root/${KP_PROJECT_PATCH%.*} -+ PATCH_ROOT=$KP_PROJECT_BUILD_ROOT/storage - $KPATCH_PATH/libcare-ctl -v server /var/run/libcare.sock $PATCH_ROOT \ -- >/data/test.log 2>&1 & : -+ >/data/libcare-ctl.log 2>&1 & : - LISTENER_PID=$! -+ - sleep 1 - kill -0 $LISTENER_PID - -@@ -134,11 +126,11 @@ kp_patch_test() { - - popd - -- local patched=$(awk '/kpatch_ctl targeting/ { n++ } END { print n }' /data/test.log) -+ local patched=$(awk '/kpatch_ctl targeting/ { n++ } END { print n }' /data/libcare-ctl.log) - - test $patched -ge $executed - -- grep -vq 'No patch(es) applicable to' /data/test.log -- grep 'patch hunk(s) have been successfully applied' /data/test.log \ -+ grep -vq 'No patch(es) applicable to' /data/libcare-ctl.log -+ grep 'patch hunk(s) have been successfully applied' /data/libcare-ctl.log \ - | wc -l - } -diff --git a/packages/rhel7/glibc/glibc-2.17-55.el7/pkgfile.yaml b/packages/rhel7/glibc/glibc-2.17-55.el7/pkgfile.yaml -index 51028ed..b17e895 100644 ---- a/packages/rhel7/glibc/glibc-2.17-55.el7/pkgfile.yaml -+++ b/packages/rhel7/glibc/glibc-2.17-55.el7/pkgfile.yaml -@@ -1,5 +1,6 @@ - image: kernelcare/centos7:gcc-4.8.2-16.el7 - prebuild: /tmp/build.orig-glibc-2.17-55.el7.x86_64.rpm.tgz -+patch: /tmp/kpatch-glibc-2.17-55.el7.x86_64.tgz - input: - - package: . - - patches: ../../../../patches/ -diff --git a/scripts/pkgbuild b/scripts/pkgbuild -index 97c78a9..f91af57 100755 ---- a/scripts/pkgbuild -+++ b/scripts/pkgbuild -@@ -17,6 +17,7 @@ die() { - usage() { - echo "Usage: build [--prebuild] [--help] [--arch ARCH] DIR" - echo " -p|--prebuild prebuild project for further use" -+ echo " -t|--test run unit and stress tests" - echo " -a|--arch ARCH target architecture(x86_64 by default)" - echo " -h|--help print this message" - echo " DIR directory with project's info file and other resources" -@@ -32,6 +33,9 @@ prepare() { - -p|--prebuild) - ACTION=prebuild - ;; -+ -t|--test) -+ ACTION=test -+ ;; - -a|--arch) - shift - ARCH=$1 -@@ -247,13 +251,17 @@ kp_build_rpm() { - -bc \ - $KP_RPMBUILD_FLAGS \ - '--define "_topdir $KP_PROJECT_BUILD_ROOT"' \ -- $KP_PROJECT_BUILD_ROOT/SPECS/$KP_PROJECT_SPEC -+ $KP_PROJECT_BUILD_ROOT/SPECS/$KP_PROJECT_SPEC 2>&1 | -+ tee $KP_PROJECT_BUILD_ROOT/build.log - } - --kp_install_generic() { -- local ROOT_PATCHED="$HOME/root.patched" -+kp_install_files() { -+ local src="$1" -+ local dest="$2" -+ local direction="$3" -+ local files="$4" - -- eval set -- $KP_INSTALL_FILES -+ eval set -- $files - while test -n "$1"; do - local buildpath="$1" - local installpath="$2" -@@ -263,12 +271,16 @@ kp_install_generic() { - continue - fi - -- installpath="$ROOT_PATCHED/$installpath" -- -- mkdir -p "$(dirname "$installpath")" -- -- /bin/cp -ra $KP_PROJECT_BUILD_DIR/$buildpath $installpath -+ if test $direction = "from_prebuild"; then -+ install -D $src/$buildpath $dest/$installpath -+ else -+ install -D $src/$installpath $dest/$buildpath -+ fi - done -+} -+ -+kp_check_missing_files() { -+ local builddir="$1" - - local failed= - pushd $KP_PROJECT_BUILD_DIR -@@ -295,6 +307,16 @@ kp_install_generic() { - fi - } - -+kp_install_generic() { -+ local root_patched="$HOME/root.patched" -+ -+ kp_install_files $KP_PROJECT_BUILD_DIR \ -+ $root_patched \ -+ "from_prebuild" \ -+ "$KP_INSTALL_FILES" -+ kp_check_missing_files $KP_PROJECT_BUILD_DIR -+} -+ - kp_install_rpm() { - kp_install_orig_rpm - kp_install_generic -@@ -367,6 +389,33 @@ kp_pack_patch() { - popd - } - -+kp_unpack_patch() { -+ local tmpdir=$(mktemp -d --tmpdir) -+ -+ echo " unpacking patches for $KP_PROJECT into $KP_PROJECT_BUILD_ROOT/storage" -+ -+ tar -xf /kcdata/$KP_PROJECT_PATCH -C $tmpdir -+ -+ find $tmpdir -name \*.kpatch > $tmpdir/patchlist -+ -+ while read patchfile; do -+ local patchname=${patchfile##*/} -+ local buildid=${patchname%.kpatch} -+ -+ local KP_STORAGE=$KP_PROJECT_BUILD_ROOT/storage/$buildid -+ -+ mkdir -p $KP_STORAGE/1 -+ cp $patchfile $KP_STORAGE/1/kpatch.bin -+ ln -rs $KP_STORAGE/1 $KP_STORAGE/latest -+ done < $tmpdir/patchlist -+ -+ rm -fr $tmpdir -+} -+ -+kp_mark_tests_fail() { -+ touch /kcdata/Tests-FAIL -+} -+ - overwrite_utils() { - TMPBIN=$(mktemp -d --tmpdir) - -@@ -394,7 +443,8 @@ overwrite_utils() { - } - - kp_patch_test() { -- : -+ echo "Empty kp_patch_test called, override it!" -+ exit 1 - } - - main() { -@@ -408,20 +458,25 @@ main() { - - kp_prepare_env_hook - -- if [ "$ACTION" == "prebuild" ]; then -+ if test "$ACTION" == "prebuild"; then - kp_prepare_source - kp_prebuild_hook - kp_prebuild - kp_pack_prebuilt -- else -+ elif test "$ACTION" == "build"; then - kp_unpack_prebuilt - kp_patch_source - kp_build_hook - kp_build - kp_sanity_check - kp_gen_kpatch -- kp_patch_test - kp_pack_patch -+ elif test "$ACTION" == "test"; then -+ kp_unpack_prebuilt -+ kp_prepare_test_binaries -+ kp_unpack_patch -+ #kp_patch_source -+ kp_patch_test - fi - - #clean_dirs -diff --git a/scripts/toil/build-patch.sh b/scripts/toil/build-patch.sh -index 0e12de4..28720a1 100755 ---- a/scripts/toil/build-patch.sh -+++ b/scripts/toil/build-patch.sh -@@ -15,4 +15,3 @@ make -C $KPATCH_PATH clean all - make -C /data/execve clean all - - /kcdata/scripts/pkgbuild $@ /kcdata/package --ls /kcdata -lR -diff --git a/scripts/toil/pkgbuild.py b/scripts/toil/pkgbuild.py -index c4b009a..e091032 100755 ---- a/scripts/toil/pkgbuild.py -+++ b/scripts/toil/pkgbuild.py -@@ -12,8 +12,9 @@ The basic components are the following: - first job. - - #. `DoBuild` checks presence of the object in the Storage and runs -- `prebuildJob` chained with `uploadJob` and `buildJob` if the object is missing. -- Only `buildJob` is run otherwise. -+ `prebuildJob` chained with `uploadPrebuildJob`, `buildJob`, -+ `uploadPatchJob` and `testJob` if the object is missing. -+ Only `buildJob` and it's children are run otherwise. - - This is used to build missing parts such as an archive with the baseline - source code called `prebuilt` which is listed as optional for the -@@ -625,7 +626,7 @@ class S3DownloadJob(S3FileJob): - self.fileName = fileName - super(S3DownloadJob, self).__init__( - memory="1M", cores=1, unitName="download %s" % url, -- disk=self.obj['ContentLength']) -+ disk=max(4096, self.obj['ContentLength'])) - - def run(self, fileStore): - with fileStore.writeGlobalFileStream() as (fh, fileId): -@@ -731,24 +732,35 @@ class DoBuild(Job): - """If prebuild archive is not in storage do a prebuild and upload it to the - specified location. Otherwise just do a build.""" - -- def __init__(self, fileName, prebuildJob, uploadJob, buildJob): -+ def __init__(self, prebuildFileName, buildFileName, prebuildJob, uploadPrebuildJob, buildJob, uploadPatchJob, testJob): - super(DoBuild, self).__init__(memory="256M") - -- self.fileName = fileName -+ self.prebuildFileName = prebuildFileName -+ self.buildFileName = buildFileName - self.prebuildJob = prebuildJob - self.buildJob = buildJob -- self.uploadJob = uploadJob -+ self.uploadPrebuildJob = uploadPrebuildJob -+ self.uploadPatchJob = uploadPatchJob -+ self.testJob = testJob - - def run(self, fileStore): -- if self.fileName not in self.storage: -+ if self.prebuildFileName not in self.storage: - self.addChild(self.prebuildJob) - - self.prebuildJob.addChildNoStorage(self.buildJob) -- self.prebuildJob.addChildNoStorage(self.uploadJob) -+ self.prebuildJob.addChildNoStorage(self.uploadPrebuildJob) -+ -+ self.buildJob.addChildNoStorage(self.uploadPatchJob) -+ self.buildJob.addChildNoStorage(self.testJob) - else: -- self.addChild(self.buildJob) -+ if self.buildFileName not in self.storage: -+ self.addChild(self.buildJob) -+ self.buildJob.addChildNoStorage(self.uploadPatchJob) -+ self.buildJob.addChildNoStorage(self.testJob) -+ else: -+ self.addChild(self.testJob) - -- self._storage = self.buildJob.storage -+ self._storage = self.testJob.storage - - - class BuildPatchJob(toilJob): -@@ -784,21 +796,33 @@ class BuildPatchJob(toilJob): - prebuildUrl = self.packageDescription['prebuild'] - prebuildName = os.path.basename(prebuildUrl) - -+ patchUrl = self.packageDescription['patch'] -+ buildName = os.path.basename(patchUrl) -+ - prebuildJob = DockerScriptJob( - script=self.script, - image=self.image, -- args=['-p'], -+ args=['--prebuild'], - logfileName="prebuild.log") -- uploadJob = UploadJob([(prebuildName, prebuildUrl)]) -+ uploadPrebuildJob = UploadJob([(prebuildName, prebuildUrl)]) -+ - - buildJob = DockerScriptJob( - script=self.script, - image=self.image, - logfileName="build.log") -+ uploadPatchJob = UploadJob([(buildName, patchUrl)]) - -+ testJob = DockerScriptJob( -+ script=self.script, -+ image=self.image, -+ args=['--test'], -+ logfileName="test.log") -+ -+ doBuild = DoBuild(prebuildFileName=prebuildName, buildFileName=buildName, prebuildJob=prebuildJob, -+ uploadPrebuildJob=uploadPrebuildJob, buildJob=buildJob, -+ uploadPatchJob=uploadPatchJob, testJob=testJob) - -- doBuild = DoBuild(fileName=prebuildName, prebuildJob=prebuildJob, -- uploadJob=uploadJob, buildJob=buildJob) - tail.addFollowOn(doBuild) - tail = doBuild - -@@ -831,6 +855,11 @@ def readPackageDescription(packageFile): - prebuildUrl = '*' + prebuildUrl - inputs.append(prebuildUrl) - -+ patchUrl = packageDescription['patch'] -+ if not patchUrl.startswith('*'): -+ patchUrl = '*' + patchUrl -+ inputs.append(patchUrl) -+ - return packageDescription - - def start(toil): --- -2.23.0 - diff --git a/0011-glibc-minimal-readme-for-toil-builder.patch b/0011-glibc-minimal-readme-for-toil-builder.patch deleted file mode 100644 index 25e2f6eea628c6c2bff9fd1b204417c254688510..0000000000000000000000000000000000000000 --- a/0011-glibc-minimal-readme-for-toil-builder.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0c0f6387230d6164eaa58ae4a95656539ace5159 Mon Sep 17 00:00:00 2001 -From: Pavel Boldin -Date: Tue, 30 Jan 2018 16:42:32 +0200 -Subject: [PATCH 11/89] glibc: minimal readme for toil builder - -Signed-off-by: Pavel Boldin ---- - packages/rhel7/glibc/glibc-2.17-55.el7/README.md | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - create mode 100644 packages/rhel7/glibc/glibc-2.17-55.el7/README.md - -diff --git a/packages/rhel7/glibc/glibc-2.17-55.el7/README.md b/packages/rhel7/glibc/glibc-2.17-55.el7/README.md -new file mode 100644 -index 0000000..740d294 ---- /dev/null -+++ b/packages/rhel7/glibc/glibc-2.17-55.el7/README.md -@@ -0,0 +1,16 @@ -+Use toil-based build script to build patches for the `glibc`. For that simple -+run:: -+ -+```shell -+$ LIBCARE_DIR=~/libcare-opensource -+$ pip install -r $LIBCARE_DIR/scripts/toil/requirements.txt -+$ python $LIBCARE_DIR/scripts/toil/pkgbuild.py workdir pkgfile.yaml -+... -+``` -+ -+This should build the following files: -+```shell -+$ ls /tmp/build.orig-glibc-2.17-55.el7.x86_64.rpm.tgz /tmp/kpatch-glibc-2.17-55.el7.x86_64.tgz -+/tmp/build.orig-glibc-2.17-55.el7.x86_64.rpm.tgz -+/tmp/kpatch-glibc-2.17-55.el7.x86_64.tgz -+``` --- -2.23.0 - diff --git a/0012-Fix-kpatch_process_init-kpatch_coroutines_free.patch b/0012-Fix-kpatch_process_init-kpatch_coroutines_free.patch deleted file mode 100644 index 4cad170d6927796063d7698d34aa5cc3177b5c26..0000000000000000000000000000000000000000 --- a/0012-Fix-kpatch_process_init-kpatch_coroutines_free.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 3566489ee43a348f41bb0fd9c779f1064956ea82 Mon Sep 17 00:00:00 2001 -From: Roman Rashchupkin -Date: Thu, 25 Jan 2018 10:18:33 +0300 -Subject: [PATCH 12/89] Fix kpatch_process_init/kpatch_coroutines_free - ---- - src/kpatch_coro.c | 7 ++++--- - src/kpatch_process.c | 4 ++-- - 2 files changed, 6 insertions(+), 5 deletions(-) - -diff --git a/src/kpatch_coro.c b/src/kpatch_coro.c -index ff485fc..45d4a0b 100644 ---- a/src/kpatch_coro.c -+++ b/src/kpatch_coro.c -@@ -622,7 +622,8 @@ void kpatch_coroutines_free(struct kpatch_process *proc) - if (proc->coro.unwd) - unw_destroy_addr_space(proc->coro.unwd); - -- list_for_each_entry_safe(c, tmp, &proc->coro.coros, list) { -- kpatch_coro_free(c); -- } -+ if (!list_empty(&proc->coro.coros)) -+ list_for_each_entry_safe(c, tmp, &proc->coro.coros, list) { -+ kpatch_coro_free(c); -+ } - } -diff --git a/src/kpatch_process.c b/src/kpatch_process.c -index d394925..2f85373 100644 ---- a/src/kpatch_process.c -+++ b/src/kpatch_process.c -@@ -1121,10 +1121,10 @@ kpatch_process_init(kpatch_process_t *proc, - list_init(&proc->vmaholes); - proc->num_objs = 0; - -- if (process_get_comm(proc)) -- goto out_unlock; - if (kpatch_coroutines_init(proc)) - goto out_unlock; -+ if (process_get_comm(proc)) -+ goto out_unlock; - - return 0; - --- -2.23.0 - diff --git a/0013-Add-libcare-stresstest.patch b/0013-Add-libcare-stresstest.patch deleted file mode 100644 index 314113ea6842ec01cf378b32ad891c7d49fe6990..0000000000000000000000000000000000000000 --- a/0013-Add-libcare-stresstest.patch +++ /dev/null @@ -1,206 +0,0 @@ -From 4cd3610aa11c7b6add5cf090127c522d8004a528 Mon Sep 17 00:00:00 2001 -From: Roman Rashchupkin -Date: Wed, 24 Jan 2018 16:01:51 +0300 -Subject: [PATCH 13/89] Add libcare-stresstest - ---- - src/Makefile | 10 ++++- - src/kpatch_user.c | 106 +++++++++++++++++++++++++++++++++++++++++++++- - 2 files changed, 114 insertions(+), 2 deletions(-) - -diff --git a/src/Makefile b/src/Makefile -index cd766e1..58e942a 100644 ---- a/src/Makefile -+++ b/src/Makefile -@@ -3,7 +3,8 @@ TARGETS = kpatch_gensrc \ - kpatch_strip \ - libcare-cc \ - libcare-client \ -- libcare-ctl -+ libcare-ctl \ -+ libcare-stresstest - DEBUG = yes # comment out this line if not debug - - CC = gcc -@@ -39,6 +40,10 @@ libcare-ctl: kpatch_user.o kpatch_storage.o kpatch_patch.c kpatch_elf.o kpatch_p - libcare-ctl: kpatch_process.o kpatch_common.o rbtree.o kpatch_log.o - libcare-ctl: LDLIBS += -lelf -lrt $(LIBUNWIND_LIBS) - -+libcare-stresstest: kpatch_user-stresstest.o kpatch_storage.o kpatch_patch.c kpatch_elf.o kpatch_ptrace.o kpatch_coro.o -+libcare-stresstest: kpatch_process.o kpatch_common.o rbtree.o kpatch_log.o -+libcare-stresstest: LDLIBS += -lelf -lrt $(LIBUNWIND_LIBS) -+ - libcare-client: libcare-client.o - - kpatch_strip: kpatch_strip.o kpatch_elf_objinfo.o kpatch_log.o -@@ -61,6 +66,9 @@ endif - %.o: %.c deps/%.d - $(CC) $(CFLAGS) $(CFLAGS_$(*)) -o $(@) -c $(<) - -+%-stresstest.o: %.c -+ $(CC) -DSTRESS_TEST=1 $(CFLAGS) $(CFLAGS_$(*)) -o $(@) -c $(<) -+ - clean: - rm -rf *.o core.* deps/*.d $(TARGETS) - for f in tests/gensrc/*.s; do \ -diff --git a/src/kpatch_user.c b/src/kpatch_user.c -index d257b67..e6649b0 100644 ---- a/src/kpatch_user.c -+++ b/src/kpatch_user.c -@@ -6,6 +6,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -563,6 +564,88 @@ cmd_update(int argc, char *argv[]) - /* send_fd */ -1); - } - -+#ifdef STRESS_TEST -+ -+struct test_data { -+ int option_period; -+ int stat_cycle_num; -+} test_info = { .option_period = 0, .stat_cycle_num = 0 }; -+ -+static int -+server_wait(int pid, int period) -+{ -+ struct timespec req, rem; -+ int i; -+ req.tv_sec = 0; -+ req.tv_nsec = 1000*1000; -+ for (i=0; i 0) -+ close(fd); -+ fd = -1; -+ if (test_info.option_period == 0) -+ return 0; -+ delay = rand() % test_info.option_period; -+ if (server_wait(pid, delay) < 0) -+ return 0; -+ -+ while (processes_unpatch(pid, 0, 0) < 0) -+ if (server_wait(pid, 1) < 0) -+ return 0; -+ test_info.stat_cycle_num++; -+ -+ delay = rand() % test_info.option_period; -+ if (server_wait(pid, delay) < 0) -+ return 0; -+ } -+ -+ return 0; -+} -+ -+static int cmd_stress_test(int fd, int argc, char *argv[]) -+{ -+ int child = fork(); -+ if (child == 0) { -+ int rv = server_stress_test(fd, argc, argv); -+ exit(rv); -+ } -+ close(fd); -+ return 0; -+} -+ -+static int usage_stresstest() -+{ -+ fprintf(stderr, "usage: libcare-stresstest PERIOD(ms, 0 - only patch) [STORAGE ROOT]\n"); -+ return -1; -+} -+ -+#endif -+ - static int - server_execute_cmd(int fd, int argc, char *argv[]) - { -@@ -572,8 +655,13 @@ server_execute_cmd(int fd, int argc, char *argv[]) - - if (!strcmp(cmd, "execve")) - return cmd_execve_startup(fd, argc, argv, 1); -- if (!strcmp(cmd, "startup")) -+ if (!strcmp(cmd, "startup")) { -+#ifdef STRESS_TEST -+ return cmd_stress_test(fd, argc, argv); -+#else - return cmd_execve_startup(fd, argc, argv, 0); -+#endif -+ } - if (!strcmp(cmd, "update")) - return cmd_update(argc, argv); - if (!strcmp(cmd, "storage")) -@@ -739,6 +827,12 @@ cmd_server(int argc, char *argv[]) - return -1; - } - -+#ifdef STRESS_TEST -+ if (sscanf(argv[0], "%d", &test_info.option_period) != 1) { -+ kplogerror("Can't parse period from %s\n", argv[0]); -+ } -+#endif -+ - sfd = server_bind_socket(argv[1]); - if (sfd < 0) - return sfd; -@@ -824,6 +918,9 @@ static int usage(const char *err) - { - if (err) - fprintf(stderr, "err: %s\n", err); -+#ifdef STRESS_TEST -+ return usage_stresstest(); -+#endif - fprintf(stderr, "usage: libcare-ctl [options] [args]\n"); - fprintf(stderr, "\nOptions:\n"); - fprintf(stderr, " -v - verbose mode\n"); -@@ -872,6 +969,12 @@ int main(int argc, char *argv[]) - argc -= optind; - argv += optind; - -+#ifdef STRESS_TEST -+ if (argc < 3) -+ return usage("not enough arguments."); -+ signal(SIGCHLD, SIG_IGN); -+ return cmd_server(argc, argv); -+#else - if (argc < 1) - return usage("not enough arguments."); - -@@ -879,4 +982,5 @@ int main(int argc, char *argv[]) - return cmd_server(argc, argv); - else - return execute_cmd(argc, argv); -+#endif - } --- -2.23.0 - diff --git a/0014-read-auxv-from-proc-pid-auxv.patch b/0014-read-auxv-from-proc-pid-auxv.patch deleted file mode 100644 index 94c7f62836a68586e48cc90120d792ea656904a1..0000000000000000000000000000000000000000 --- a/0014-read-auxv-from-proc-pid-auxv.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 212e98a668117a11aa528e5669189b58dcaacd95 Mon Sep 17 00:00:00 2001 -From: Pavel Boldin -Date: Wed, 7 Feb 2018 09:14:39 +0200 -Subject: [PATCH 14/89] read auxv from /proc/pid/auxv - -Signed-off-by: Pavel Boldin ---- - src/kpatch_ptrace.c | 54 +++++++++++++++++---------------------------- - 1 file changed, 20 insertions(+), 34 deletions(-) - -diff --git a/src/kpatch_ptrace.c b/src/kpatch_ptrace.c -index f732004..f91b80e 100644 ---- a/src/kpatch_ptrace.c -+++ b/src/kpatch_ptrace.c -@@ -143,55 +143,41 @@ int kpatch_process_mem_iter_peek_ulong(struct process_mem_iter *iter, - return kpatch_process_mem_iter_peek(iter, dst, sizeof(*dst), remote_addr); - } - --/* FIXME(pboldin): read these from /proc/pid/auxv */ - int kpatch_ptrace_get_entry_point(struct kpatch_ptrace_ctx *pctx, - unsigned long *pentry_point) - { -- int ret; -- unsigned long *rstack, val; -- struct user_regs_struct regs; -- struct process_mem_iter *iter; -+ int fd, ret; -+ unsigned long entry[2] = { AT_NULL, 0 }; -+ char path[sizeof("/proc/0123456789/auxv")]; - - kpdebug("Looking for entry point..."); - -- ret = ptrace(PTRACE_GETREGS, pctx->pid, NULL, ®s); -- if (ret < 0) { -- kplogerror("can't get regs\n"); -- return -1; -- } -- -- iter = kpatch_process_mem_iter_init(pctx->proc); -- if (!iter) { -- kplogerror("can't allocate iterator\n"); -+ sprintf(path, "/proc/%d/auxv", pctx->pid); -+ fd = open(path, O_RDONLY); -+ if (fd == -1) { -+ kplogerror("can't open %s\n", path); - return -1; - } - -- /* Read stack and look for AUX data */ -- rstack = (unsigned long*)regs.rsp; -- -- /* rstack now points to envs */ -- rstack += PEEK_ULONG(rstack) + 2; -- -- /* Skip envs */ -- for (; PEEK_ULONG(rstack); rstack++) -- continue; -+ do { -+ ret = read(fd, entry, sizeof(entry)); -+ if (ret < 0 && errno == EINTR) -+ continue; -+ if (ret != sizeof(entry)) -+ break; - -- /* Now got to AUX */ -- for (rstack++; (val = PEEK_ULONG(rstack)) != AT_NULL; rstack += 2) { -- if (val == AT_ENTRY) { -- *pentry_point = PEEK_ULONG(rstack + 1); -+ if (entry[0] == AT_ENTRY) { -+ *pentry_point = entry[1]; - break; - } -- } -+ } while (1); - -- if (val != AT_ENTRY) -- kpdebug("FAIL\n"); -- else -- kpdebug("OK\n"); -+ if (ret < 0) -+ kplogerror("reading %s\n", path); - -- kpatch_process_mem_iter_free(iter); -+ close(fd); - -- return val == AT_ENTRY ? 0 : -1; -+ return entry[0] == AT_ENTRY ? 0 : -1; - } - - #define BREAK_INSN_LENGTH 1 --- -2.23.0 - diff --git a/0015-add-fail-to-unpatch-test.patch b/0015-add-fail-to-unpatch-test.patch deleted file mode 100644 index d21ea94a20d9d6275f288a2b840208d67da3da8d..0000000000000000000000000000000000000000 --- a/0015-add-fail-to-unpatch-test.patch +++ /dev/null @@ -1,147 +0,0 @@ -From f25aa052cd31cab4c6301cca5eb8e5e5f129d5bd Mon Sep 17 00:00:00 2001 -From: Pavel Boldin -Date: Wed, 7 Feb 2018 23:59:39 +0200 -Subject: [PATCH 15/89] add `fail to unpatch` test - -Add a test sample where patch is always busy in the loop and cannot -be unapplied. - -Signed-off-by: Pavel Boldin ---- - tests/fail_unpatch/Makefile | 4 ++++ - tests/fail_unpatch/desc | 1 + - tests/fail_unpatch/fail_unpatch.c | 29 ++++++++++++++++++++++++++++ - tests/fail_unpatch/fail_unpatch.diff | 11 +++++++++++ - tests/run_tests.sh | 25 ++++++++++++++++++++++-- - 5 files changed, 68 insertions(+), 2 deletions(-) - create mode 100644 tests/fail_unpatch/Makefile - create mode 100644 tests/fail_unpatch/desc - create mode 100644 tests/fail_unpatch/fail_unpatch.c - create mode 100644 tests/fail_unpatch/fail_unpatch.diff - -diff --git a/tests/fail_unpatch/Makefile b/tests/fail_unpatch/Makefile -new file mode 100644 -index 0000000..d7680e9 ---- /dev/null -+++ b/tests/fail_unpatch/Makefile -@@ -0,0 +1,4 @@ -+ -+LDLIBS:=-lpthread -+ -+include ../makefile.inc -diff --git a/tests/fail_unpatch/desc b/tests/fail_unpatch/desc -new file mode 100644 -index 0000000..02151c5 ---- /dev/null -+++ b/tests/fail_unpatch/desc -@@ -0,0 +1 @@ -+fails to unpatch the code -diff --git a/tests/fail_unpatch/fail_unpatch.c b/tests/fail_unpatch/fail_unpatch.c -new file mode 100644 -index 0000000..6b5c50f ---- /dev/null -+++ b/tests/fail_unpatch/fail_unpatch.c -@@ -0,0 +1,29 @@ -+#include -+#include -+ -+void print_greetings_patched(void) -+{ -+ while (1) { -+ printf("Hello. This a PATCHED version!\n"); -+ sleep(1); -+ } -+} -+ -+void print_greetings(void) -+{ -+ printf("Hello. This is an UNPATCHED version!\n"); -+} -+ -+void do_work() { -+ while (1) { -+ print_greetings(); -+ sleep(1); -+ } -+} -+ -+int main() -+{ -+ do_work(); -+ -+ return 0; -+} -diff --git a/tests/fail_unpatch/fail_unpatch.diff b/tests/fail_unpatch/fail_unpatch.diff -new file mode 100644 -index 0000000..49738bd ---- /dev/null -+++ b/tests/fail_unpatch/fail_unpatch.diff -@@ -0,0 +1,11 @@ -+--- ./fail_unpatch.c 2018-02-07 18:39:27.145493215 +0200 -++++ ./fail_unpatch.c 2018-02-07 18:39:43.349482218 +0200 -+@@ -11,7 +11,7 @@ -+ -+ void print_greetings(void) -+ { -+- printf("Hello. This is an UNPATCHED version!\n"); -++ print_greetings_patched(); -+ } -+ -+ void do_work() { -diff --git a/tests/run_tests.sh b/tests/run_tests.sh -index fbfb273..2bdd303 100755 ---- a/tests/run_tests.sh -+++ b/tests/run_tests.sh -@@ -105,6 +105,10 @@ check_result() { - ! grep_tail 'UNPATCHED' - return $? - ;; -+ fail_unpatch) -+ grep_tail '\${outfile}_patched -+ cat ${outfile}_patched - -+ echo "============unpatching===============" >>$logfile - libcare_ctl unpatch-user -p $pid \ -- >$logfile 2>&1 || : -+ >>$logfile 2>&1 || : - - sleep 2 - --- -2.23.0 - diff --git a/0016-Waitpid-for-finished-threads-after-detach.patch b/0016-Waitpid-for-finished-threads-after-detach.patch deleted file mode 100644 index 06e525d03ad1b8527705019cf221de25baa13dfb..0000000000000000000000000000000000000000 --- a/0016-Waitpid-for-finished-threads-after-detach.patch +++ /dev/null @@ -1,67 +0,0 @@ -From b6b35d80755caed0528dfdf3825ecf055fe9ea76 Mon Sep 17 00:00:00 2001 -From: Roman Rashchupkin -Date: Wed, 28 Feb 2018 23:05:50 +0300 -Subject: [PATCH 16/89] Waitpid for finished threads after detach. - ---- - src/kpatch_process.c | 14 +++++++++++++- - src/kpatch_ptrace.c | 2 +- - 2 files changed, 14 insertions(+), 2 deletions(-) - -diff --git a/src/kpatch_process.c b/src/kpatch_process.c -index 2f85373..5c0374a 100644 ---- a/src/kpatch_process.c -+++ b/src/kpatch_process.c -@@ -12,6 +12,11 @@ - #include - #include - -+#include -+#include -+#include -+#include -+ - #include - #include - #include -@@ -537,6 +542,8 @@ static void - process_detach(kpatch_process_t *proc) - { - struct kpatch_ptrace_ctx *p, *ptmp; -+ int status; -+ pid_t pid; - - if (proc->memfd >= 0 && close(proc->memfd) < 0) - kplogerror("can't close memfd"); -@@ -546,9 +553,14 @@ process_detach(kpatch_process_t *proc) - unw_destroy_addr_space(proc->ptrace.unwd); - - list_for_each_entry_safe(p, ptmp, &proc->ptrace.pctxs, list) { -- kpatch_ptrace_detach(p); -+ if (kpatch_ptrace_detach(p) == -ESRCH) { -+ do { -+ pid = waitpid(p->pid, &status, __WALL); -+ } while (pid > 0 && !WIFEXITED(status)); -+ } - kpatch_ptrace_ctx_destroy(p); - } -+ kpinfo("Finished ptrace detaching."); - } - - static int -diff --git a/src/kpatch_ptrace.c b/src/kpatch_ptrace.c -index f91b80e..a5f61b3 100644 ---- a/src/kpatch_ptrace.c -+++ b/src/kpatch_ptrace.c -@@ -1186,7 +1186,7 @@ int kpatch_ptrace_detach(struct kpatch_ptrace_ctx *pctx) - ret = ptrace(PTRACE_DETACH, pctx->pid, NULL, NULL); - if (ret < 0) { - kplogerror("can't detach from %d\n", pctx->pid); -- return -1; -+ return -errno; - } - - kpdebug("OK\n"); --- -2.23.0 - diff --git a/0017-.gitignore-build-artefacts.patch b/0017-.gitignore-build-artefacts.patch deleted file mode 100644 index 9634ca479102f2872e033337d50ba92bfb5799b9..0000000000000000000000000000000000000000 --- a/0017-.gitignore-build-artefacts.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 90a310f57710abb3f5e41c431d26e77fef63ad2b Mon Sep 17 00:00:00 2001 -From: Pavel Boldin -Date: Thu, 13 Sep 2018 12:00:02 +0300 -Subject: [PATCH 17/89] .gitignore build artefacts - -Signed-off-by: Pavel Boldin ---- - .gitignore | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/.gitignore b/.gitignore -index 5761abc..065f093 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -1 +1,10 @@ - *.o -+*.d -+src/kpatch_gensrc -+src/kpatch_make -+src/kpatch_strip -+src/libcare-cc -+src/libcare-client -+src/libcare-ctl -+src/libcare-stresstest -+tags --- -2.23.0 - diff --git a/0018-kpatch_storage-put-an-end-to-description-string-load.patch b/0018-kpatch_storage-put-an-end-to-description-string-load.patch deleted file mode 100644 index 3bf9df526e82ba343e5cbbf40f40cac3673d22d6..0000000000000000000000000000000000000000 --- a/0018-kpatch_storage-put-an-end-to-description-string-load.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 3954dd43124e87c788352ccc528cc79e8fca6f6d Mon Sep 17 00:00:00 2001 -From: YiFan -Date: Tue, 13 Aug 2019 11:02:36 +0800 -Subject: [PATCH 18/89] kpatch_storage: put an end to description string loaded - -Description string should be ended up with a '\0'. ---- - src/kpatch_storage.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/src/kpatch_storage.c b/src/kpatch_storage.c -index a466460..2375559 100644 ---- a/src/kpatch_storage.c -+++ b/src/kpatch_storage.c -@@ -377,8 +377,10 @@ char *storage_get_description(kpatch_storage_t *storage, - if (rv == -1) - goto err_free; - -- if (rv == 0) -+ if (rv == 0) { -+ desc[sz] = '\0'; - break; -+ } - - sz += rv; - } --- -2.23.0 - diff --git a/0019-Fix-README-files.patch b/0019-Fix-README-files.patch deleted file mode 100644 index 54db1acb1379b0bf2b20414edc5891c6de697feb..0000000000000000000000000000000000000000 --- a/0019-Fix-README-files.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 43e10a5ef1db3c56a872e3a61edaf224b51822f0 Mon Sep 17 00:00:00 2001 -From: Pavel Artsishevsky -Date: Tue, 18 Feb 2020 15:21:26 +0300 -Subject: [PATCH 19/89] Fix README files - -- Update patch build instructions for GHOST sample; -- Add Travis CI status image to main readme file. ---- - README.rst | 3 +++ - samples/ghost/README.rst | 11 +++++++++++ - 2 files changed, 14 insertions(+) - -diff --git a/README.rst b/README.rst -index 927325d..932b7c5 100644 ---- a/README.rst -+++ b/README.rst -@@ -1,6 +1,9 @@ - LibCare -- Patch Userspace Code on Live Processes - ================================================= - -+.. image:: https://travis-ci.org/cloudlinux/libcare.svg?branch=master -+ :target: https://travis-ci.org/cloudlinux/libcare -+ - Welcome to LibCare --- Live Patch Updates for Userspace Processes and Libraries. - - LibCare delivers live patches to any of your Linux executables or libraries at -diff --git a/samples/ghost/README.rst b/samples/ghost/README.rst -index da97926..e274b54 100644 ---- a/samples/ghost/README.rst -+++ b/samples/ghost/README.rst -@@ -32,6 +32,17 @@ Now, from inside the container let's install vulnerable version of glibc: - glibc-headers-2.17-55.el7 glibc-common-2.17-55.el7 - ... - -+Also we have to downgrade elfutils since newer versions of ``eu-unstrip`` -+fail to work with glibc utilities: -+ -+.. code:: console -+ -+ [root@... /]# yum downgrade -y --enablerepo=C7.0.1406-base \ -+ elfutils-devel-0.158-3.el7.x86_64 elfutils-0.158-3.el7.x86_64 \ -+ elfutils-libs-0.158-3.el7.x86_64 elfutils-libelf-0.158-3.el7.x86_64 \ -+ elfutils-libelf-devel-0.158-3.el7.x86_64 -+ ... -+ - Build the ``libcare`` tools: - - .. code:: console --- -2.23.0 - diff --git a/0020-include-Create-include-directory-for-header-files.patch b/0020-include-Create-include-directory-for-header-files.patch deleted file mode 100644 index 7890a97f76164a2b9a007167df3694fb6845c287..0000000000000000000000000000000000000000 --- a/0020-include-Create-include-directory-for-header-files.patch +++ /dev/null @@ -1,129 +0,0 @@ -From ca5872b354b7987ce2dfd6f5268771268ad006d0 Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Sat, 10 Oct 2020 16:46:38 +0800 -Subject: [PATCH 20/89] include: Create include directory for header files - -Move all header files from src directory into newly created include directory - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/{ => include}/kpatch_common.h | 0 - src/{ => include}/kpatch_coro.h | 0 - src/{ => include}/kpatch_dbgfilter.h | 0 - src/{ => include}/kpatch_elf.h | 0 - src/{ => include}/kpatch_elf_objinfo.h | 0 - src/{ => include}/kpatch_file.h | 0 - src/{ => include}/kpatch_flags.h | 0 - src/{ => include}/kpatch_io.h | 0 - src/{ => include}/kpatch_log.h | 0 - src/{ => include}/kpatch_parse.h | 0 - src/{ => include}/kpatch_patch.h | 0 - src/{ => include}/kpatch_process.h | 0 - src/{ => include}/kpatch_ptrace.h | 0 - src/{ => include}/kpatch_storage.h | 0 - src/{ => include}/kpatch_str.h | 0 - src/{ => include}/kpatch_user.h | 0 - src/{ => include}/list.h | 0 - src/{ => include}/rbtree.h | 0 - src/{ => include}/util.h | 0 - 19 files changed, 0 insertions(+), 0 deletions(-) - rename src/{ => include}/kpatch_common.h (100%) - rename src/{ => include}/kpatch_coro.h (100%) - rename src/{ => include}/kpatch_dbgfilter.h (100%) - rename src/{ => include}/kpatch_elf.h (100%) - rename src/{ => include}/kpatch_elf_objinfo.h (100%) - rename src/{ => include}/kpatch_file.h (100%) - rename src/{ => include}/kpatch_flags.h (100%) - rename src/{ => include}/kpatch_io.h (100%) - rename src/{ => include}/kpatch_log.h (100%) - rename src/{ => include}/kpatch_parse.h (100%) - rename src/{ => include}/kpatch_patch.h (100%) - rename src/{ => include}/kpatch_process.h (100%) - rename src/{ => include}/kpatch_ptrace.h (100%) - rename src/{ => include}/kpatch_storage.h (100%) - rename src/{ => include}/kpatch_str.h (100%) - rename src/{ => include}/kpatch_user.h (100%) - rename src/{ => include}/list.h (100%) - rename src/{ => include}/rbtree.h (100%) - rename src/{ => include}/util.h (100%) - -diff --git a/src/kpatch_common.h b/src/include/kpatch_common.h -similarity index 100% -rename from src/kpatch_common.h -rename to src/include/kpatch_common.h -diff --git a/src/kpatch_coro.h b/src/include/kpatch_coro.h -similarity index 100% -rename from src/kpatch_coro.h -rename to src/include/kpatch_coro.h -diff --git a/src/kpatch_dbgfilter.h b/src/include/kpatch_dbgfilter.h -similarity index 100% -rename from src/kpatch_dbgfilter.h -rename to src/include/kpatch_dbgfilter.h -diff --git a/src/kpatch_elf.h b/src/include/kpatch_elf.h -similarity index 100% -rename from src/kpatch_elf.h -rename to src/include/kpatch_elf.h -diff --git a/src/kpatch_elf_objinfo.h b/src/include/kpatch_elf_objinfo.h -similarity index 100% -rename from src/kpatch_elf_objinfo.h -rename to src/include/kpatch_elf_objinfo.h -diff --git a/src/kpatch_file.h b/src/include/kpatch_file.h -similarity index 100% -rename from src/kpatch_file.h -rename to src/include/kpatch_file.h -diff --git a/src/kpatch_flags.h b/src/include/kpatch_flags.h -similarity index 100% -rename from src/kpatch_flags.h -rename to src/include/kpatch_flags.h -diff --git a/src/kpatch_io.h b/src/include/kpatch_io.h -similarity index 100% -rename from src/kpatch_io.h -rename to src/include/kpatch_io.h -diff --git a/src/kpatch_log.h b/src/include/kpatch_log.h -similarity index 100% -rename from src/kpatch_log.h -rename to src/include/kpatch_log.h -diff --git a/src/kpatch_parse.h b/src/include/kpatch_parse.h -similarity index 100% -rename from src/kpatch_parse.h -rename to src/include/kpatch_parse.h -diff --git a/src/kpatch_patch.h b/src/include/kpatch_patch.h -similarity index 100% -rename from src/kpatch_patch.h -rename to src/include/kpatch_patch.h -diff --git a/src/kpatch_process.h b/src/include/kpatch_process.h -similarity index 100% -rename from src/kpatch_process.h -rename to src/include/kpatch_process.h -diff --git a/src/kpatch_ptrace.h b/src/include/kpatch_ptrace.h -similarity index 100% -rename from src/kpatch_ptrace.h -rename to src/include/kpatch_ptrace.h -diff --git a/src/kpatch_storage.h b/src/include/kpatch_storage.h -similarity index 100% -rename from src/kpatch_storage.h -rename to src/include/kpatch_storage.h -diff --git a/src/kpatch_str.h b/src/include/kpatch_str.h -similarity index 100% -rename from src/kpatch_str.h -rename to src/include/kpatch_str.h -diff --git a/src/kpatch_user.h b/src/include/kpatch_user.h -similarity index 100% -rename from src/kpatch_user.h -rename to src/include/kpatch_user.h -diff --git a/src/list.h b/src/include/list.h -similarity index 100% -rename from src/list.h -rename to src/include/list.h -diff --git a/src/rbtree.h b/src/include/rbtree.h -similarity index 100% -rename from src/rbtree.h -rename to src/include/rbtree.h -diff --git a/src/util.h b/src/include/util.h -similarity index 100% -rename from src/util.h -rename to src/include/util.h --- -2.23.0 - diff --git a/0021-src-Update-header-file-position.patch b/0021-src-Update-header-file-position.patch deleted file mode 100644 index f15ef137228f00a295695d3207c56bd0176a12d9..0000000000000000000000000000000000000000 --- a/0021-src-Update-header-file-position.patch +++ /dev/null @@ -1,373 +0,0 @@ -From 64f163e9bd26b0af65f12e7cc4205da0d787e7fc Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Sat, 10 Oct 2020 16:50:15 +0800 -Subject: [PATCH 21/89] src: Update header file position - -Update header file positon with include prefix to source file in src directory. - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/kpatch_common.c | 6 +++--- - src/kpatch_coro.c | 12 ++++++------ - src/kpatch_dbgfilter.c | 6 +++--- - src/kpatch_elf.c | 14 +++++++------- - src/kpatch_elf_objinfo.c | 6 +++--- - src/kpatch_gensrc.c | 8 ++++---- - src/kpatch_io.c | 6 +++--- - src/kpatch_log.c | 2 +- - src/kpatch_make.c | 2 +- - src/kpatch_parse.c | 6 +++--- - src/kpatch_patch.c | 20 ++++++++++---------- - src/kpatch_process.c | 14 +++++++------- - src/kpatch_ptrace.c | 8 ++++---- - src/kpatch_storage.c | 14 +++++++------- - src/kpatch_strip.c | 8 ++++---- - src/kpatch_user.c | 18 +++++++++--------- - src/rbtree.c | 2 +- - 17 files changed, 76 insertions(+), 76 deletions(-) - -diff --git a/src/kpatch_common.c b/src/kpatch_common.c -index 99bc0b3..95d4a54 100644 ---- a/src/kpatch_common.c -+++ b/src/kpatch_common.c -@@ -6,9 +6,9 @@ - #include - #include - --#include "kpatch_file.h" --#include "kpatch_common.h" --#include "kpatch_log.h" -+#include "include/kpatch_file.h" -+#include "include/kpatch_common.h" -+#include "include/kpatch_log.h" - - int kpatch_openat_file(int atfd, const char *fname, struct kp_file *kpatch) - { -diff --git a/src/kpatch_coro.c b/src/kpatch_coro.c -index 45d4a0b..02d421b 100644 ---- a/src/kpatch_coro.c -+++ b/src/kpatch_coro.c -@@ -8,12 +8,12 @@ - - #include - --#include "kpatch_user.h" --#include "kpatch_coro.h" --#include "kpatch_common.h" --#include "kpatch_elf.h" --#include "kpatch_ptrace.h" --#include "kpatch_log.h" -+#include "include/kpatch_user.h" -+#include "include/kpatch_coro.h" -+#include "include/kpatch_common.h" -+#include "include/kpatch_elf.h" -+#include "include/kpatch_ptrace.h" -+#include "include/kpatch_log.h" - - /* Indicates that the next CORO flavours should be tried */ - #define CORO_SEARCH_NEXT (1<<31) -diff --git a/src/kpatch_dbgfilter.c b/src/kpatch_dbgfilter.c -index 73a9bc3..d385c18 100644 ---- a/src/kpatch_dbgfilter.c -+++ b/src/kpatch_dbgfilter.c -@@ -1,9 +1,9 @@ - #include - #include - --#include "kpatch_parse.h" --#include "kpatch_str.h" --#include "kpatch_dbgfilter.h" -+#include "include/kpatch_parse.h" -+#include "include/kpatch_str.h" -+#include "include/kpatch_dbgfilter.h" - - static int is_cold_hot(char *s) - { -diff --git a/src/kpatch_elf.c b/src/kpatch_elf.c -index e42642b..b1dfed0 100644 ---- a/src/kpatch_elf.c -+++ b/src/kpatch_elf.c -@@ -7,13 +7,13 @@ - - #include - --#include "kpatch_common.h" --#include "kpatch_user.h" --#include "kpatch_process.h" --#include "kpatch_elf.h" --#include "kpatch_file.h" --#include "kpatch_ptrace.h" --#include "kpatch_log.h" -+#include "include/kpatch_common.h" -+#include "include/kpatch_user.h" -+#include "include/kpatch_process.h" -+#include "include/kpatch_elf.h" -+#include "include/kpatch_file.h" -+#include "include/kpatch_ptrace.h" -+#include "include/kpatch_log.h" - - static int - elf_object_peek_phdr(struct object_file *o) -diff --git a/src/kpatch_elf_objinfo.c b/src/kpatch_elf_objinfo.c -index 65b7144..c967c37 100644 ---- a/src/kpatch_elf_objinfo.c -+++ b/src/kpatch_elf_objinfo.c -@@ -4,9 +4,9 @@ - - #include - --#include "kpatch_common.h" --#include "kpatch_elf_objinfo.h" --#include "kpatch_log.h" -+#include "include/kpatch_common.h" -+#include "include/kpatch_elf_objinfo.h" -+#include "include/kpatch_log.h" - - const char *kpatch_objinfo_strptr(kpatch_objinfo *oi, int type, size_t nameidx) - { -diff --git a/src/kpatch_gensrc.c b/src/kpatch_gensrc.c -index a15fa2c..a16b652 100644 ---- a/src/kpatch_gensrc.c -+++ b/src/kpatch_gensrc.c -@@ -4,10 +4,10 @@ - #include - #include - --#include "kpatch_log.h" --#include "kpatch_parse.h" --#include "kpatch_dbgfilter.h" --#include "kpatch_flags.h" -+#include "include/kpatch_log.h" -+#include "include/kpatch_parse.h" -+#include "include/kpatch_dbgfilter.h" -+#include "include/kpatch_flags.h" - - #define OS_RHEL5 1 - #define OS_RHEL6 2 -diff --git a/src/kpatch_io.c b/src/kpatch_io.c -index 663bed0..7bdc298 100644 ---- a/src/kpatch_io.c -+++ b/src/kpatch_io.c -@@ -4,9 +4,9 @@ - #include - #include - --#include "kpatch_log.h" --#include "kpatch_io.h" --#include "kpatch_str.h" -+#include "include/kpatch_log.h" -+#include "include/kpatch_io.h" -+#include "include/kpatch_str.h" - - void *kp_realloc(void *p, int oldsz, int newsz) - { -diff --git a/src/kpatch_log.c b/src/kpatch_log.c -index de80f7b..6e48de4 100644 ---- a/src/kpatch_log.c -+++ b/src/kpatch_log.c -@@ -4,7 +4,7 @@ - #include - #include - --#include "kpatch_log.h" -+#include "include/kpatch_log.h" - - int log_level = LOG_INFO; - int log_indent; -diff --git a/src/kpatch_make.c b/src/kpatch_make.c -index c584b06..6a173e6 100644 ---- a/src/kpatch_make.c -+++ b/src/kpatch_make.c -@@ -9,7 +9,7 @@ - #include - #include - --#include "kpatch_file.h" -+#include "include/kpatch_file.h" - - #define ALIGN(x, align) ((x + align - 1) & (~(align - 1))) - -diff --git a/src/kpatch_parse.c b/src/kpatch_parse.c -index 358916b..dfb3109 100644 ---- a/src/kpatch_parse.c -+++ b/src/kpatch_parse.c -@@ -1,8 +1,8 @@ - #include - --#include "kpatch_log.h" --#include "kpatch_parse.h" --#include "kpatch_flags.h" -+#include "include/kpatch_log.h" -+#include "include/kpatch_parse.h" -+#include "include/kpatch_flags.h" - - char *cline(struct kp_file *f, int l) - { -diff --git a/src/kpatch_patch.c b/src/kpatch_patch.c -index e32c702..21a160a 100644 ---- a/src/kpatch_patch.c -+++ b/src/kpatch_patch.c -@@ -10,16 +10,16 @@ - #include - #include - --#include "kpatch_patch.h" --#include "kpatch_user.h" --#include "kpatch_storage.h" --#include "kpatch_process.h" --#include "kpatch_file.h" --#include "kpatch_common.h" --#include "kpatch_elf.h" --#include "kpatch_ptrace.h" --#include "list.h" --#include "kpatch_log.h" -+#include "include/kpatch_patch.h" -+#include "include/kpatch_user.h" -+#include "include/kpatch_storage.h" -+#include "include/kpatch_process.h" -+#include "include/kpatch_file.h" -+#include "include/kpatch_common.h" -+#include "include/kpatch_elf.h" -+#include "include/kpatch_ptrace.h" -+#include "include/list.h" -+#include "include/kpatch_log.h" - - - static inline int -diff --git a/src/kpatch_process.c b/src/kpatch_process.c -index 5c0374a..3f7f2f6 100644 ---- a/src/kpatch_process.c -+++ b/src/kpatch_process.c -@@ -23,13 +23,13 @@ - - #include - --#include "kpatch_process.h" --#include "kpatch_file.h" --#include "kpatch_common.h" --#include "kpatch_elf.h" --#include "kpatch_ptrace.h" --#include "list.h" --#include "kpatch_log.h" -+#include "include/kpatch_process.h" -+#include "include/kpatch_file.h" -+#include "include/kpatch_common.h" -+#include "include/kpatch_elf.h" -+#include "include/kpatch_ptrace.h" -+#include "include/list.h" -+#include "include/kpatch_log.h" - - /* - * Locks process by opening /proc//maps -diff --git a/src/kpatch_ptrace.c b/src/kpatch_ptrace.c -index a5f61b3..8910aa8 100644 ---- a/src/kpatch_ptrace.c -+++ b/src/kpatch_ptrace.c -@@ -15,10 +15,10 @@ - #include - #include - --#include "kpatch_process.h" --#include "kpatch_common.h" --#include "kpatch_ptrace.h" --#include "kpatch_log.h" -+#include "include/kpatch_process.h" -+#include "include/kpatch_common.h" -+#include "include/kpatch_ptrace.h" -+#include "include/kpatch_log.h" - - #include - -diff --git a/src/kpatch_storage.c b/src/kpatch_storage.c -index 2375559..9165cbf 100644 ---- a/src/kpatch_storage.c -+++ b/src/kpatch_storage.c -@@ -10,13 +10,13 @@ - #include - #include - --#include "kpatch_storage.h" --#include "kpatch_file.h" --#include "kpatch_common.h" --#include "kpatch_elf.h" --#include "kpatch_ptrace.h" --#include "list.h" --#include "kpatch_log.h" -+#include "include/kpatch_storage.h" -+#include "include/kpatch_file.h" -+#include "include/kpatch_common.h" -+#include "include/kpatch_elf.h" -+#include "include/kpatch_ptrace.h" -+#include "include/list.h" -+#include "include/kpatch_log.h" - - - /***************************************************************************** -diff --git a/src/kpatch_strip.c b/src/kpatch_strip.c -index b4de32d..6ad56a3 100644 ---- a/src/kpatch_strip.c -+++ b/src/kpatch_strip.c -@@ -7,13 +7,13 @@ - #include - #include - #include --#include "kpatch_file.h" --#include "kpatch_common.h" -+#include "include/kpatch_file.h" -+#include "include/kpatch_common.h" - - #include --#include "kpatch_elf_objinfo.h" -+#include "include/kpatch_elf_objinfo.h" - --#include "kpatch_log.h" -+#include "include/kpatch_log.h" - - #define ALIGN(off,sz) (((off)+(sz)-1)&~((sz)-1)) - -diff --git a/src/kpatch_user.c b/src/kpatch_user.c -index e6649b0..11e3408 100644 ---- a/src/kpatch_user.c -+++ b/src/kpatch_user.c -@@ -16,15 +16,15 @@ - #include - #include - --#include "kpatch_user.h" --#include "kpatch_storage.h" --#include "kpatch_patch.h" --#include "kpatch_process.h" --#include "kpatch_file.h" --#include "kpatch_common.h" --#include "kpatch_elf.h" --#include "list.h" --#include "kpatch_log.h" -+#include "include/kpatch_user.h" -+#include "include/kpatch_storage.h" -+#include "include/kpatch_patch.h" -+#include "include/kpatch_process.h" -+#include "include/kpatch_file.h" -+#include "include/kpatch_common.h" -+#include "include/kpatch_elf.h" -+#include "include/list.h" -+#include "include/kpatch_log.h" - - /* Global variables */ - static char storage_dir[PATH_MAX] = "/var/lib/libcare"; -diff --git a/src/rbtree.c b/src/rbtree.c -index fee5844..6aff1d1 100644 ---- a/src/rbtree.c -+++ b/src/rbtree.c -@@ -21,7 +21,7 @@ - linux/lib/rbtree.c - */ - --#include "rbtree.h" -+#include "include/rbtree.h" - - /* - * red-black trees properties: http://en.wikipedia.org/wiki/Rbtree --- -2.23.0 - diff --git a/0022-arch-Create-arch-directory-to-support-multi-arch.patch b/0022-arch-Create-arch-directory-to-support-multi-arch.patch deleted file mode 100644 index 5399258421a4f8385989c38f93ae16ac19d9fe78..0000000000000000000000000000000000000000 --- a/0022-arch-Create-arch-directory-to-support-multi-arch.patch +++ /dev/null @@ -1,73 +0,0 @@ -From b0d5f7f4e15bd19e7dc055b3f24171a3b14aa445 Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Sat, 10 Oct 2020 16:59:16 +0800 -Subject: [PATCH 22/89] arch: Create arch directory to support multi-arch - -Create directory arch/aarch64 and arch/x86 hold arch-related source files. -Create arch-related source files in libcare. -Files list below are architecture dependent: - arch_coro.c - arch_elf.c - arch_parse.c - arch_patch.c - arch_ptrace.c - arch_process.c - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/arch/aarch64/arch_coro.c | 0 - src/arch/aarch64/arch_elf.c | 0 - src/arch/aarch64/arch_parse.c | 0 - src/arch/aarch64/arch_patch.c | 0 - src/arch/aarch64/arch_ptrace.c | 0 - src/arch/x86/arch_coro.c | 0 - src/arch/x86/arch_elf.c | 0 - src/arch/x86/arch_parse.c | 0 - src/arch/x86/arch_patch.c | 0 - src/arch/x86/arch_ptrace.c | 0 - 10 files changed, 0 insertions(+), 0 deletions(-) - create mode 100644 src/arch/aarch64/arch_coro.c - create mode 100644 src/arch/aarch64/arch_elf.c - create mode 100644 src/arch/aarch64/arch_parse.c - create mode 100644 src/arch/aarch64/arch_patch.c - create mode 100644 src/arch/aarch64/arch_ptrace.c - create mode 100644 src/arch/x86/arch_coro.c - create mode 100644 src/arch/x86/arch_elf.c - create mode 100644 src/arch/x86/arch_parse.c - create mode 100644 src/arch/x86/arch_patch.c - create mode 100644 src/arch/x86/arch_ptrace.c - -diff --git a/src/arch/aarch64/arch_coro.c b/src/arch/aarch64/arch_coro.c -new file mode 100644 -index 0000000..e69de29 -diff --git a/src/arch/aarch64/arch_elf.c b/src/arch/aarch64/arch_elf.c -new file mode 100644 -index 0000000..e69de29 -diff --git a/src/arch/aarch64/arch_parse.c b/src/arch/aarch64/arch_parse.c -new file mode 100644 -index 0000000..e69de29 -diff --git a/src/arch/aarch64/arch_patch.c b/src/arch/aarch64/arch_patch.c -new file mode 100644 -index 0000000..e69de29 -diff --git a/src/arch/aarch64/arch_ptrace.c b/src/arch/aarch64/arch_ptrace.c -new file mode 100644 -index 0000000..e69de29 -diff --git a/src/arch/x86/arch_coro.c b/src/arch/x86/arch_coro.c -new file mode 100644 -index 0000000..e69de29 -diff --git a/src/arch/x86/arch_elf.c b/src/arch/x86/arch_elf.c -new file mode 100644 -index 0000000..e69de29 -diff --git a/src/arch/x86/arch_parse.c b/src/arch/x86/arch_parse.c -new file mode 100644 -index 0000000..e69de29 -diff --git a/src/arch/x86/arch_patch.c b/src/arch/x86/arch_patch.c -new file mode 100644 -index 0000000..e69de29 -diff --git a/src/arch/x86/arch_ptrace.c b/src/arch/x86/arch_ptrace.c -new file mode 100644 -index 0000000..e69de29 --- -2.23.0 - diff --git a/0023-config-configure-out-the-running-arch.patch b/0023-config-configure-out-the-running-arch.patch deleted file mode 100644 index 6e2941e538ca8352413595a4f046d9f69b62c5eb..0000000000000000000000000000000000000000 --- a/0023-config-configure-out-the-running-arch.patch +++ /dev/null @@ -1,26 +0,0 @@ -From d9b5d88e94b8be0100b0fc2ee0054c78fb0737be Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Tue, 13 Oct 2020 09:36:24 +0800 -Subject: [PATCH 23/89] config: configure out the running arch - -To support multi-arch, we need to figure out which architecture we stands on. -So let's get arch type before running the compilation process. - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/config | 2 ++ - 1 file changed, 2 insertions(+) - create mode 100755 src/config - -diff --git a/src/config b/src/config -new file mode 100755 -index 0000000..6c44cf2 ---- /dev/null -+++ b/src/config -@@ -0,0 +1,2 @@ -+#!/bin/bash -+uname -m > arch.desc --- -2.23.0 - diff --git a/0024-Makefile-Adapt-Makefile-for-different-architectures.patch b/0024-Makefile-Adapt-Makefile-for-different-architectures.patch deleted file mode 100644 index 73cf5ad0fb5eaaa4b937aac1984ea1f872c2e4a6..0000000000000000000000000000000000000000 --- a/0024-Makefile-Adapt-Makefile-for-different-architectures.patch +++ /dev/null @@ -1,72 +0,0 @@ -From d12c8e57c24649e6c8c74e6dc72f02f54e82aea7 Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Tue, 13 Oct 2020 14:55:53 +0800 -Subject: [PATCH 24/89] Makefile: Adapt Makefile for different architectures - -First take the arch information from config file. Then compile the -right file accroding to the architecture and find right header file -postion from src/include. - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/Makefile | 21 +++++++++++++++------ - 1 file changed, 15 insertions(+), 6 deletions(-) - -diff --git a/src/Makefile b/src/Makefile -index 58e942a..9108a02 100644 ---- a/src/Makefile -+++ b/src/Makefile -@@ -7,8 +7,10 @@ TARGETS = kpatch_gensrc \ - libcare-stresstest - DEBUG = yes # comment out this line if not debug - -+SRC_PATH := $(shell pwd) -+ - CC = gcc --CFLAGS_MISC = -Wall -g -O2 -D_GNU_SOURCE -+CFLAGS_MISC = -Wall -g -O2 -D_GNU_SOURCE -I $(SRC_PATH) - - cc-option = $(shell if $(CC) $(CFLAGS_MISC) $(1) -S -o /dev/null -xc /dev/null \ - > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;) -@@ -18,6 +20,13 @@ CFLAGS_WARN += $(call cc-option,-Wno-builtin-macro-redefined) - CFLAGS_WARN += $(call cc-option,-Wno-deprecated-declarations) - CFLAGS = $(CFLAGS_MISC) $(CFLAGS_WARN) - -+ARCH := $(shell cat arch.desc) -+ifeq ($(ARCH),aarch64) -+VPATH = arch/aarch64 -+else -+VPATH = arch/x86 -+endif -+ - ifdef DEBUG - CFLAGS += -DDEBUG -O0 -g - endif -@@ -30,18 +39,18 @@ all: $(TARGETS) - - .SUFFIXES: - --kpatch_gensrc: kpatch_gensrc.o kpatch_dbgfilter.o kpatch_parse.o kpatch_io.o rbtree.o kpatch_log.o -+kpatch_gensrc: kpatch_gensrc.o kpatch_dbgfilter.o kpatch_parse.o kpatch_io.o rbtree.o kpatch_log.o arch_parse.o - kpatch_make: kpatch_make.o - - LIBUNWIND_LIBS := $(shell pkg-config --libs libunwind libunwind-ptrace) - - --libcare-ctl: kpatch_user.o kpatch_storage.o kpatch_patch.c kpatch_elf.o kpatch_ptrace.o kpatch_coro.o --libcare-ctl: kpatch_process.o kpatch_common.o rbtree.o kpatch_log.o -+libcare-ctl: kpatch_user.o kpatch_storage.o kpatch_patch.o kpatch_elf.o kpatch_ptrace.o kpatch_coro.o arch_patch.o arch_elf.o arch_ptrace.o arch_coro.o -+libcare-ctl: kpatch_process.o kpatch_common.o rbtree.o kpatch_log.o arch_process.o - libcare-ctl: LDLIBS += -lelf -lrt $(LIBUNWIND_LIBS) - --libcare-stresstest: kpatch_user-stresstest.o kpatch_storage.o kpatch_patch.c kpatch_elf.o kpatch_ptrace.o kpatch_coro.o --libcare-stresstest: kpatch_process.o kpatch_common.o rbtree.o kpatch_log.o -+libcare-stresstest: kpatch_user-stresstest.o kpatch_storage.o kpatch_patch.o kpatch_elf.o kpatch_ptrace.o kpatch_coro.o arch_patch.o arch_elf.o arch_ptrace.o arch_coro.o -+libcare-stresstest: kpatch_process.o kpatch_common.o rbtree.o kpatch_log.o arch_process.o - libcare-stresstest: LDLIBS += -lelf -lrt $(LIBUNWIND_LIBS) - - libcare-client: libcare-client.o --- -2.23.0 - diff --git a/0025-kpatch_parse-Update-asm_directives-for-aarch64.patch b/0025-kpatch_parse-Update-asm_directives-for-aarch64.patch deleted file mode 100644 index 3f411bc6b40b5569541e34b512665572670c75a7..0000000000000000000000000000000000000000 --- a/0025-kpatch_parse-Update-asm_directives-for-aarch64.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 48a7b69f85710e1db33db994e79fdcd568ceacda Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Mon, 12 Oct 2020 10:53:28 +0800 -Subject: [PATCH 25/89] kpatch_parse: Update asm_directives for aarch64 - -Update asm_directives in kpatch_parse.c, because -the golbal identifier in x86 is ".globl" -which is different from the ".global"in aarch64. - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/kpatch_parse.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/src/kpatch_parse.c b/src/kpatch_parse.c -index dfb3109..44e8a60 100644 ---- a/src/kpatch_parse.c -+++ b/src/kpatch_parse.c -@@ -82,6 +82,8 @@ static struct { - { DIRECTIVE_SUBSECTION, ".subsection"}, - - { DIRECTIVE_GLOBL, ".globl"}, -+ { DIRECTIVE_GLOBL, ".global"}, -+ - { DIRECTIVE_LOCAL, ".local"}, - { DIRECTIVE_HIDDEN, ".hidden"}, - { DIRECTIVE_PROTECTED, ".protected"}, --- -2.23.0 - diff --git a/0026-kpatch_parse-Split-function-parse_ctype.patch b/0026-kpatch_parse-Split-function-parse_ctype.patch deleted file mode 100644 index 8f6f3772b5a139156beb0a41fca6d8d04f03105d..0000000000000000000000000000000000000000 --- a/0026-kpatch_parse-Split-function-parse_ctype.patch +++ /dev/null @@ -1,154 +0,0 @@ -From 13dafd93cf011d79f1f4baf2c9035faeb52f4945 Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Mon, 12 Oct 2020 13:31:41 +0800 -Subject: [PATCH 26/89] kpatch_parse: Split function parse_ctype - -The parse_ctype function is arch related, so let's make two -separate definations in arch/x86/arch_parse.c and arch/aarch64/arch_parse.c - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/arch/aarch64/arch_parse.c | 34 ++++++++++++++++++++++++++++++++++ - src/arch/x86/arch_parse.c | 31 +++++++++++++++++++++++++++++++ - src/include/kpatch_parse.h | 2 ++ - src/kpatch_parse.c | 28 +--------------------------- - 4 files changed, 68 insertions(+), 27 deletions(-) - -diff --git a/src/arch/aarch64/arch_parse.c b/src/arch/aarch64/arch_parse.c -index e69de29..8eb88a9 100644 ---- a/src/arch/aarch64/arch_parse.c -+++ b/src/arch/aarch64/arch_parse.c -@@ -0,0 +1,34 @@ -+#include -+ -+#include "include/kpatch_log.h" -+#include "include/kpatch_parse.h" -+#include "include/kpatch_flags.h" -+ -+int parse_ctype(char *origs, bool with_checks) -+{ -+ char *s = origs; -+ int type; -+ kpstr_t t; -+ -+ s = skip_blanks(s); -+ if (s[0] == '#') -+ return DIRECTIVE_COMMENT; /* Single-line comment */ -+ -+ if (s[0] == '/' && s[1] == '/') -+ return DIRECTIVE_COMMENT; /* Arm disassembly support c style comment */ -+ -+ get_token(&s, &t); -+ type = find_ctype(&t); -+ -+ if (type >= 0) -+ return type; -+ -+ /* -+ * Asm labels starting from digits are local labels, they can be even created multiple times in the same function. -+ * So there is no reason to handle them and bother with renaming at all. It would create conflicts at our brains -+ * and require special tracking and matching... Brrrr.... */ -+ if (s && *s == ':') -+ return !isdigit(t.s[0]) ? DIRECTIVE_LABEL : DIRECTIVE_LOCAL_LABEL; -+ -+ return DIRECTIVE_OTHER; -+} -diff --git a/src/arch/x86/arch_parse.c b/src/arch/x86/arch_parse.c -index e69de29..5a67116 100644 ---- a/src/arch/x86/arch_parse.c -+++ b/src/arch/x86/arch_parse.c -@@ -0,0 +1,31 @@ -+#include -+ -+#include "include/kpatch_log.h" -+#include "include/kpatch_parse.h" -+#include "include/kpatch_flags.h" -+ -+int parse_ctype(char *origs, bool with_checks) -+{ -+ char *s = origs; -+ int type; -+ kpstr_t t; -+ -+ s = skip_blanks(s); -+ if (s[0] == '#') -+ return DIRECTIVE_COMMENT; /* Single-line comment */ -+ -+ get_token(&s, &t); -+ type = find_ctype(&t); -+ -+ if (type >= 0) -+ return type; -+ -+ /* -+ * Asm labels starting from digits are local labels, they can be even created multiple times in the same function. -+ * So there is no reason to handle them and bother with renaming at all. It would create conflicts at our brains -+ * and require special tracking and matching... Brrrr.... */ -+ if (s && *s == ':') -+ return !isdigit(t.s[0]) ? DIRECTIVE_LABEL : DIRECTIVE_LOCAL_LABEL; -+ -+ return DIRECTIVE_OTHER; -+} -diff --git a/src/include/kpatch_parse.h b/src/include/kpatch_parse.h -index 1012d5d..e1b7501 100644 ---- a/src/include/kpatch_parse.h -+++ b/src/include/kpatch_parse.h -@@ -51,6 +51,8 @@ void init_ctypes(struct kp_file *f); - int ctype(struct kp_file *f, int l); - int is_sect_cmd(struct kp_file *f, int l); - -+ -+int find_ctype(kpstr_t *t); - int parse_ctype(char *s, bool with_checks); - - /* ----------------------------------------- sections ----------------------------------------- */ -diff --git a/src/kpatch_parse.c b/src/kpatch_parse.c -index 44e8a60..4bafdb7 100644 ---- a/src/kpatch_parse.c -+++ b/src/kpatch_parse.c -@@ -109,7 +109,7 @@ static void get_type_args(char *s, kpstr_t *nm, kpstr_t *attr) - kpfatal("can't parse .type command"); - } - --static int find_ctype(kpstr_t *t) -+int find_ctype(kpstr_t *t) - { - int i; - for (i = 0; i < (int)(sizeof(asm_directives)/sizeof(asm_directives[0])); i++) { -@@ -119,32 +119,6 @@ static int find_ctype(kpstr_t *t) - return -1; - } - --int parse_ctype(char *origs, bool with_checks) --{ -- char *s = origs; -- int type; -- kpstr_t t; -- -- s = skip_blanks(s); -- if (s[0] == '#') -- return DIRECTIVE_COMMENT; /* Single-line comment */ -- -- get_token(&s, &t); -- type = find_ctype(&t); -- -- if (type >= 0) -- return type; -- -- /* -- * Asm labels starting from digits are local labels, they can be even created multiple times in the same function. -- * So there is no reason to handle them and bother with renaming at all. It would create conflicts at our brains -- * and require special tracking and matching... Brrrr.... */ -- if (s && *s == ':') -- return !isdigit(t.s[0]) ? DIRECTIVE_LABEL : DIRECTIVE_LOCAL_LABEL; -- -- return DIRECTIVE_OTHER; --} -- - int ctype(struct kp_file *f, int l) - { - if (l >= f->nr_lines) --- -2.23.0 - diff --git a/0027-kpatch_parse-Split-function-init_multilines.patch b/0027-kpatch_parse-Split-function-init_multilines.patch deleted file mode 100644 index e4d98b349b8f7e1aee8bcdc7dff3018cc88e6acd..0000000000000000000000000000000000000000 --- a/0027-kpatch_parse-Split-function-init_multilines.patch +++ /dev/null @@ -1,249 +0,0 @@ -From 0e0e7195fca05f706c1701484710fea9fc8b21f5 Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Mon, 12 Oct 2020 13:41:06 +0800 -Subject: [PATCH 27/89] kpatch_parse: Split function init_multilines - -The function init_multilines is arch related, so let's make -two definations in arch/x86/arch_parse.c and arch/aarch64/arch_parse.c - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/arch/aarch64/arch_parse.c | 67 +++++++++++++++++++++++++++++++++++ - src/arch/x86/arch_parse.c | 65 +++++++++++++++++++++++++++++++++ - src/kpatch_parse.c | 65 --------------------------------- - 3 files changed, 132 insertions(+), 65 deletions(-) - -diff --git a/src/arch/aarch64/arch_parse.c b/src/arch/aarch64/arch_parse.c -index 8eb88a9..1233e03 100644 ---- a/src/arch/aarch64/arch_parse.c -+++ b/src/arch/aarch64/arch_parse.c -@@ -4,6 +4,73 @@ - #include "include/kpatch_parse.h" - #include "include/kpatch_flags.h" - -+/* break manually crafted multiple statements separated by ; to separate lines */ -+void init_multilines(struct kp_file *f) -+{ -+ int i, nr, sz = 64, slen, first_token; -+ char **lines = NULL, *s, *se; -+ int *lines_num = NULL; -+ kpstr_t t; -+ -+ nr = 0; -+ for (i = 0; i < f->nr_lines; i++) { -+ if (nr + 1000 >= sz || !lines) { -+ sz *= 2; -+ lines = kp_realloc(lines, (sz/2) * sizeof(char *), sz * sizeof(char *)); -+ lines_num = kp_realloc(lines_num, (sz/2) * sizeof(int), sz * sizeof(int)); -+ } -+ -+ s = f->lines[i]; -+ if (strpbrk(s, ";:") != NULL) { -+ while (s && *s) { -+ se = s; -+ slen = strlen(s); -+ first_token = 1; -+ while (se) { -+ get_token(&se, &t); -+ if (t.l == 1 && t.s[0] == '#') -+ goto done; -+ if (t.l == 2 && t.s[0] == '/' && t.s[1] == '/') -+ goto done; -+ if (t.l == 1 && t.s[0] == ';') { -+ slen = t.s - s; -+ break; -+ } -+ /* first token with ':' after is -+ * the label, separate it unless -+ * it is done already (next non-blank -+ * is '\0') -+ */ -+ if (first_token && se && -+ se[0] == ':' && -+ se[1] != '\0') { -+ slen = se - s + 1; -+ se++; -+ break; -+ } -+ first_token = 0; -+ } -+ lines[nr] = strndup(s, slen); -+ s = se; -+ lines_num[nr] = i; -+ nr++; -+ if (nr >= sz) -+ kpfatal("oops, not prepared to handle >1000 asm statements in single line"); -+ } -+ free(f->lines[i]); -+ } else { -+done: -+ lines[nr] = s; -+ lines_num[nr] = i; -+ nr++; -+ } -+ } -+ free(f->lines); -+ f->lines = lines; -+ f->lines_num = lines_num; -+ f->nr_lines = nr; -+} -+ - int parse_ctype(char *origs, bool with_checks) - { - char *s = origs; -diff --git a/src/arch/x86/arch_parse.c b/src/arch/x86/arch_parse.c -index 5a67116..92ff483 100644 ---- a/src/arch/x86/arch_parse.c -+++ b/src/arch/x86/arch_parse.c -@@ -4,6 +4,71 @@ - #include "include/kpatch_parse.h" - #include "include/kpatch_flags.h" - -+/* break manually crafted multiple statements separated by ; to separate lines */ -+void init_multilines(struct kp_file *f) -+{ -+ int i, nr, sz = 64, slen, first_token; -+ char **lines = NULL, *s, *se; -+ int *lines_num = NULL; -+ kpstr_t t; -+ -+ nr = 0; -+ for (i = 0; i < f->nr_lines; i++) { -+ if (nr + 1000 >= sz || !lines) { -+ sz *= 2; -+ lines = kp_realloc(lines, (sz/2) * sizeof(char *), sz * sizeof(char *)); -+ lines_num = kp_realloc(lines_num, (sz/2) * sizeof(int), sz * sizeof(int)); -+ } -+ -+ s = f->lines[i]; -+ if (strpbrk(s, ";:") != NULL) { -+ while (s && *s) { -+ se = s; -+ slen = strlen(s); -+ first_token = 1; -+ while (se) { -+ get_token(&se, &t); -+ if (t.l == 1 && t.s[0] == '#') -+ goto done; -+ if (t.l == 1 && t.s[0] == ';') { -+ slen = t.s - s; -+ break; -+ } -+ /* first token with ':' after is -+ * the label, separate it unless -+ * it is done already (next non-blank -+ * is '\0') -+ */ -+ if (first_token && se && -+ se[0] == ':' && -+ se[1] != '\0') { -+ slen = se - s + 1; -+ se++; -+ break; -+ } -+ first_token = 0; -+ } -+ lines[nr] = strndup(s, slen); -+ s = se; -+ lines_num[nr] = i; -+ nr++; -+ if (nr >= sz) -+ kpfatal("oops, not prepared to handle >1000 asm statements in single line"); -+ } -+ free(f->lines[i]); -+ } else { -+done: -+ lines[nr] = s; -+ lines_num[nr] = i; -+ nr++; -+ } -+ } -+ free(f->lines); -+ f->lines = lines; -+ f->lines_num = lines_num; -+ f->nr_lines = nr; -+} -+ - int parse_ctype(char *origs, bool with_checks) - { - char *s = origs; -diff --git a/src/kpatch_parse.c b/src/kpatch_parse.c -index 4bafdb7..857dbf3 100644 ---- a/src/kpatch_parse.c -+++ b/src/kpatch_parse.c -@@ -136,71 +136,6 @@ int is_sect_cmd(struct kp_file *f, int l) - t == DIRECTIVE_PREVIOUS || t == DIRECTIVE_SUBSECTION; - } - --/* break manually crafted multiple statements separated by ; to separate lines */ --void init_multilines(struct kp_file *f) --{ -- int i, nr, sz = 64, slen, first_token; -- char **lines = NULL, *s, *se; -- int *lines_num = NULL; -- kpstr_t t; -- -- nr = 0; -- for (i = 0; i < f->nr_lines; i++) { -- if (nr + 1000 >= sz || !lines) { -- sz *= 2; -- lines = kp_realloc(lines, (sz/2) * sizeof(char *), sz * sizeof(char *)); -- lines_num = kp_realloc(lines_num, (sz/2) * sizeof(int), sz * sizeof(int)); -- } -- -- s = f->lines[i]; -- if (strpbrk(s, ";:") != NULL) { -- while (s && *s) { -- se = s; -- slen = strlen(s); -- first_token = 1; -- while (se) { -- get_token(&se, &t); -- if (t.l == 1 && t.s[0] == '#') -- goto done; -- if (t.l == 1 && t.s[0] == ';') { -- slen = t.s - s; -- break; -- } -- /* first token with ':' after is -- * the label, separate it unless -- * it is done already (next non-blank -- * is '\0') -- */ -- if (first_token && se && -- se[0] == ':' && -- se[1] != '\0') { -- slen = se - s + 1; -- se++; -- break; -- } -- first_token = 0; -- } -- lines[nr] = strndup(s, slen); -- s = se; -- lines_num[nr] = i; -- nr++; -- if (nr >= sz) -- kpfatal("oops, not prepared to handle >1000 asm statements in single line"); -- } -- free(f->lines[i]); -- } else { --done: -- lines[nr] = s; -- lines_num[nr] = i; -- nr++; -- } -- } -- free(f->lines); -- f->lines = lines; -- f->lines_num = lines_num; -- f->nr_lines = nr; --} -- - void init_ctypes(struct kp_file *f) - { - int i; --- -2.23.0 - diff --git a/0028-kpatch_parse-Split-function-is_variable_start.patch b/0028-kpatch_parse-Split-function-is_variable_start.patch deleted file mode 100644 index 92d549b513b50e936f5f655dc779c1f25c0ce2eb..0000000000000000000000000000000000000000 --- a/0028-kpatch_parse-Split-function-is_variable_start.patch +++ /dev/null @@ -1,282 +0,0 @@ -From a3fce6e82d24afe186a46461b9cf931f2f023f36 Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Mon, 12 Oct 2020 13:48:18 +0800 -Subject: [PATCH 28/89] kpatch_parse: Split function is_variable_start - -The function is_variable_start is arch related, since different arch may -use different assembly directives to describe variables. So let's make -two definations in arch/x86/arch_parse.c and arch/aarch64/arch_parse.c - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/arch/aarch64/arch_parse.c | 69 ++++++++++++++++++++++++++++++++++ - src/arch/x86/arch_parse.c | 69 ++++++++++++++++++++++++++++++++++ - src/include/kpatch_parse.h | 1 + - src/kpatch_parse.c | 71 +---------------------------------- - 4 files changed, 140 insertions(+), 70 deletions(-) - -diff --git a/src/arch/aarch64/arch_parse.c b/src/arch/aarch64/arch_parse.c -index 1233e03..abbc38c 100644 ---- a/src/arch/aarch64/arch_parse.c -+++ b/src/arch/aarch64/arch_parse.c -@@ -4,6 +4,75 @@ - #include "include/kpatch_parse.h" - #include "include/kpatch_flags.h" - -+int is_variable_start(struct kp_file *f, int l, int *e, int *pglobl, kpstr_t *nm) -+{ -+ char *s; -+ int l0 = l, globl = 0; -+ kpstr_t nm2, attr; -+ -+ kpstrset(nm, "", 0); -+ for ( ; cline(f, l); l++) { -+ -+ /* first verify that all the commands we met has the same symbol name... just to be safe! */ -+ s = cline(f, l); -+ if (*s == '\0' && l != l0) -+ continue; -+ switch (ctype(f, l)) { -+ case DIRECTIVE_TYPE: -+ case DIRECTIVE_GLOBL: -+ case DIRECTIVE_LOCAL: -+ get_token(&s, &nm2); -+ case DIRECTIVE_LABEL: -+ get_token(&s, &nm2); -+ if (nm->l && kpstrcmp(nm, &nm2)) /* some other symbol met... stop */ -+ return 0; -+ *nm = nm2; -+ break; -+ } -+ -+ switch (ctype(f, l)) { -+ case DIRECTIVE_TEXT: -+ case DIRECTIVE_DATA: -+ case DIRECTIVE_BSS: -+ case DIRECTIVE_SECTION: -+ case DIRECTIVE_PUSHSECTION: -+ case DIRECTIVE_POPSECTION: -+ case DIRECTIVE_PREVIOUS: -+ case DIRECTIVE_SUBSECTION: -+ break; -+ case DIRECTIVE_TYPE: -+ get_type_args(cline(f, l), &nm2, &attr); -+ if (kpstrcmpz(&attr, "%object") && kpstrcmpz(&attr, "%tls_object")) -+ return 0; -+ break; -+ case DIRECTIVE_GLOBL: -+ globl = 1; -+ break; -+ case DIRECTIVE_ALIGN: -+ break; -+ case DIRECTIVE_COMMENT: -+ case DIRECTIVE_SIZE: -+ /* can't start with .size */ -+ if (l0 == l) -+ return 0; -+ break; -+ case DIRECTIVE_LABEL: -+ if (!is_data_sect(csect(f, l))) -+ return 0; -+ /* fall throught */ -+ case DIRECTIVE_LOCAL: -+ if (e) -+ *e = l + 1; -+ if (pglobl) -+ *pglobl = globl; -+ return 1; -+ default: -+ return 0; -+ } -+ } -+ return 0; -+} -+ - /* break manually crafted multiple statements separated by ; to separate lines */ - void init_multilines(struct kp_file *f) - { -diff --git a/src/arch/x86/arch_parse.c b/src/arch/x86/arch_parse.c -index 92ff483..ca57507 100644 ---- a/src/arch/x86/arch_parse.c -+++ b/src/arch/x86/arch_parse.c -@@ -4,6 +4,75 @@ - #include "include/kpatch_parse.h" - #include "include/kpatch_flags.h" - -+int is_variable_start(struct kp_file *f, int l, int *e, int *pglobl, kpstr_t *nm) -+{ -+ char *s; -+ int l0 = l, globl = 0; -+ kpstr_t nm2, attr; -+ -+ kpstrset(nm, "", 0); -+ for ( ; cline(f, l); l++) { -+ -+ /* first verify that all the commands we met has the same symbol name... just to be safe! */ -+ s = cline(f, l); -+ if (*s == '\0' && l != l0) -+ continue; -+ switch (ctype(f, l)) { -+ case DIRECTIVE_TYPE: -+ case DIRECTIVE_GLOBL: -+ case DIRECTIVE_LOCAL: -+ get_token(&s, &nm2); -+ case DIRECTIVE_LABEL: -+ get_token(&s, &nm2); -+ if (nm->l && kpstrcmp(nm, &nm2)) /* some other symbol met... stop */ -+ return 0; -+ *nm = nm2; -+ break; -+ } -+ -+ switch (ctype(f, l)) { -+ case DIRECTIVE_TEXT: -+ case DIRECTIVE_DATA: -+ case DIRECTIVE_BSS: -+ case DIRECTIVE_SECTION: -+ case DIRECTIVE_PUSHSECTION: -+ case DIRECTIVE_POPSECTION: -+ case DIRECTIVE_PREVIOUS: -+ case DIRECTIVE_SUBSECTION: -+ break; -+ case DIRECTIVE_TYPE: -+ get_type_args(cline(f, l), &nm2, &attr); -+ if (kpstrcmpz(&attr, "@object")) -+ return 0; -+ break; -+ case DIRECTIVE_GLOBL: -+ globl = 1; -+ break; -+ case DIRECTIVE_ALIGN: -+ break; -+ case DIRECTIVE_COMMENT: -+ case DIRECTIVE_SIZE: -+ /* can't start with .size */ -+ if (l0 == l) -+ return 0; -+ break; -+ case DIRECTIVE_LABEL: -+ if (!is_data_sect(csect(f, l))) -+ return 0; -+ /* fall throught */ -+ case DIRECTIVE_LOCAL: -+ if (e) -+ *e = l + 1; -+ if (pglobl) -+ *pglobl = globl; -+ return 1; -+ default: -+ return 0; -+ } -+ } -+ return 0; -+} -+ - /* break manually crafted multiple statements separated by ; to separate lines */ - void init_multilines(struct kp_file *f) - { -diff --git a/src/include/kpatch_parse.h b/src/include/kpatch_parse.h -index e1b7501..0f41509 100644 ---- a/src/include/kpatch_parse.h -+++ b/src/include/kpatch_parse.h -@@ -109,6 +109,7 @@ void __get_token(char **str, kpstr_t *x, const char *delim); - int is_function_start(struct kp_file *f, int l, kpstr_t *nm); - int is_function_end(struct kp_file *f, int l, kpstr_t *nm); - -+void get_type_args(char *s, kpstr_t *nm, kpstr_t *attr); - int is_variable_start(struct kp_file *f, int l, int *e, int *globl, kpstr_t *nm); - int is_data_def(char *s, int type); - -diff --git a/src/kpatch_parse.c b/src/kpatch_parse.c -index 857dbf3..a3be7c0 100644 ---- a/src/kpatch_parse.c -+++ b/src/kpatch_parse.c -@@ -93,7 +93,7 @@ static struct { - }; - - /* parse arguments of .type command */ --static void get_type_args(char *s, kpstr_t *nm, kpstr_t *attr) -+void get_type_args(char *s, kpstr_t *nm, kpstr_t *attr) - { - kpstr_t t, t2; - -@@ -674,75 +674,6 @@ int is_function_end(struct kp_file *f, int l, kpstr_t *nm) - return 1; - } - --int is_variable_start(struct kp_file *f, int l, int *e, int *pglobl, kpstr_t *nm) --{ -- char *s; -- int l0 = l, globl = 0; -- kpstr_t nm2, attr; -- -- kpstrset(nm, "", 0); -- for ( ; cline(f, l); l++) { -- -- /* first verify that all the commands we met has the same symbol name... just to be safe! */ -- s = cline(f, l); -- if (*s == '\0' && l != l0) -- continue; -- switch (ctype(f, l)) { -- case DIRECTIVE_TYPE: -- case DIRECTIVE_GLOBL: -- case DIRECTIVE_LOCAL: -- get_token(&s, &nm2); -- case DIRECTIVE_LABEL: -- get_token(&s, &nm2); -- if (nm->l && kpstrcmp(nm, &nm2)) /* some other symbol met... stop */ -- return 0; -- *nm = nm2; -- break; -- } -- -- switch (ctype(f, l)) { -- case DIRECTIVE_TEXT: -- case DIRECTIVE_DATA: -- case DIRECTIVE_BSS: -- case DIRECTIVE_SECTION: -- case DIRECTIVE_PUSHSECTION: -- case DIRECTIVE_POPSECTION: -- case DIRECTIVE_PREVIOUS: -- case DIRECTIVE_SUBSECTION: -- break; -- case DIRECTIVE_TYPE: -- get_type_args(cline(f, l), &nm2, &attr); -- if (kpstrcmpz(&attr, "@object")) -- return 0; -- break; -- case DIRECTIVE_GLOBL: -- globl = 1; -- break; -- case DIRECTIVE_ALIGN: -- break; -- case DIRECTIVE_COMMENT: -- case DIRECTIVE_SIZE: -- /* can't start with .size */ -- if (l0 == l) -- return 0; -- break; -- case DIRECTIVE_LABEL: -- if (!is_data_sect(csect(f, l))) -- return 0; -- /* fall throught */ -- case DIRECTIVE_LOCAL: -- if (e) -- *e = l + 1; -- if (pglobl) -- *pglobl = globl; -- return 1; -- default: -- return 0; -- } -- } -- return 0; --} -- - int is_data_def(char *s, int type) - { - kpstr_t t; --- -2.23.0 - diff --git a/0029-kpatch_parse-Split-function-is_data_def.patch b/0029-kpatch_parse-Split-function-is_data_def.patch deleted file mode 100644 index cd71280f8c3a9e2cbcabebceb5e1848e52864523..0000000000000000000000000000000000000000 --- a/0029-kpatch_parse-Split-function-is_data_def.patch +++ /dev/null @@ -1,180 +0,0 @@ -From eaff972f8edd58491eeca17f4b7553cceb1fb5d4 Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Mon, 12 Oct 2020 13:53:01 +0800 -Subject: [PATCH 29/89] kpatch_parse: Split function is_data_def - -The function is_data_def is arch related, so let's make two -separate definations in arch/x86/arch_parse.c and arch/aarch64/arch_parse.c - -Signed-off-by: Jiajie Li ---- - src/arch/aarch64/arch_parse.c | 64 +++++++++++++++++++++++++++++++++++ - src/arch/x86/arch_parse.c | 34 +++++++++++++++++++ - src/kpatch_parse.c | 33 ------------------ - 3 files changed, 98 insertions(+), 33 deletions(-) - -diff --git a/src/arch/aarch64/arch_parse.c b/src/arch/aarch64/arch_parse.c -index abbc38c..fea09f6 100644 ---- a/src/arch/aarch64/arch_parse.c -+++ b/src/arch/aarch64/arch_parse.c -@@ -4,6 +4,70 @@ - #include "include/kpatch_parse.h" - #include "include/kpatch_flags.h" - -+int is_data_def(char *s, int type) -+{ -+ kpstr_t t; -+ -+ get_token(&s, &t); -+ if ( -+ /* strings */ -+ !kpstrcmpz(&t, ".ascii") || -+ !kpstrcmpz(&t, ".asciz") || -+ !kpstrcmpz(&t, ".string") || -+ !kpstrcmpz(&t, ".string8") || -+ !kpstrcmpz(&t, ".string16") || -+ !kpstrcmpz(&t, ".string32") || -+ !kpstrcmpz(&t, ".string64") || -+ /* numeric */ -+ !kpstrcmpz(&t, ".byte") || -+ !kpstrcmpz(&t, ".1byte") || -+ !kpstrcmpz(&t, ".dc.b") || -+ -+ !kpstrcmpz(&t, ".hword") || -+ !kpstrcmpz(&t, ".short") || -+ !kpstrcmpz(&t, ".2byte") || -+ !kpstrcmpz(&t, ".dc") || -+ !kpstrcmpz(&t, ".dc.w") || -+ !kpstrcmpz(&t, ".value") || -+ !kpstrcmpz(&t, ".octa") || -+ -+ !kpstrcmpz(&t, ".word") || -+ !kpstrcmpz(&t, ".4byte") || -+ !kpstrcmpz(&t, ".long") || -+ !kpstrcmpz(&t, ".int") || -+ !kpstrcmpz(&t, ".dc.l") || -+ !kpstrcmpz(&t, ".dc.a") ||// (AArch32 only) -+ -+ !kpstrcmpz(&t, ".quad") || -+ !kpstrcmpz(&t, ".8byte") || -+ !kpstrcmpz(&t, ".xword") ||//(AArch64 only) -+ !kpstrcmpz(&t, ".dc.a") ||//(AArch64 only) -+ -+ !kpstrcmpz(&t, ".short") || -+ !kpstrcmpz(&t, ".int") || -+ !kpstrcmpz(&t, ".long") || -+ !kpstrcmpz(&t, ".quad") || -+ /* float */ -+ !kpstrcmpz(&t, ".double") || -+ !kpstrcmpz(&t, ".dc.d") || -+ !kpstrcmpz(&t, ".float") || -+ !kpstrcmpz(&t, ".single") || -+ !kpstrcmpz(&t, ".dc.s") || -+ /* other */ -+ !kpstrcmpz(&t, ".value") || -+ !kpstrcmpz(&t, ".comm") || -+ !kpstrcmpz(&t, ".zero") || -+ !kpstrcmpz(&t, ".fill") || -+ !kpstrcmpz(&t, ".space") || -+ !kpstrcmpz(&t, ".skip") || -+ /* dwarf types */ -+ !kpstrcmpz(&t, ".uleb128") || -+ !kpstrcmpz(&t, ".sleb128") -+ ) -+ return 1; -+ return 0; -+} -+ - int is_variable_start(struct kp_file *f, int l, int *e, int *pglobl, kpstr_t *nm) - { - char *s; -diff --git a/src/arch/x86/arch_parse.c b/src/arch/x86/arch_parse.c -index ca57507..81edaf8 100644 ---- a/src/arch/x86/arch_parse.c -+++ b/src/arch/x86/arch_parse.c -@@ -4,6 +4,40 @@ - #include "include/kpatch_parse.h" - #include "include/kpatch_flags.h" - -+int is_data_def(char *s, int type) -+{ -+ kpstr_t t; -+ -+ get_token(&s, &t); -+ if ( -+ /* strings */ -+ !kpstrcmpz(&t, ".ascii") || -+ !kpstrcmpz(&t, ".asciz") || -+ !kpstrcmpz(&t, ".string") || -+ /* numeric */ -+ !kpstrcmpz(&t, ".byte") || -+ !kpstrcmpz(&t, ".word") || -+ !kpstrcmpz(&t, ".short") || -+ !kpstrcmpz(&t, ".int") || -+ !kpstrcmpz(&t, ".long") || -+ !kpstrcmpz(&t, ".quad") || -+ /* float */ -+ !kpstrcmpz(&t, ".double") || -+ !kpstrcmpz(&t, ".float") || -+ !kpstrcmpz(&t, ".single") || -+ /* other */ -+ !kpstrcmpz(&t, ".value") || -+ !kpstrcmpz(&t, ".comm") || -+ !kpstrcmpz(&t, ".zero") || -+ /* dwarf types */ -+ !kpstrcmpz(&t, ".uleb128") || -+ !kpstrcmpz(&t, ".sleb128") || -+ !kpstrcmpz(&t, ".4byte") -+ ) -+ return 1; -+ return 0; -+} -+ - int is_variable_start(struct kp_file *f, int l, int *e, int *pglobl, kpstr_t *nm) - { - char *s; -diff --git a/src/kpatch_parse.c b/src/kpatch_parse.c -index a3be7c0..f486b55 100644 ---- a/src/kpatch_parse.c -+++ b/src/kpatch_parse.c -@@ -674,37 +674,4 @@ int is_function_end(struct kp_file *f, int l, kpstr_t *nm) - return 1; - } - --int is_data_def(char *s, int type) --{ -- kpstr_t t; -- -- get_token(&s, &t); -- if ( -- /* strings */ -- !kpstrcmpz(&t, ".ascii") || -- !kpstrcmpz(&t, ".asciz") || -- !kpstrcmpz(&t, ".string") || -- /* numeric */ -- !kpstrcmpz(&t, ".byte") || -- !kpstrcmpz(&t, ".word") || -- !kpstrcmpz(&t, ".short") || -- !kpstrcmpz(&t, ".int") || -- !kpstrcmpz(&t, ".long") || -- !kpstrcmpz(&t, ".quad") || -- /* float */ -- !kpstrcmpz(&t, ".double") || -- !kpstrcmpz(&t, ".float") || -- !kpstrcmpz(&t, ".single") || -- /* other */ -- !kpstrcmpz(&t, ".value") || -- !kpstrcmpz(&t, ".comm") || -- !kpstrcmpz(&t, ".zero") || -- /* dwarf types */ -- !kpstrcmpz(&t, ".uleb128") || -- !kpstrcmpz(&t, ".sleb128") || -- !kpstrcmpz(&t, ".4byte") -- ) -- return 1; -- return 0; --} - --- -2.23.0 - diff --git a/0030-kpatch_parse-Split-function-is_function_start.patch b/0030-kpatch_parse-Split-function-is_function_start.patch deleted file mode 100644 index 94fd088f01ca8c0813ea4c0e2a46753238696fb4..0000000000000000000000000000000000000000 --- a/0030-kpatch_parse-Split-function-is_function_start.patch +++ /dev/null @@ -1,149 +0,0 @@ -From 3ecebe9ea858d5502af5f5cd79141e4546ae3fe8 Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Mon, 12 Oct 2020 13:58:58 +0800 -Subject: [PATCH 30/89] kpatch_parse: Split function is_function_start - -The function is_function_start is arch related, so make two -separate definations in arch/x86/arch_parse.c and arch/aarch64/arch_parse.c - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/arch/aarch64/arch_parse.c | 32 ++++++++++++++++++++++++++++++++ - src/arch/x86/arch_parse.c | 32 ++++++++++++++++++++++++++++++++ - src/kpatch_parse.c | 33 --------------------------------- - 3 files changed, 64 insertions(+), 33 deletions(-) - -diff --git a/src/arch/aarch64/arch_parse.c b/src/arch/aarch64/arch_parse.c -index fea09f6..e0f0c8b 100644 ---- a/src/arch/aarch64/arch_parse.c -+++ b/src/arch/aarch64/arch_parse.c -@@ -4,6 +4,38 @@ - #include "include/kpatch_parse.h" - #include "include/kpatch_flags.h" - -+int is_function_start(struct kp_file *f, int l, kpstr_t *nm) -+{ -+ char *s; -+ kpstr_t nm2, attr; -+ int l0 = l, func = 0; -+ -+ kpstrset(nm, "", 0); -+ for (; l < f->nr_lines; l++) { -+ if (l != l0 && cline(f, l)[0] == '\0') -+ continue; -+ if ((is_sect_cmd(f, l) && is_code_sect(csect(f, l))) || -+ ctype(f, l) == DIRECTIVE_ALIGN) -+ continue; -+ get_type_args(cline(f, l), &nm2, &attr); -+ if ((ctype(f, l) == DIRECTIVE_WEAK && l0 != l) || -+ ctype(f, l) == DIRECTIVE_GLOBL || ctype(f, l) == DIRECTIVE_HIDDEN || -+ ctype(f, l) == DIRECTIVE_PROTECTED || ctype(f, l) == DIRECTIVE_INTERNAL || -+ (ctype(f, l) == DIRECTIVE_TYPE && !kpstrcmpz(&attr, "%function"))) { -+ s = cline(f, l); -+ get_token(&s, &nm2); /* skip command */ -+ get_token(&s, &nm2); -+ if (nm->l && kpstrcmp(nm, &nm2)) /* verify name matches in all .weak/.globl/.type commands */ -+ return 0; -+ *nm = nm2; -+ func = func ? 1 : ctype(f, l) == DIRECTIVE_TYPE; -+ continue; -+ } -+ break; -+ } -+ return func; -+} -+ - int is_data_def(char *s, int type) - { - kpstr_t t; -diff --git a/src/arch/x86/arch_parse.c b/src/arch/x86/arch_parse.c -index 81edaf8..c51c49b 100644 ---- a/src/arch/x86/arch_parse.c -+++ b/src/arch/x86/arch_parse.c -@@ -4,6 +4,38 @@ - #include "include/kpatch_parse.h" - #include "include/kpatch_flags.h" - -+int is_function_start(struct kp_file *f, int l, kpstr_t *nm) -+{ -+ char *s; -+ kpstr_t nm2, attr; -+ int l0 = l, func = 0; -+ -+ kpstrset(nm, "", 0); -+ for (; l < f->nr_lines; l++) { -+ if (l != l0 && cline(f, l)[0] == '\0') -+ continue; -+ if ((is_sect_cmd(f, l) && is_code_sect(csect(f, l))) || -+ ctype(f, l) == DIRECTIVE_ALIGN) -+ continue; -+ get_type_args(cline(f, l), &nm2, &attr); -+ if ((ctype(f, l) == DIRECTIVE_WEAK && l0 != l) || -+ ctype(f, l) == DIRECTIVE_GLOBL || ctype(f, l) == DIRECTIVE_HIDDEN || -+ ctype(f, l) == DIRECTIVE_PROTECTED || ctype(f, l) == DIRECTIVE_INTERNAL || -+ (ctype(f, l) == DIRECTIVE_TYPE && !kpstrcmpz(&attr, "@function"))) { -+ s = cline(f, l); -+ get_token(&s, &nm2); /* skip command */ -+ get_token(&s, &nm2); -+ if (nm->l && kpstrcmp(nm, &nm2)) /* verify name matches in all .weak/.globl/.type commands */ -+ return 0; -+ *nm = nm2; -+ func = func ? 1 : ctype(f, l) == DIRECTIVE_TYPE; -+ continue; -+ } -+ break; -+ } -+ return func; -+} -+ - int is_data_def(char *s, int type) - { - kpstr_t t; -diff --git a/src/kpatch_parse.c b/src/kpatch_parse.c -index f486b55..3df658d 100644 ---- a/src/kpatch_parse.c -+++ b/src/kpatch_parse.c -@@ -625,39 +625,6 @@ void init_sections(struct kp_file *f) - } - - /* ----------------------------------------- code block boundaries detection ---------------------------------------- */ -- --int is_function_start(struct kp_file *f, int l, kpstr_t *nm) --{ -- char *s; -- kpstr_t nm2, attr; -- int l0 = l, func = 0; -- -- kpstrset(nm, "", 0); -- for (; l < f->nr_lines; l++) { -- if (l != l0 && cline(f, l)[0] == '\0') -- continue; -- if ((is_sect_cmd(f, l) && is_code_sect(csect(f, l))) || -- ctype(f, l) == DIRECTIVE_ALIGN) -- continue; -- get_type_args(cline(f, l), &nm2, &attr); -- if ((ctype(f, l) == DIRECTIVE_WEAK && l0 != l) || -- ctype(f, l) == DIRECTIVE_GLOBL || ctype(f, l) == DIRECTIVE_HIDDEN || -- ctype(f, l) == DIRECTIVE_PROTECTED || ctype(f, l) == DIRECTIVE_INTERNAL || -- (ctype(f, l) == DIRECTIVE_TYPE && !kpstrcmpz(&attr, "@function"))) { -- s = cline(f, l); -- get_token(&s, &nm2); /* skip command */ -- get_token(&s, &nm2); -- if (nm->l && kpstrcmp(nm, &nm2)) /* verify name matches in all .weak/.globl/.type commands */ -- return 0; -- *nm = nm2; -- func = func ? 1 : ctype(f, l) == DIRECTIVE_TYPE; -- continue; -- } -- break; -- } -- return func; --} -- - int is_function_end(struct kp_file *f, int l, kpstr_t *nm) - { - /* Functions should always end by .size directive. Previously used to detect .LFe labels, but they are not generated w/o frame pointers */ --- -2.23.0 - diff --git a/0031-kpatch_common.h-Factor-out-PAGE_SIZE-marco.patch b/0031-kpatch_common.h-Factor-out-PAGE_SIZE-marco.patch deleted file mode 100644 index 69b760eb579364717d6b28bb079f4bfef7a1f0ca..0000000000000000000000000000000000000000 --- a/0031-kpatch_common.h-Factor-out-PAGE_SIZE-marco.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0430a8354e988a1a72896844d45b1a5c83743d74 Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Mon, 12 Oct 2020 14:02:50 +0800 -Subject: [PATCH 31/89] kpatch_common.h: Factor out PAGE_SIZE marco - -Since page size may be different on OS configuration. Let's make a -change it to get PAGE_SIZE dynamicly accquired from syscall. - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/include/kpatch_common.h | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/src/include/kpatch_common.h b/src/include/kpatch_common.h -index c160250..775ea14 100644 ---- a/src/include/kpatch_common.h -+++ b/src/include/kpatch_common.h -@@ -41,4 +41,21 @@ int kpatch_close_file(struct kp_file *kpatch); - # define R_X86_64_GOTPCRELX 0x29 - #endif - -+static inline int page_shift(int n) { -+ int res = -1; -+ -+ while(n) { -+ res++; -+ n >>= 1; -+ } -+ -+ return res; -+} -+ -+#ifndef PAGE_SIZE -+#define PAGE_SIZE getpagesize() -+#define PAGE_MASK (~(PAGE_SIZE-1)) -+#define PAGE_SHIFT page_shift(PAGE_SIZE) -+#endif -+ - #endif --- -2.23.0 - diff --git a/0032-kpatch_coro-Split-function-_UCORO_access_reg.patch b/0032-kpatch_coro-Split-function-_UCORO_access_reg.patch deleted file mode 100644 index 0004231ca2c26759f6c29cc1e116a1b48be4148d..0000000000000000000000000000000000000000 --- a/0032-kpatch_coro-Split-function-_UCORO_access_reg.patch +++ /dev/null @@ -1,196 +0,0 @@ -From ae9e01aefed4105c808301e783d29ddd349dc0f6 Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Mon, 12 Oct 2020 14:22:45 +0800 -Subject: [PATCH 32/89] kpatch_coro: Split function _UCORO_access_reg - -The function _UCORO_access_reg is arch related, so make two -separate definations in arch/x86/arch_coro.c and arch/aarch64/arch_coro.c - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/arch/aarch64/arch_coro.c | 39 ++++++++++++++++++++++++++++++++ - src/arch/x86/arch_coro.c | 43 ++++++++++++++++++++++++++++++++++++ - src/include/kpatch_coro.h | 11 +++++++++ - src/kpatch_coro.c | 37 ------------------------------- - 4 files changed, 93 insertions(+), 37 deletions(-) - -diff --git a/src/arch/aarch64/arch_coro.c b/src/arch/aarch64/arch_coro.c -index e69de29..e6fe3d0 100644 ---- a/src/arch/aarch64/arch_coro.c -+++ b/src/arch/aarch64/arch_coro.c -@@ -0,0 +1,39 @@ -+#include -+#include -+#include -+#include -+#include -+ -+#include "include/kpatch_user.h" -+#include "include/kpatch_coro.h" -+#include "include/kpatch_common.h" -+#include "include/kpatch_elf.h" -+#include "include/kpatch_ptrace.h" -+#include "include/kpatch_log.h" -+ -+int _UCORO_access_reg(unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, -+ int write, void *arg) -+{ -+ struct UCORO_info *info = (struct UCORO_info *)arg; -+ unsigned long *regs = (unsigned long *)info->coro->env[0].__jmpbuf; -+ -+ if (write) { -+ kperr("_UCORO_access_reg: write is not implemeneted (%d)\n", reg); -+ return -UNW_EINVAL; -+ } -+ switch (reg) { -+ case UNW_AARCH64_X9: -+ *val = regs[JB_RBX]; break; -+ case UNW_AARCH64_X29: -+ *val = regs[JB_RBP]; break; -+ case UNW_AARCH64_X12...UNW_AARCH64_X15: -+ *val = regs[reg - UNW_AARCH64_X12 + JB_R12]; break; -+ case UNW_AARCH64_SP: -+ *val = regs[JB_RSP]; break; -+ case UNW_AARCH64_PC: -+ *val = regs[JB_RIP]; break; -+ default: -+ return _UPT_access_reg(as, reg, val, write, arg); -+ } -+ return 0; -+} -diff --git a/src/arch/x86/arch_coro.c b/src/arch/x86/arch_coro.c -index e69de29..ce889df 100644 ---- a/src/arch/x86/arch_coro.c -+++ b/src/arch/x86/arch_coro.c -@@ -0,0 +1,43 @@ -+#include -+#include -+#include -+ -+#include -+ -+#include -+ -+#include -+ -+#include "include/kpatch_user.h" -+#include "include/kpatch_coro.h" -+#include "include/kpatch_common.h" -+#include "include/kpatch_elf.h" -+#include "include/kpatch_ptrace.h" -+#include "include/kpatch_log.h" -+ -+int _UCORO_access_reg(unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, -+ int write, void *arg) -+{ -+ struct UCORO_info *info = (struct UCORO_info *)arg; -+ unsigned long *regs = (unsigned long *)info->coro->env[0].__jmpbuf; -+ -+ if (write) { -+ kperr("_UCORO_access_reg: write is not implemeneted (%d)\n", reg); -+ return -UNW_EINVAL; -+ } -+ switch (reg) { -+ case UNW_X86_64_RBX: -+ *val = regs[JB_RBX]; break; -+ case UNW_X86_64_RBP: -+ *val = regs[JB_RBP]; break; -+ case UNW_X86_64_R12...UNW_X86_64_R15: -+ *val = regs[reg - UNW_X86_64_R12 + JB_R12]; break; -+ case UNW_X86_64_RSP: -+ *val = regs[JB_RSP]; break; -+ case UNW_X86_64_RIP: -+ *val = regs[JB_RIP]; break; -+ default: -+ return _UPT_access_reg(as, reg, val, write, arg); -+ } -+ return 0; -+} -diff --git a/src/include/kpatch_coro.h b/src/include/kpatch_coro.h -index 1588b5e..760b1db 100644 ---- a/src/include/kpatch_coro.h -+++ b/src/include/kpatch_coro.h -@@ -19,6 +19,17 @@ struct kpatch_coro { - void *_UCORO_create(struct kpatch_coro *coro, pid_t pid); - void _UCORO_destroy(void *arg); - -+ -+struct UCORO_info { -+ union { -+ void *upt; -+ char dummy[256]; -+ }; -+ struct kpatch_coro *coro; -+}; -+int _UCORO_access_reg(unw_addr_space_t as, unw_regnum_t reg, -+ unw_word_t *val, int write, void *arg); -+ - int kpatch_coroutines_init(struct kpatch_process *proc); - int kpatch_coroutines_find(struct kpatch_process *proc); - void kpatch_coroutines_free(struct kpatch_process *proc); -diff --git a/src/kpatch_coro.c b/src/kpatch_coro.c -index 02d421b..83d04ce 100644 ---- a/src/kpatch_coro.c -+++ b/src/kpatch_coro.c -@@ -6,8 +6,6 @@ - - #include - --#include -- - #include "include/kpatch_user.h" - #include "include/kpatch_coro.h" - #include "include/kpatch_common.h" -@@ -505,13 +503,6 @@ static struct kpatch_coro_ops kpatch_coro_flavours[] = { - * - * That's why I had to do this hack - */ --struct UCORO_info { -- union { -- void *upt; -- char dummy[256]; -- }; -- struct kpatch_coro *coro; --}; - - void *_UCORO_create(struct kpatch_coro *coro, pid_t pid) - { -@@ -538,34 +529,6 @@ void _UCORO_destroy(void *arg) - _UPT_destroy(info); - } - --static int --_UCORO_access_reg(unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, -- int write, void *arg) --{ -- struct UCORO_info *info = (struct UCORO_info *)arg; -- unsigned long *regs = (unsigned long *)info->coro->env[0].__jmpbuf; -- -- if (write) { -- kperr("_UCORO_access_reg: write is not implemeneted (%d)\n", reg); -- return -UNW_EINVAL; -- } -- switch (reg) { -- case UNW_X86_64_RBX: -- *val = regs[JB_RBX]; break; -- case UNW_X86_64_RBP: -- *val = regs[JB_RBP]; break; -- case UNW_X86_64_R12...UNW_X86_64_R15: -- *val = regs[reg - UNW_X86_64_R12 + JB_R12]; break; -- case UNW_X86_64_RSP: -- *val = regs[JB_RSP]; break; -- case UNW_X86_64_RIP: -- *val = regs[JB_RIP]; break; -- default: -- return _UPT_access_reg(as, reg, val, write, arg); -- } -- return 0; --} -- - static unw_accessors_t _UCORO_accessors = { - _UPT_find_proc_info, - _UPT_put_unwind_info, --- -2.23.0 - diff --git a/0033-kpatch_coro-Split-function-get_ptr_guard.patch b/0033-kpatch_coro-Split-function-get_ptr_guard.patch deleted file mode 100644 index cdb224481a3233c3041b7d8e9eaa9b2b5acb0cba..0000000000000000000000000000000000000000 --- a/0033-kpatch_coro-Split-function-get_ptr_guard.patch +++ /dev/null @@ -1,148 +0,0 @@ -From 612e06f2fc95029c13cfdb684014259fb49f18fe Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Mon, 12 Oct 2020 14:32:51 +0800 -Subject: [PATCH 33/89] kpatch_coro: Split function get_ptr_guard - -The function get_ptr_guard is arch related, so make two -separate definations in arch/x86/arch_coro.c and arch/aarch64/arch_coro.c - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/arch/aarch64/arch_coro.c | 24 ++++++++++++++++++++++++ - src/arch/x86/arch_coro.c | 23 +++++++++++++++++++++++ - src/include/kpatch_coro.h | 5 +++++ - src/kpatch_coro.c | 25 ------------------------- - 4 files changed, 52 insertions(+), 25 deletions(-) - -diff --git a/src/arch/aarch64/arch_coro.c b/src/arch/aarch64/arch_coro.c -index e6fe3d0..b93581e 100644 ---- a/src/arch/aarch64/arch_coro.c -+++ b/src/arch/aarch64/arch_coro.c -@@ -11,6 +11,30 @@ - #include "include/kpatch_ptrace.h" - #include "include/kpatch_log.h" - -+int get_ptr_guard(struct kpatch_process *proc, -+ unsigned long *ptr_guard) -+{ -+ int ret; -+ unsigned long tls = 0; -+ -+ /* -+ ret = kpatch_arch_prctl_remote(proc2pctx(proc), ARCH_GET_FS, &tls); -+ if (ret < 0) { -+ kpdebug("FAIL. Can't get TLS base value\n"); -+ return -1; -+ }*/ -+ ret = kpatch_process_mem_read(proc, -+ tls + GLIBC_TLS_PTR_GUARD, -+ ptr_guard, -+ sizeof(*ptr_guard)); -+ if (ret < 0) { -+ kpdebug("FAIL. Can't get pointer guard value\n"); -+ return -1; -+ } -+ -+ return 0; -+} -+ - int _UCORO_access_reg(unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, - int write, void *arg) - { -diff --git a/src/arch/x86/arch_coro.c b/src/arch/x86/arch_coro.c -index ce889df..86bf12f 100644 ---- a/src/arch/x86/arch_coro.c -+++ b/src/arch/x86/arch_coro.c -@@ -15,6 +15,29 @@ - #include "include/kpatch_ptrace.h" - #include "include/kpatch_log.h" - -+int get_ptr_guard(struct kpatch_process *proc, -+ unsigned long *ptr_guard) -+{ -+ int ret; -+ unsigned long tls; -+ -+ ret = kpatch_arch_prctl_remote(proc2pctx(proc), ARCH_GET_FS, &tls); -+ if (ret < 0) { -+ kpdebug("FAIL. Can't get TLS base value\n"); -+ return -1; -+ } -+ ret = kpatch_process_mem_read(proc, -+ tls + GLIBC_TLS_PTR_GUARD, -+ ptr_guard, -+ sizeof(*ptr_guard)); -+ if (ret < 0) { -+ kpdebug("FAIL. Can't get pointer guard value\n"); -+ return -1; -+ } -+ -+ return 0; -+} -+ - int _UCORO_access_reg(unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, - int write, void *arg) - { -diff --git a/src/include/kpatch_coro.h b/src/include/kpatch_coro.h -index 760b1db..272855e 100644 ---- a/src/include/kpatch_coro.h -+++ b/src/include/kpatch_coro.h -@@ -30,6 +30,11 @@ struct UCORO_info { - int _UCORO_access_reg(unw_addr_space_t as, unw_regnum_t reg, - unw_word_t *val, int write, void *arg); - -+#define GLIBC_TLS_PTR_GUARD 0x30 -+int get_ptr_guard(struct kpatch_process *proc, -+ unsigned long *ptr_guard); -+ -+ - int kpatch_coroutines_init(struct kpatch_process *proc); - int kpatch_coroutines_find(struct kpatch_process *proc); - void kpatch_coroutines_free(struct kpatch_process *proc); -diff --git a/src/kpatch_coro.c b/src/kpatch_coro.c -index 83d04ce..ea4050f 100644 ---- a/src/kpatch_coro.c -+++ b/src/kpatch_coro.c -@@ -105,8 +105,6 @@ kpatch_coro_free(struct kpatch_coro *c) - #define JB_RSP 6 - #define JB_RIP 7 - --#define GLIBC_TLS_PTR_GUARD 0x30 -- - #define STACK_OFFSET_UC_LINK (2 * sizeof(long)) - #define STACK_OFFSET_START_CONTEXT (3 * sizeof(long)) - #define STACK_OFFSET_UC_LINK_PTR (4 * sizeof(long)) -@@ -191,29 +189,6 @@ static int is_test_target(struct kpatch_process *proc, - return strcmp(proc->comm, procname) == 0; - } - --static int get_ptr_guard(struct kpatch_process *proc, -- unsigned long *ptr_guard) --{ -- int ret; -- unsigned long tls; -- -- ret = kpatch_arch_prctl_remote(proc2pctx(proc), ARCH_GET_FS, &tls); -- if (ret < 0) { -- kpdebug("FAIL. Can't get TLS base value\n"); -- return -1; -- } -- ret = kpatch_process_mem_read(proc, -- tls + GLIBC_TLS_PTR_GUARD, -- ptr_guard, -- sizeof(*ptr_guard)); -- if (ret < 0) { -- kpdebug("FAIL. Can't get pointer guard value\n"); -- return -1; -- } -- -- return 0; --} -- - int is_centos7_qemu(struct kpatch_process *proc) - { - struct utsname uts; --- -2.23.0 - diff --git a/0034-kpatch_coro-Split-function-locate_start_context_symb.patch b/0034-kpatch_coro-Split-function-locate_start_context_symb.patch deleted file mode 100644 index feea29aa6783234d5f15d1098bf5c7a185e38d62..0000000000000000000000000000000000000000 --- a/0034-kpatch_coro-Split-function-locate_start_context_symb.patch +++ /dev/null @@ -1,307 +0,0 @@ -From 9ac8822b66bb06a463a29ec86088cfe8adc1e6d4 Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Mon, 12 Oct 2020 14:45:03 +0800 -Subject: [PATCH 34/89] kpatch_coro: Split function locate_start_context_symbol - -The function locate_start_context_symbol is arch related, so let's -make two separate definations in arch/x86/arch_coro.c and -arch/aarch64/arch_coro.c - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/arch/aarch64/arch_coro.c | 63 ++++++++++++++++++++++++++ - src/arch/x86/arch_coro.c | 67 +++++++++++++++++++++++++++ - src/include/kpatch_coro.h | 21 +++++++++ - src/kpatch_coro.c | 87 ------------------------------------ - 4 files changed, 151 insertions(+), 87 deletions(-) - -diff --git a/src/arch/aarch64/arch_coro.c b/src/arch/aarch64/arch_coro.c -index b93581e..f485cf9 100644 ---- a/src/arch/aarch64/arch_coro.c -+++ b/src/arch/aarch64/arch_coro.c -@@ -11,6 +11,69 @@ - #include "include/kpatch_ptrace.h" - #include "include/kpatch_log.h" - -+asm ( -+ "makecontext_call:\n" -+ "mov x29, sp\n" -+ "and x29,x29,#-16\n" -+ "sub x29, x29,#0x400\n" -+ "ldr x9,[x29,#-128]\n" -+ "str x9,[fp,#0x10]\n" -+ //"str #128,[fp.#0x20]\n" -+ "mov x0,fp\n" -+ "mov x1,#0x100\n" -+ "mov x2,#0\n" -+ "svc #0\n" -+ "brk #0\n" -+ "makecontext_call_end:" -+ ); -+ -+extern unsigned char makecontext_call, makecontext_call_end; -+ -+int -+locate_start_context_symbol(struct kpatch_process *proc, -+ unsigned long *pstart_context) -+{ -+ struct object_file *olibc; -+ struct user_regs_struct regs; -+ int rv; -+ unsigned long makecontext; -+ -+ olibc = kpatch_process_get_obj_by_regex(proc, "^libc-.*\\.so"); -+ if (olibc == NULL) { -+ kpdebug("FAIL. Can't find libc\n"); -+ return -1; -+ } -+ -+ rv = kpatch_resolve_undefined_single_dynamic(olibc, -+ "makecontext", -+ &makecontext); -+ makecontext = vaddr2addr(olibc, makecontext); -+ if (rv < 0 || makecontext == 0) { -+ kpdebug("FAIL. Can't find makecontext\n"); -+ return -1; -+ } -+ -+ regs.regs[8] = makecontext; -+ rv = kpatch_execute_remote(proc2pctx(proc), -+ &makecontext_call, -+ &makecontext_call_end - &makecontext_call, -+ ®s); -+ if (rv < 0) { -+ kpdebug("FAIL. Can't execute makecontext\n"); -+ return -1; -+ } -+ -+ rv = kpatch_process_mem_read(proc, -+ regs.regs[29]- STACK_OFFSET_START_CONTEXT, -+ pstart_context, -+ sizeof(*pstart_context)); -+ if (rv < 0) { -+ kpdebug("FAIL. Can't peek __start_context address\n"); -+ return -1; -+ } -+ return rv; -+} -+ - int get_ptr_guard(struct kpatch_process *proc, - unsigned long *ptr_guard) - { -diff --git a/src/arch/x86/arch_coro.c b/src/arch/x86/arch_coro.c -index 86bf12f..27c834b 100644 ---- a/src/arch/x86/arch_coro.c -+++ b/src/arch/x86/arch_coro.c -@@ -15,6 +15,73 @@ - #include "include/kpatch_ptrace.h" - #include "include/kpatch_log.h" - -+asm ("makecontext_call:\n" -+ "mov %rsp, %rbp\n" -+ "and $-16, %rbp\n" -+ /* ucontext_t is 0x3a8 bytes */ -+ "sub $0x400, %rbp\n" -+ /* TODO interpolate these from the calculations above */ -+ -+ /* set uc_stack.ss_sp and uc_stack.ss_size */ -+ /* TODO magic -128 is used below as well */ -+ "lea -128(%rbp), %rbx\n" -+ "movq %rbx, 0x10(%rbp)\n" -+ "movq $128, 0x20(%rbp)\n" -+ "mov %rbp, %rdi\n" -+ "mov $0x100, %rsi\n" -+ "xor %rdx, %rdx\n" -+ /* call `makecontext` */ -+ "call *%rax\n" -+ "int3\n" -+ "makecontext_call_end:"); -+ -+extern unsigned char makecontext_call, makecontext_call_end; -+ -+int -+locate_start_context_symbol(struct kpatch_process *proc, -+ unsigned long *pstart_context) -+{ -+ struct object_file *olibc; -+ struct user_regs_struct regs; -+ int rv; -+ unsigned long makecontext; -+ -+ olibc = kpatch_process_get_obj_by_regex(proc, "^libc-.*\\.so"); -+ if (olibc == NULL) { -+ kpdebug("FAIL. Can't find libc\n"); -+ return -1; -+ } -+ -+ rv = kpatch_resolve_undefined_single_dynamic(olibc, -+ "makecontext", -+ &makecontext); -+ makecontext = vaddr2addr(olibc, makecontext); -+ if (rv < 0 || makecontext == 0) { -+ kpdebug("FAIL. Can't find makecontext\n"); -+ return -1; -+ } -+ -+ regs.rax = makecontext; -+ rv = kpatch_execute_remote(proc2pctx(proc), -+ &makecontext_call, -+ &makecontext_call_end - &makecontext_call, -+ ®s); -+ if (rv < 0) { -+ kpdebug("FAIL. Can't execute makecontext\n"); -+ return -1; -+ } -+ -+ rv = kpatch_process_mem_read(proc, -+ regs.rbp - STACK_OFFSET_START_CONTEXT, -+ pstart_context, -+ sizeof(*pstart_context)); -+ if (rv < 0) { -+ kpdebug("FAIL. Can't peek __start_context address\n"); -+ return -1; -+ } -+ return rv; -+} -+ - int get_ptr_guard(struct kpatch_process *proc, - unsigned long *ptr_guard) - { -diff --git a/src/include/kpatch_coro.h b/src/include/kpatch_coro.h -index 272855e..0b3a9a1 100644 ---- a/src/include/kpatch_coro.h -+++ b/src/include/kpatch_coro.h -@@ -30,10 +30,31 @@ struct UCORO_info { - int _UCORO_access_reg(unw_addr_space_t as, unw_regnum_t reg, - unw_word_t *val, int write, void *arg); - -+#define PTR_DEMANGLE(ptr, key) ((((ptr) >> 0x11) | ((ptr) << 47)) ^ key) -+#define JB_RBX 0 -+#define JB_RBP 1 -+#define JB_R12 2 -+#define JB_R13 3 -+#define JB_R14 4 -+#define JB_R15 5 -+#define JB_RSP 6 -+#define JB_RIP 7 -+ -+#define STACK_OFFSET_UC_LINK (2 * sizeof(long)) -+#define STACK_OFFSET_START_CONTEXT (3 * sizeof(long)) -+#define STACK_OFFSET_UC_LINK_PTR (4 * sizeof(long)) -+#define STACK_OFFSET_COROUTINE_UCONTEXT (7 * sizeof(long)) -+#define STACK_OFFSET_COROUTINE (8 * sizeof(long)) -+ -+#define UCONTEXT_OFFSET_JMPBUF 0x38 -+ - #define GLIBC_TLS_PTR_GUARD 0x30 - int get_ptr_guard(struct kpatch_process *proc, - unsigned long *ptr_guard); - -+int locate_start_context_symbol(struct kpatch_process *proc, -+ unsigned long *pstart_context); -+ - - int kpatch_coroutines_init(struct kpatch_process *proc); - int kpatch_coroutines_find(struct kpatch_process *proc); -diff --git a/src/kpatch_coro.c b/src/kpatch_coro.c -index ea4050f..8457800 100644 ---- a/src/kpatch_coro.c -+++ b/src/kpatch_coro.c -@@ -95,93 +95,6 @@ kpatch_coro_free(struct kpatch_coro *c) - * some kind of persistency (to allow kernelcare updates). This - * service also can listen to netlink events about new processes. - */ --#define PTR_DEMANGLE(ptr, key) ((((ptr) >> 0x11) | ((ptr) << 47)) ^ key) --#define JB_RBX 0 --#define JB_RBP 1 --#define JB_R12 2 --#define JB_R13 3 --#define JB_R14 4 --#define JB_R15 5 --#define JB_RSP 6 --#define JB_RIP 7 -- --#define STACK_OFFSET_UC_LINK (2 * sizeof(long)) --#define STACK_OFFSET_START_CONTEXT (3 * sizeof(long)) --#define STACK_OFFSET_UC_LINK_PTR (4 * sizeof(long)) --#define STACK_OFFSET_COROUTINE_UCONTEXT (7 * sizeof(long)) --#define STACK_OFFSET_COROUTINE (8 * sizeof(long)) -- --#define UCONTEXT_OFFSET_JMPBUF 0x38 -- --#define UCONTEXT_OFFSET_UC_STACK_SS_SP offsetof(ucontext_t, uc_stack.ss_sp) --#define UCONTEXT_OFFSET_UC_STACK_SS_SIZE offsetof(ucontext_t, uc_stack.ss_size) -- --asm ("makecontext_call:\n" -- "mov %rsp, %rbp\n" -- "and $-16, %rbp\n" -- /* ucontext_t is 0x3a8 bytes */ -- "sub $0x400, %rbp\n" -- /* TODO interpolate these from the calculations above */ -- -- /* set uc_stack.ss_sp and uc_stack.ss_size */ -- /* TODO magic -128 is used below as well */ -- "lea -128(%rbp), %rbx\n" -- "movq %rbx, 0x10(%rbp)\n" -- "movq $128, 0x20(%rbp)\n" -- "mov %rbp, %rdi\n" -- "mov $0x100, %rsi\n" -- "xor %rdx, %rdx\n" -- /* call `makecontext` */ -- "call *%rax\n" -- "int3\n" -- "makecontext_call_end:"); -- --extern unsigned char makecontext_call, makecontext_call_end; -- --static int --locate_start_context_symbol(struct kpatch_process *proc, -- unsigned long *pstart_context) --{ -- struct object_file *olibc; -- struct user_regs_struct regs; -- int rv; -- unsigned long makecontext; -- -- olibc = kpatch_process_get_obj_by_regex(proc, "^libc-.*\\.so"); -- if (olibc == NULL) { -- kpdebug("FAIL. Can't find libc\n"); -- return -1; -- } -- -- rv = kpatch_resolve_undefined_single_dynamic(olibc, -- "makecontext", -- &makecontext); -- makecontext = vaddr2addr(olibc, makecontext); -- if (rv < 0 || makecontext == 0) { -- kpdebug("FAIL. Can't find makecontext\n"); -- return -1; -- } -- -- regs.rax = makecontext; -- rv = kpatch_execute_remote(proc2pctx(proc), -- &makecontext_call, -- &makecontext_call_end - &makecontext_call, -- ®s); -- if (rv < 0) { -- kpdebug("FAIL. Can't execute makecontext\n"); -- return -1; -- } -- -- rv = kpatch_process_mem_read(proc, -- regs.rbp - STACK_OFFSET_START_CONTEXT, -- pstart_context, -- sizeof(*pstart_context)); -- if (rv < 0) { -- kpdebug("FAIL. Can't peek __start_context address\n"); -- return -1; -- } -- return rv; --} - - static int is_test_target(struct kpatch_process *proc, - const char *procname) --- -2.23.0 - diff --git a/0035-kpatch_patch-Split-function-patch_apply_hunk.patch b/0035-kpatch_patch-Split-function-patch_apply_hunk.patch deleted file mode 100644 index 8a579976a2cc7d08c11d8dcd213a68ae8cc18a07..0000000000000000000000000000000000000000 --- a/0035-kpatch_patch-Split-function-patch_apply_hunk.patch +++ /dev/null @@ -1,237 +0,0 @@ -From 4f165eacd6d1d64cc43a58dd54e35017663d99e2 Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Mon, 12 Oct 2020 14:58:18 +0800 -Subject: [PATCH 35/89] kpatch_patch: Split function patch_apply_hunk - -The function patch_apply_hunk is arch related, so make two -separate definations in arch/x86/arch_patch.c and arch/aarch64/arch_patch.c - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/arch/aarch64/arch_patch.c | 68 +++++++++++++++++++++++++++++++++++ - src/arch/x86/arch_patch.c | 66 ++++++++++++++++++++++++++++++++++ - src/include/kpatch_patch.h | 2 ++ - src/kpatch_patch.c | 44 ++--------------------- - 4 files changed, 139 insertions(+), 41 deletions(-) - -diff --git a/src/arch/aarch64/arch_patch.c b/src/arch/aarch64/arch_patch.c -index e69de29..9102621 100644 ---- a/src/arch/aarch64/arch_patch.c -+++ b/src/arch/aarch64/arch_patch.c -@@ -0,0 +1,68 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "include/kpatch_patch.h" -+#include "include/kpatch_user.h" -+#include "include/kpatch_storage.h" -+#include "include/kpatch_process.h" -+#include "include/kpatch_file.h" -+#include "include/kpatch_common.h" -+#include "include/kpatch_elf.h" -+#include "include/kpatch_ptrace.h" -+#include "include/list.h" -+#include "include/kpatch_log.h" -+ -+ -+/***************************************************************************** -+ * Patch application subroutines -+ ****************************************************************************/ -+/* -+ * This flag is local, i.e. it is never stored to the -+ * patch applied to patient's memory. -+ */ -+int PATCH_APPLIED = (1 << 31); -+int HUNK_SIZE = 4; -+ -+int patch_apply_hunk(struct object_file *o, size_t nhunk) -+{ -+ int ret; -+ unsigned char code[] = {0x00, 0x00, 0x00, 0x00}; /* ins: b IMM */ -+ struct kpatch_info *info = &o->info[nhunk]; -+ unsigned long pundo; -+ -+ if (is_new_func(info)) -+ return 0; -+ -+ pundo = o->kpta + o->kpfile.patch->user_undo + nhunk * HUNK_SIZE; -+ kpinfo("%s origcode from 0x%lx+0x%x to 0x%lx\n", -+ o->name, info->daddr, HUNK_SIZE, pundo); -+ ret = kpatch_process_memcpy(o->proc, pundo, -+ info->daddr, HUNK_SIZE); -+ if (ret < 0) -+ return ret; -+ -+ kpinfo("%s hunk 0x%lx+0x%x -> 0x%lx+0x%x\n", -+ o->name, info->daddr, info->dlen, info->saddr, info->slen); -+ -+ *(unsigned int *)(code) = (unsigned int)(info->saddr - info->daddr) / 4; -+ code[3] &= 0x3; -+ code[3] |= 0x14; -+ -+ ret = kpatch_process_mem_write(o->proc, -+ code, -+ info->daddr, -+ sizeof(code)); -+ /* -+ * NOTE(pboldin): This is only stored locally, as information have -+ * been copied to patient's memory already. -+ */ -+ info->flags |= PATCH_APPLIED; -+ return ret ? -1 : 0; -+} -diff --git a/src/arch/x86/arch_patch.c b/src/arch/x86/arch_patch.c -index e69de29..a6e794d 100644 ---- a/src/arch/x86/arch_patch.c -+++ b/src/arch/x86/arch_patch.c -@@ -0,0 +1,66 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "include/kpatch_patch.h" -+#include "include/kpatch_user.h" -+#include "include/kpatch_storage.h" -+#include "include/kpatch_process.h" -+#include "include/kpatch_file.h" -+#include "include/kpatch_common.h" -+#include "include/kpatch_elf.h" -+#include "include/kpatch_ptrace.h" -+#include "include/list.h" -+#include "include/kpatch_log.h" -+ -+/***************************************************************************** -+ * Patch application subroutines -+ ****************************************************************************/ -+/* -+ * This flag is local, i.e. it is never stored to the -+ * patch applied to patient's memory. -+ */ -+int PATCH_APPLIED = (1 << 31); -+int HUNK_SIZE = 5; -+ -+int patch_apply_hunk(struct object_file *o, size_t nhunk) -+{ -+ int ret; -+ char code[] = {0xe9, 0x00, 0x00, 0x00, 0x00}; /* jmp IMM */ -+ struct kpatch_info *info = &o->info[nhunk]; -+ unsigned long pundo; -+ -+ if (is_new_func(info)) -+ return 0; -+ -+ pundo = o->kpta + o->kpfile.patch->user_undo + nhunk * HUNK_SIZE; -+ kpinfo("%s origcode from 0x%lx+0x%x to 0x%lx\n", -+ o->name, info->daddr, HUNK_SIZE, pundo); -+ ret = kpatch_process_memcpy(o->proc, pundo, -+ info->daddr, HUNK_SIZE); -+ if (ret < 0) -+ return ret; -+ -+ kpinfo("%s hunk 0x%lx+0x%x -> 0x%lx+0x%x\n", -+ o->name, info->daddr, info->dlen, info->saddr, info->slen); -+ *(unsigned int *)(code + 1) = (unsigned int)(info->saddr - info->daddr - 5); -+ ret = kpatch_process_mem_write(o->proc, -+ code, -+ info->daddr, -+ sizeof(code)); -+ /* -+ * NOTE(pboldin): This is only stored locally, as information have -+ * been copied to patient's memory already. -+ */ -+ info->flags |= PATCH_APPLIED; -+ return ret ? -1 : 0; -+} -+ -diff --git a/src/include/kpatch_patch.h b/src/include/kpatch_patch.h -index 44806ab..fa96b08 100644 ---- a/src/include/kpatch_patch.h -+++ b/src/include/kpatch_patch.h -@@ -25,4 +25,6 @@ struct unpatch_data { - int process_patch(int pid, void *_data); - int process_unpatch(int pid, void *_data); - -+int patch_apply_hunk(struct object_file *o, size_t nhunk); -+ - #endif -diff --git a/src/kpatch_patch.c b/src/kpatch_patch.c -index 21a160a..4a1d149 100644 ---- a/src/kpatch_patch.c -+++ b/src/kpatch_patch.c -@@ -270,47 +270,6 @@ patch_ensure_safety(struct object_file *o, - /***************************************************************************** - * Patch application subroutines - ****************************************************************************/ --/* -- * This flag is local, i.e. it is never stored to the -- * patch applied to patient's memory. -- */ --#define PATCH_APPLIED (1 << 31) -- --#define HUNK_SIZE 5 -- --static int --patch_apply_hunk(struct object_file *o, size_t nhunk) --{ -- int ret; -- char code[HUNK_SIZE] = {0xe9, 0x00, 0x00, 0x00, 0x00}; /* jmp IMM */ -- struct kpatch_info *info = &o->info[nhunk]; -- unsigned long pundo; -- -- if (is_new_func(info)) -- return 0; -- -- pundo = o->kpta + o->kpfile.patch->user_undo + nhunk * HUNK_SIZE; -- kpinfo("%s origcode from 0x%lx+0x%x to 0x%lx\n", -- o->name, info->daddr, HUNK_SIZE, pundo); -- ret = kpatch_process_memcpy(o->proc, pundo, -- info->daddr, HUNK_SIZE); -- if (ret < 0) -- return ret; -- -- kpinfo("%s hunk 0x%lx+0x%x -> 0x%lx+0x%x\n", -- o->name, info->daddr, info->dlen, info->saddr, info->slen); -- *(unsigned int *)(code + 1) = (unsigned int)(info->saddr - info->daddr - 5); -- ret = kpatch_process_mem_write(o->proc, -- code, -- info->daddr, -- sizeof(code)); -- /* -- * NOTE(pboldin): This is only stored locally, as information have -- * been copied to patient's memory already. -- */ -- info->flags |= PATCH_APPLIED; -- return ret ? -1 : 0; --} - - static int - duplicate_kp_file(struct object_file *o) -@@ -328,6 +287,9 @@ duplicate_kp_file(struct object_file *o) - return 0; - } - -+extern int PATCH_APPLIED; -+extern int HUNK_SIZE; -+ - static int - object_apply_patch(struct object_file *o) - { --- -2.23.0 - diff --git a/0036-kpatch_elf-Split-function-kpatch_add_jmp_entry.patch b/0036-kpatch_elf-Split-function-kpatch_add_jmp_entry.patch deleted file mode 100644 index 68bc71a7086206f3c7d45fc0654fe500b7b72437..0000000000000000000000000000000000000000 --- a/0036-kpatch_elf-Split-function-kpatch_add_jmp_entry.patch +++ /dev/null @@ -1,151 +0,0 @@ -From 3352c27078a63b5bfc6ff4df639489fdabfd4dbe Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Mon, 12 Oct 2020 15:11:05 +0800 -Subject: [PATCH 36/89] kpatch_elf: Split function kpatch_add_jmp_entry - -The function kpatch_add_jmp_entry is arch related. To support multi-arch -let's rename it with kpatch_arch_add_jmp_entry, and make the defination in -arch/x86/arch_elf.c and arch/aarch64/arch_elf.c - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/arch/aarch64/arch_elf.c | 35 +++++++++++++++++++++++++++++++++++ - src/arch/x86/arch_elf.c | 35 +++++++++++++++++++++++++++++++++++ - src/include/kpatch_elf.h | 2 ++ - src/kpatch_elf.c | 21 +-------------------- - 4 files changed, 73 insertions(+), 20 deletions(-) - -diff --git a/src/arch/aarch64/arch_elf.c b/src/arch/aarch64/arch_elf.c -index e69de29..b977489 100644 ---- a/src/arch/aarch64/arch_elf.c -+++ b/src/arch/aarch64/arch_elf.c -@@ -0,0 +1,35 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include "include/kpatch_common.h" -+#include "include/kpatch_user.h" -+#include "include/kpatch_process.h" -+#include "include/kpatch_elf.h" -+#include "include/kpatch_file.h" -+#include "include/kpatch_ptrace.h" -+#include "include/kpatch_log.h" -+ -+#define JMP_TABLE_JUMP 0xd61f022058000051 /* ldr x17 #8; br x17 */ -+unsigned long kpatch_arch_add_jmp_entry(struct object_file *o, unsigned long addr) -+{ -+ struct kpatch_jmp_table_entry entry = {JMP_TABLE_JUMP, addr}; -+ int e; -+ -+ if (o->jmp_table == NULL) { -+ kpfatalerror("JMP TABLE not found\n"); -+ return 0; -+ } -+ -+ if (o->jmp_table->cur_entry >= o->jmp_table->max_entry) -+ return 0; -+ e = o->jmp_table->cur_entry++; -+ o->jmp_table->entries[e] = entry; -+ return (unsigned long)(o->kpta + o->kpfile.patch->jmp_offset + \ -+ ((void *)&o->jmp_table->entries[e] - (void *)o->jmp_table)); -+} -diff --git a/src/arch/x86/arch_elf.c b/src/arch/x86/arch_elf.c -index e69de29..ef5564e 100644 ---- a/src/arch/x86/arch_elf.c -+++ b/src/arch/x86/arch_elf.c -@@ -0,0 +1,35 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include "include/kpatch_common.h" -+#include "include/kpatch_user.h" -+#include "include/kpatch_process.h" -+#include "include/kpatch_elf.h" -+#include "include/kpatch_file.h" -+#include "include/kpatch_ptrace.h" -+#include "include/kpatch_log.h" -+ -+#define JMP_TABLE_JUMP 0x90900000000225ff /* jmp [rip+2]; nop; nop */ -+unsigned long kpatch_arch_add_jmp_entry(struct object_file *o, unsigned long addr) -+{ -+ struct kpatch_jmp_table_entry entry = {JMP_TABLE_JUMP, addr}; -+ int e; -+ -+ if (o->jmp_table == NULL) { -+ kpfatalerror("JMP TABLE not found\n"); -+ return 0; -+ } -+ -+ if (o->jmp_table->cur_entry >= o->jmp_table->max_entry) -+ return 0; -+ e = o->jmp_table->cur_entry++; -+ o->jmp_table->entries[e] = entry; -+ return (unsigned long)(o->kpta + o->kpfile.patch->jmp_offset + \ -+ ((void *)&o->jmp_table->entries[e] - (void *)o->jmp_table)); -+} -diff --git a/src/include/kpatch_elf.h b/src/include/kpatch_elf.h -index 8c0a4a4..7e5d8c3 100644 ---- a/src/include/kpatch_elf.h -+++ b/src/include/kpatch_elf.h -@@ -43,4 +43,6 @@ struct kpatch_jmp_table { - struct kpatch_jmp_table_entry entries[0]; - }; - -+unsigned long kpatch_arch_add_jmp_entry(struct object_file *o, unsigned long addr); -+ - #endif -diff --git a/src/kpatch_elf.c b/src/kpatch_elf.c -index b1dfed0..21ba496 100644 ---- a/src/kpatch_elf.c -+++ b/src/kpatch_elf.c -@@ -686,25 +686,6 @@ kpatch_resolve_undefined(struct object_file *obj, - return addr; - } - --#define JMP_TABLE_JUMP 0x90900000000225ff /* jmp [rip+2]; nop; nop */ --static unsigned long kpatch_add_jmp_entry(struct object_file *o, unsigned long addr) --{ -- struct kpatch_jmp_table_entry entry = {JMP_TABLE_JUMP, addr}; -- int e; -- -- if (o->jmp_table == NULL) { -- kpfatalerror("JMP TABLE not found\n"); -- return 0; -- } -- -- if (o->jmp_table->cur_entry >= o->jmp_table->max_entry) -- return 0; -- e = o->jmp_table->cur_entry++; -- o->jmp_table->entries[e] = entry; -- return (unsigned long)(o->kpta + o->kpfile.patch->jmp_offset + \ -- ((void *)&o->jmp_table->entries[e] - (void *)o->jmp_table)); --} -- - static inline int - symbol_resolve(struct object_file *o, - GElf_Shdr *shdr, -@@ -737,7 +718,7 @@ symbol_resolve(struct object_file *o, - } - /* OK, we overuse st_size to store original offset */ - s->st_size = uaddr; -- s->st_value = kpatch_add_jmp_entry(o, uaddr); -+ s->st_value = kpatch_arch_add_jmp_entry(o, uaddr); - - kpdebug("symbol '%s' = 0x%lx\n", - symname, uaddr); --- -2.23.0 - diff --git a/0037-kpatch_elf-Split-function-kpatch_apply_relocate_add.patch b/0037-kpatch_elf-Split-function-kpatch_apply_relocate_add.patch deleted file mode 100644 index 66916c3cbe4c7249f1507466ca9f5d3fc26d68f1..0000000000000000000000000000000000000000 --- a/0037-kpatch_elf-Split-function-kpatch_apply_relocate_add.patch +++ /dev/null @@ -1,414 +0,0 @@ -From 69837926282fc65d41be15390d9a125da97adc54 Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Mon, 12 Oct 2020 15:37:08 +0800 -Subject: [PATCH 37/89] kpatch_elf: Split function kpatch_apply_relocate_add - -The function kpatch_apply_relocate_add is arch related. To support multi-arch -let's rename it with kpatch_arch_apply_relocate_add, and make the defination -in arch/x86/arch_elf.c and arch/aarch64/arch_elf.c - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/arch/aarch64/arch_elf.c | 100 ++++++++++++++++++++++++++++++++++++ - src/arch/x86/arch_elf.c | 89 ++++++++++++++++++++++++++++++++ - src/include/bitops.h | 27 ++++++++++ - src/include/kpatch_elf.h | 5 ++ - src/kpatch_elf.c | 94 ++------------------------------- - 5 files changed, 224 insertions(+), 91 deletions(-) - create mode 100644 src/include/bitops.h - -diff --git a/src/arch/aarch64/arch_elf.c b/src/arch/aarch64/arch_elf.c -index b977489..deacb6f 100644 ---- a/src/arch/aarch64/arch_elf.c -+++ b/src/arch/aarch64/arch_elf.c -@@ -14,6 +14,106 @@ - #include "include/kpatch_file.h" - #include "include/kpatch_ptrace.h" - #include "include/kpatch_log.h" -+#include "include/bitops.h" -+ -+static int kpatch_arch_apply_relocate(GElf_Rela *r, GElf_Sym *s, -+ void *loc, void *loc2, unsigned long val) -+{ -+ switch (GELF_R_TYPE(r->r_info)) { -+ case R_AARCH64_ABS64: -+ *(unsigned long *)loc = val; -+ kpdebug("R_AARCH64_ABS64: loc=0x%x, val =0x%lx\n",*(unsigned int*)loc,val); -+ break; -+ case R_AARCH64_ADD_ABS_LO12_NC: { -+ //ADD ins -+ kpdebug("R_AARCH64_ADD_ABS_LO12_NC: val=0x%lx\n", val); -+ val = val & 0xfff; -+ uint32_t mask = 0xfff << 10; -+ *(unsigned int*)loc &= ~mask; -+ or_32(loc, (val & 0xfff) << 10); -+ kpdebug("R_AARCH64_ADD_ABS_LO12_NC: loc=0x%x, val =0x%lx\n",*(unsigned int*)loc,val); -+ break; -+ } -+ case R_AARCH64_CALL26: { -+ // TODO bl ins -+ kpdebug("R_AARCH64_CALL26: val=0x%lx\n", val); -+ val -= (unsigned long)loc2; -+ uint32_t mask = 0x03FFFFFF;; -+ *(unsigned int*)loc &= ~mask; -+ or_32(loc, (val >> 2) & mask); -+ kpdebug("R_AARCH64_CALL26: loc=0x%x, val =0x%lx\n",*(unsigned int*)loc, val); -+ break; -+ } -+ case R_AARCH64_ADR_PREL_PG_HI21: { -+ // TODO ADRP ins -+ kpdebug("RR_AARCH64_ADR_PREL_PG_HI21: val=0x%lx\n", val); -+ val = (val >> 12) - ((unsigned long)loc2 >> 12); -+ kpdebug("val=0x%lx\n",val); -+ uint32_t immLo = (val & 0x3) << 29; -+ uint32_t immHi = (val & 0x1FFFFC) << 3; -+ uint64_t mask = (0x3 << 29) | (0x1FFFFC << 3); -+ *(unsigned int*)loc = (*(unsigned int*)loc & ~mask) | immLo | immHi; -+ //*(unsigned int*)loc &= 0x7fffffff; -+ kpdebug("lo=0x%x hi=0x%x\n",immLo,immHi); -+ kpdebug("R_AARCH64_ADR_PREL_PG_HI21: loc=0x%x, val=0x%lx\n", *(unsigned int *)loc, val); -+ break; -+ } -+ default: -+ kperr("unknown relocation type: %lx\n", r->r_info); -+ return -1; -+ } -+ return 0; -+} -+ -+int kpatch_arch_apply_relocate_add(struct object_file *o, GElf_Shdr *relsec) -+{ -+ struct kpatch_file *kp = o->kpfile.patch; -+ GElf_Ehdr *ehdr = (void *)kp + kp->kpatch_offset; -+ GElf_Shdr *shdr = (void *)ehdr + ehdr->e_shoff, *symhdr; -+ GElf_Rela *relocs = (void *)ehdr + relsec->sh_offset; -+ GElf_Shdr *tshdr = shdr + relsec->sh_info; -+ void *t = (void *)ehdr + shdr[relsec->sh_info].sh_offset; -+ void *tshdr2 = (void *)shdr[relsec->sh_info].sh_addr; -+ int i, is_kpatch_info; -+ const char *scnname; -+ -+ for (i = 1; i < ehdr->e_shnum; i++) { -+ if (shdr[i].sh_type == SHT_SYMTAB) -+ symhdr = &shdr[i]; -+ } -+ -+ scnname = secname(ehdr, shdr + relsec->sh_info); -+ kpdebug("applying relocations to '%s'\n", scnname); -+ is_kpatch_info = strcmp(scnname, ".kpatch.info") == 0; -+ -+ for (i = 0; i < relsec->sh_size / sizeof(*relocs); i++) { -+ GElf_Rela *r = relocs + i; -+ GElf_Sym *s; -+ unsigned long val; -+ void *loc, *loc2; -+ -+ if (r->r_offset < 0 || r->r_offset >= tshdr->sh_size) -+ kpfatalerror("Relocation offset for section '%s'" -+ " is at 0x%lx beyond the section size 0x%lx\n", -+ scnname, r->r_offset, tshdr->sh_size); -+ -+ /* Location in our address space */ -+ loc = t + r->r_offset; -+ /* Location in target process address space (for relative addressing) */ -+ loc2 = tshdr2 + r->r_offset; -+ s = (GElf_Sym *)((void *)ehdr + symhdr->sh_offset) + GELF_R_SYM(r->r_info); -+ val = s->st_value + r->r_addend; -+ -+ if (is_kpatch_info && is_undef_symbol(s)) { -+ val = s->st_size; -+ } -+ -+ kpatch_arch_apply_relocate(r, s, loc, loc2, val); -+ } -+ -+ return 0; -+} -+ - - #define JMP_TABLE_JUMP 0xd61f022058000051 /* ldr x17 #8; br x17 */ - unsigned long kpatch_arch_add_jmp_entry(struct object_file *o, unsigned long addr) -diff --git a/src/arch/x86/arch_elf.c b/src/arch/x86/arch_elf.c -index ef5564e..52de117 100644 ---- a/src/arch/x86/arch_elf.c -+++ b/src/arch/x86/arch_elf.c -@@ -15,6 +15,95 @@ - #include "include/kpatch_ptrace.h" - #include "include/kpatch_log.h" - -+int kpatch_arch_apply_relocate_add(struct object_file *o, GElf_Shdr *relsec) -+{ -+ struct kpatch_file *kp = o->kpfile.patch; -+ GElf_Ehdr *ehdr = (void *)kp + kp->kpatch_offset; -+ GElf_Shdr *shdr = (void *)ehdr + ehdr->e_shoff, *symhdr; -+ GElf_Rela *relocs = (void *)ehdr + relsec->sh_offset; -+ GElf_Shdr *tshdr = shdr + relsec->sh_info; -+ void *t = (void *)ehdr + shdr[relsec->sh_info].sh_offset; -+ void *tshdr2 = (void *)shdr[relsec->sh_info].sh_addr; -+ int i, is_kpatch_info; -+ const char *scnname; -+ -+ for (i = 1; i < ehdr->e_shnum; i++) { -+ if (shdr[i].sh_type == SHT_SYMTAB) -+ symhdr = &shdr[i]; -+ } -+ -+ scnname = secname(ehdr, shdr + relsec->sh_info); -+ kpdebug("applying relocations to '%s'\n", scnname); -+ is_kpatch_info = strcmp(scnname, ".kpatch.info") == 0; -+ -+ for (i = 0; i < relsec->sh_size / sizeof(*relocs); i++) { -+ GElf_Rela *r = relocs + i; -+ GElf_Sym *s; -+ unsigned long val; -+ void *loc, *loc2; -+ -+ if (r->r_offset < 0 || r->r_offset >= tshdr->sh_size) -+ kpfatalerror("Relocation offset for section '%s'" -+ " is at 0x%lx beyond the section size 0x%lx\n", -+ scnname, r->r_offset, tshdr->sh_size); -+ -+ /* Location in our address space */ -+ loc = t + r->r_offset; -+ /* Location in target process address space (for relative addressing) */ -+ loc2 = tshdr2 + r->r_offset; -+ s = (GElf_Sym *)((void *)ehdr + symhdr->sh_offset) + GELF_R_SYM(r->r_info); -+ val = s->st_value + r->r_addend; -+ -+ if (is_kpatch_info && is_undef_symbol(s)) { -+ val = s->st_size; -+ } -+ -+ switch (GELF_R_TYPE(r->r_info)) { -+ case R_X86_64_NONE: -+ break; -+ case R_X86_64_64: -+ *(unsigned long *)loc = val; -+ break; -+ case R_X86_64_32: -+ *(unsigned int *)loc = val; -+ break; -+ case R_X86_64_32S: -+ *(signed int *)loc = val; -+ break; -+ case R_X86_64_GOTTPOFF: -+ case R_X86_64_GOTPCREL: -+ case R_X86_64_REX_GOTPCRELX: -+ case R_X86_64_GOTPCRELX: -+ if (is_undef_symbol(s)) { -+ /* This is an undefined symbol, -+ * use jmp table as the GOT */ -+ val += sizeof(unsigned long); -+ } else if (GELF_ST_TYPE(s->st_info) == STT_TLS) { -+ /* This is GOTTPOFF that already points -+ * to an appropriate GOT entry in the -+ * patient's memory. -+ */ -+ val = r->r_addend + o->load_offset - 4; -+ } -+ /* FALLTHROUGH */ -+ case R_X86_64_PC32: -+ val -= (unsigned long)loc2; -+ *(unsigned int *)loc = val; -+ break; -+ case R_X86_64_TPOFF64: -+ case R_X86_64_TPOFF32: -+ kperr("TPOFF32/TPOFF64 should not be present\n"); -+ break; -+ default: -+ kperr("unknown relocation type: %lx\n", r->r_info); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+ - #define JMP_TABLE_JUMP 0x90900000000225ff /* jmp [rip+2]; nop; nop */ - unsigned long kpatch_arch_add_jmp_entry(struct object_file *o, unsigned long addr) - { -diff --git a/src/include/bitops.h b/src/include/bitops.h -new file mode 100644 -index 0000000..aab1679 ---- /dev/null -+++ b/src/include/bitops.h -@@ -0,0 +1,27 @@ -+#ifndef BITOPS_H -+#define BITOPS_H -+ -+#define BITS_PER_BYTE CHAR_BIT -+#define BITS_PER_LONG (sizeof (unsigned long) * BITS_PER_BYTE) -+ -+#define BIT(nr) (1UL << (nr)) -+#define BIT_ULL(nr) (1ULL << (nr)) -+#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) -+#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) -+#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) -+ -+static inline void or_32(void *addr, unsigned int val) -+{ -+ *(unsigned int*) addr = *(unsigned int*)addr | val; -+} -+ -+static inline void or_64(void *addr, unsigned long val) -+{ -+ *(unsigned long*) addr = *(unsigned long*)addr | val; -+} -+ -+static inline void and_32(void *addr, unsigned int val) -+{ -+ *(unsigned int*) addr = *(unsigned int*)addr & val; -+} -+#endif -diff --git a/src/include/kpatch_elf.h b/src/include/kpatch_elf.h -index 7e5d8c3..74efe04 100644 ---- a/src/include/kpatch_elf.h -+++ b/src/include/kpatch_elf.h -@@ -1,6 +1,7 @@ - #ifndef __KPATCH_ELF__ - #define __KPATCH_ELF__ - -+#include - #include "kpatch_process.h" - - const char *kpatch_get_buildid(struct object_file *o); -@@ -45,4 +46,8 @@ struct kpatch_jmp_table { - - unsigned long kpatch_arch_add_jmp_entry(struct object_file *o, unsigned long addr); - -+char *secname(GElf_Ehdr *ehdr, GElf_Shdr *s); -+int is_undef_symbol(const Elf64_Sym *sym); -+int kpatch_arch_apply_relocate_add(struct object_file *o, GElf_Shdr *relsec); -+ - #endif -diff --git a/src/kpatch_elf.c b/src/kpatch_elf.c -index 21ba496..5506292 100644 ---- a/src/kpatch_elf.c -+++ b/src/kpatch_elf.c -@@ -410,7 +410,7 @@ out: - return rv; - } - --static char *secname(GElf_Ehdr *ehdr, GElf_Shdr *s) -+char *secname(GElf_Ehdr *ehdr, GElf_Shdr *s) - { - GElf_Shdr *shdr = (void *)ehdr + ehdr->e_shoff; - char *str = (void *)ehdr + shdr[ehdr->e_shstrndx].sh_offset; -@@ -450,7 +450,7 @@ struct kpatch_jmp_table *kpatch_new_jmp_table(int entries) - return jtbl; - } - --static inline int -+inline int - is_undef_symbol(const Elf64_Sym *sym) - { - return sym->st_shndx == SHN_UNDEF || sym->st_shndx >= SHN_LORESERVE; -@@ -805,94 +805,6 @@ int kpatch_resolve(struct object_file *o) - return 0; - } - --static int kpatch_apply_relocate_add(struct object_file *o, GElf_Shdr *relsec) --{ -- struct kpatch_file *kp = o->kpfile.patch; -- GElf_Ehdr *ehdr = (void *)kp + kp->kpatch_offset; -- GElf_Shdr *shdr = (void *)ehdr + ehdr->e_shoff, *symhdr; -- GElf_Rela *relocs = (void *)ehdr + relsec->sh_offset; -- GElf_Shdr *tshdr = shdr + relsec->sh_info; -- void *t = (void *)ehdr + shdr[relsec->sh_info].sh_offset; -- void *tshdr2 = (void *)shdr[relsec->sh_info].sh_addr; -- int i, is_kpatch_info; -- const char *scnname; -- -- for (i = 1; i < ehdr->e_shnum; i++) { -- if (shdr[i].sh_type == SHT_SYMTAB) -- symhdr = &shdr[i]; -- } -- -- scnname = secname(ehdr, shdr + relsec->sh_info); -- kpdebug("applying relocations to '%s'\n", scnname); -- is_kpatch_info = strcmp(scnname, ".kpatch.info") == 0; -- -- for (i = 0; i < relsec->sh_size / sizeof(*relocs); i++) { -- GElf_Rela *r = relocs + i; -- GElf_Sym *s; -- unsigned long val; -- void *loc, *loc2; -- -- if (r->r_offset < 0 || r->r_offset >= tshdr->sh_size) -- kpfatalerror("Relocation offset for section '%s'" -- " is at 0x%lx beyond the section size 0x%lx\n", -- scnname, r->r_offset, tshdr->sh_size); -- -- /* Location in our address space */ -- loc = t + r->r_offset; -- /* Location in target process address space (for relative addressing) */ -- loc2 = tshdr2 + r->r_offset; -- s = (GElf_Sym *)((void *)ehdr + symhdr->sh_offset) + GELF_R_SYM(r->r_info); -- val = s->st_value + r->r_addend; -- -- if (is_kpatch_info && is_undef_symbol(s)) { -- val = s->st_size; -- } -- -- switch (GELF_R_TYPE(r->r_info)) { -- case R_X86_64_NONE: -- break; -- case R_X86_64_64: -- *(unsigned long *)loc = val; -- break; -- case R_X86_64_32: -- *(unsigned int *)loc = val; -- break; -- case R_X86_64_32S: -- *(signed int *)loc = val; -- break; -- case R_X86_64_GOTTPOFF: -- case R_X86_64_GOTPCREL: -- case R_X86_64_REX_GOTPCRELX: -- case R_X86_64_GOTPCRELX: -- if (is_undef_symbol(s)) { -- /* This is an undefined symbol, -- * use jmp table as the GOT */ -- val += sizeof(unsigned long); -- } else if (GELF_ST_TYPE(s->st_info) == STT_TLS) { -- /* This is GOTTPOFF that already points -- * to an appropriate GOT entry in the -- * patient's memory. -- */ -- val = r->r_addend + o->load_offset - 4; -- } -- /* FALLTHROUGH */ -- case R_X86_64_PC32: -- val -= (unsigned long)loc2; -- *(unsigned int *)loc = val; -- break; -- case R_X86_64_TPOFF64: -- case R_X86_64_TPOFF32: -- kperr("TPOFF32/TPOFF64 should not be present\n"); -- break; -- default: -- kperr("unknown relocation type: %lx\n", r->r_info); -- return -1; -- } -- } -- -- return 0; --} -- - int kpatch_relocate(struct object_file *o) - { - GElf_Ehdr *ehdr; -@@ -907,7 +819,7 @@ int kpatch_relocate(struct object_file *o) - GElf_Shdr *s = shdr + i; - - if (s->sh_type == SHT_RELA) -- ret = kpatch_apply_relocate_add(o, s); -+ ret = kpatch_arch_apply_relocate_add(o, s); - else if (shdr->sh_type == SHT_REL) { - kperr("TODO: handle SHT_REL\n"); - return -1; --- -2.23.0 - diff --git a/0038-kpatch_process-Split-function-object_find_patch_regi.patch b/0038-kpatch_process-Split-function-object_find_patch_regi.patch deleted file mode 100644 index 9e830b74189ad3e3db05982ed95869758386f47a..0000000000000000000000000000000000000000 --- a/0038-kpatch_process-Split-function-object_find_patch_regi.patch +++ /dev/null @@ -1,416 +0,0 @@ -From 80c479726361710a9ac4f328687796a183cf780f Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Mon, 12 Oct 2020 15:56:42 +0800 -Subject: [PATCH 38/89] kpatch_process: Split function object_find_patch_region - -The function object_find_patch_region is arch related. Since process -virtual address layout may be different between x86 and aarch64, -let's make two separate definations in arch/x86/arch_process.c and -arch/aarch64/arch_process.c - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/arch.desc | 1 + - src/arch/aarch64/arch_process.c | 120 ++++++++++++++++++++++++++++++++ - src/arch/x86/arch_process.c | 108 ++++++++++++++++++++++++++++ - src/include/kpatch_process.h | 9 +++ - src/kpatch_process.c | 87 ++--------------------- - 5 files changed, 242 insertions(+), 83 deletions(-) - create mode 100644 src/arch.desc - create mode 100644 src/arch/aarch64/arch_process.c - create mode 100644 src/arch/x86/arch_process.c - -diff --git a/src/arch.desc b/src/arch.desc -new file mode 100644 -index 0000000..9647742 ---- /dev/null -+++ b/src/arch.desc -@@ -0,0 +1 @@ -+aarch64 -diff --git a/src/arch/aarch64/arch_process.c b/src/arch/aarch64/arch_process.c -new file mode 100644 -index 0000000..3a64d77 ---- /dev/null -+++ b/src/arch/aarch64/arch_process.c -@@ -0,0 +1,120 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+ -+#include "include/kpatch_process.h" -+#include "include/kpatch_file.h" -+#include "include/kpatch_common.h" -+#include "include/kpatch_elf.h" -+#include "include/kpatch_ptrace.h" -+#include "include/list.h" -+#include "include/kpatch_log.h" -+ -+/* -+ * Find region for a patch. Take object's `previous_hole` as a left candidate -+ * and the next hole as a right candidate. Pace through them until there is -+ * enough space in the hole for the patch. -+ * -+ * Since holes can be much larger than 2GiB take extra caution to allocate -+ * patch region inside the (-2GiB, +2GiB) range from the original object. -+ */ -+unsigned long -+object_find_patch_region(struct object_file *obj, -+ size_t memsize, -+ struct vm_hole **hole) -+{ -+ struct list_head *head = &obj->proc->vmaholes; -+ struct vm_hole *left_hole = obj->previous_hole, -+ *right_hole = next_hole(left_hole, head); -+ unsigned long max_distance = 0x80000000; -+ struct obj_vm_area *sovma; -+ -+ unsigned long obj_start, obj_end; -+ unsigned long region_start = 0, region_end = 0; -+ -+ kpdebug("Looking for patch region for '%s'...\n", obj->name); -+ -+ sovma = list_first_entry(&obj->vma, struct obj_vm_area, list); -+ obj_start = sovma->inmem.start; -+ sovma = list_entry(obj->vma.prev, struct obj_vm_area, list); -+ obj_end = sovma->inmem.end; -+ -+ -+ max_distance -= memsize; -+ -+ /* TODO carefully check for the holes laying between obj_start and -+ * obj_end, i.e. just after the executable segment of an executable -+ */ -+ while (left_hole != NULL && right_hole != NULL) { -+ if (right_hole != NULL && -+ right_hole->start - obj_start > max_distance) -+ right_hole = NULL; -+ else if (hole_size(right_hole) > memsize) { -+ region_start = right_hole->start; -+ region_end = -+ (right_hole->end - obj_start) <= max_distance ? -+ right_hole->end - memsize : -+ obj_start + max_distance; -+ *hole = right_hole; -+ break; -+ } else -+ right_hole = next_hole(right_hole, head); -+ -+ if (left_hole != NULL && -+ obj_end - left_hole->end > max_distance) -+ left_hole = NULL; -+ else if (hole_size(left_hole) > memsize) { -+ region_start = -+ (left_hole->start - obj_end) <= max_distance ? -+ left_hole->start : obj_end > max_distance ? -+ obj_end - max_distance : 0; -+ region_end = left_hole->end - memsize; -+ *hole = left_hole; -+ break; -+ } else -+ left_hole = prev_hole(left_hole, head); -+ } -+ -+ if (region_start == region_end) { -+ kperr("can't find suitable region for patch on '%s'\n", -+ obj->name); -+ return -1UL; -+ } -+ -+ /* -+ * On aarch64, virtual address of text and data segments may be continuous, -+ * gap between data segment and process heap may be huge. Need to have -+ * region_end fixed. Here goes the trick: -+ * The branch instruction jump size is in the range of +/-128MB. -+ * So we need to put limitation to the region_end. -+ */ -+ region_end = region_start + (0x1<<25); -+ region_start = random_from_range(region_start >> PAGE_SHIFT, -+ region_end >> PAGE_SHIFT); -+ region_start <<= PAGE_SHIFT; -+ kpdebug("Found patch region for '%s' at %lx\n", obj->name, region_start); -+ -+ return region_start; -+} -+ -diff --git a/src/arch/x86/arch_process.c b/src/arch/x86/arch_process.c -new file mode 100644 -index 0000000..ba66134 ---- /dev/null -+++ b/src/arch/x86/arch_process.c -@@ -0,0 +1,108 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+ -+#include "include/kpatch_process.h" -+#include "include/kpatch_file.h" -+#include "include/kpatch_common.h" -+#include "include/kpatch_elf.h" -+#include "include/kpatch_ptrace.h" -+#include "include/list.h" -+#include "include/kpatch_log.h" -+ -+/* -+ * Find region for a patch. Take object's `previous_hole` as a left candidate -+ * and the next hole as a right candidate. Pace through them until there is -+ * enough space in the hole for the patch. -+ * -+ * Since holes can be much larger than 2GiB take extra caution to allocate -+ * patch region inside the (-2GiB, +2GiB) range from the original object. -+ */ -+unsigned long object_find_patch_region(struct object_file *obj, -+ size_t memsize, -+ struct vm_hole **hole) -+{ -+ struct list_head *head = &obj->proc->vmaholes; -+ struct vm_hole *left_hole = obj->previous_hole, -+ *right_hole = next_hole(left_hole, head); -+ unsigned long max_distance = 0x80000000; -+ struct obj_vm_area *sovma; -+ -+ unsigned long obj_start, obj_end; -+ unsigned long region_start = 0, region_end = 0; -+ -+ kpdebug("Looking for patch region for '%s'...\n", obj->name); -+ -+ sovma = list_first_entry(&obj->vma, struct obj_vm_area, list); -+ obj_start = sovma->inmem.start; -+ sovma = list_entry(obj->vma.prev, struct obj_vm_area, list); -+ obj_end = sovma->inmem.end; -+ -+ -+ max_distance -= memsize; -+ -+ /* TODO carefully check for the holes laying between obj_start and -+ * obj_end, i.e. just after the executable segment of an executable -+ */ -+ while (left_hole != NULL && right_hole != NULL) { -+ if (right_hole != NULL && -+ right_hole->start - obj_start > max_distance) -+ right_hole = NULL; -+ else if (hole_size(right_hole) > memsize) { -+ region_start = right_hole->start; -+ region_end = -+ (right_hole->end - obj_start) <= max_distance ? -+ right_hole->end - memsize : -+ obj_start + max_distance; -+ *hole = right_hole; -+ break; -+ } else -+ right_hole = next_hole(right_hole, head); -+ -+ if (left_hole != NULL && -+ obj_end - left_hole->end > max_distance) -+ left_hole = NULL; -+ else if (hole_size(left_hole) > memsize) { -+ region_start = -+ (left_hole->start - obj_end) <= max_distance ? -+ left_hole->start : obj_end > max_distance ? -+ obj_end - max_distance : 0; -+ region_end = left_hole->end - memsize; -+ *hole = left_hole; -+ break; -+ } else -+ left_hole = prev_hole(left_hole, head); -+ } -+ -+ if (region_start == region_end) { -+ kperr("can't find suitable region for patch on '%s'\n", -+ obj->name); -+ return -1UL; -+ } -+ -+ region_start += PAGE_SIZE; -+ kpdebug("Found patch region for '%s' at %lx\n", obj->name, region_start); -+ -+ return region_start; -+} -diff --git a/src/include/kpatch_process.h b/src/include/kpatch_process.h -index abbb1af..b96a6da 100644 ---- a/src/include/kpatch_process.h -+++ b/src/include/kpatch_process.h -@@ -211,4 +211,13 @@ is_kernel_object_name(char *name) - return 0; - } - -+struct vm_hole *next_hole(struct vm_hole *hole, struct list_head *head); -+struct vm_hole *prev_hole(struct vm_hole *hole, struct list_head *head); -+unsigned long hole_size(struct vm_hole *hole); -+ -+unsigned long random_from_range(unsigned long min, unsigned long max); -+unsigned long object_find_patch_region(struct object_file *obj, -+ size_t memsize, -+ struct vm_hole **hole); -+ - #endif /* ifndef __KPATCH_PROCESS__ */ -diff --git a/src/kpatch_process.c b/src/kpatch_process.c -index 3f7f2f6..9561962 100644 ---- a/src/kpatch_process.c -+++ b/src/kpatch_process.c -@@ -965,7 +965,7 @@ vm_hole_split(struct vm_hole *hole, - return 0; - } - --static inline struct vm_hole * -+inline struct vm_hole * - next_hole(struct vm_hole *hole, struct list_head *head) - { - if (hole == NULL || hole->list.next == head) -@@ -974,7 +974,7 @@ next_hole(struct vm_hole *hole, struct list_head *head) - return list_entry(hole->list.next, struct vm_hole, list); - } - --static inline struct vm_hole * -+inline struct vm_hole * - prev_hole(struct vm_hole *hole, struct list_head *head) - { - if (hole == NULL || hole->list.prev == head) -@@ -983,7 +983,7 @@ prev_hole(struct vm_hole *hole, struct list_head *head) - return list_entry(hole->list.prev, struct vm_hole, list); - } - --static inline unsigned long -+inline unsigned long - hole_size(struct vm_hole *hole) - { - if (hole == NULL) -@@ -991,92 +991,13 @@ hole_size(struct vm_hole *hole) - return hole->end - hole->start; - } - --static unsigned long -+unsigned long - random_from_range(unsigned long min, unsigned long max) - { - /* TODO this is not uniform nor safe */ - return min + random() % (max - min); - } - --/* -- * Find region for a patch. Take object's `previous_hole` as a left candidate -- * and the next hole as a right candidate. Pace through them until there is -- * enough space in the hole for the patch. -- * -- * Since holes can be much larger than 2GiB take extra caution to allocate -- * patch region inside the (-2GiB, +2GiB) range from the original object. -- */ --static unsigned long --object_find_patch_region(struct object_file *obj, -- size_t memsize, -- struct vm_hole **hole) --{ -- struct list_head *head = &obj->proc->vmaholes; -- struct vm_hole *left_hole = obj->previous_hole, -- *right_hole = next_hole(left_hole, head); -- unsigned long max_distance = 0x80000000; -- struct obj_vm_area *sovma; -- -- unsigned long obj_start, obj_end; -- unsigned long region_start = 0, region_end = 0; -- -- kpdebug("Looking for patch region for '%s'...\n", obj->name); -- -- sovma = list_first_entry(&obj->vma, struct obj_vm_area, list); -- obj_start = sovma->inmem.start; -- sovma = list_entry(obj->vma.prev, struct obj_vm_area, list); -- obj_end = sovma->inmem.end; -- -- -- max_distance -= memsize; -- -- /* TODO carefully check for the holes laying between obj_start and -- * obj_end, i.e. just after the executable segment of an executable -- */ -- while (left_hole != NULL && right_hole != NULL) { -- if (right_hole != NULL && -- right_hole->start - obj_start > max_distance) -- right_hole = NULL; -- else if (hole_size(right_hole) > memsize) { -- region_start = right_hole->start; -- region_end = -- (right_hole->end - obj_start) <= max_distance ? -- right_hole->end - memsize : -- obj_start + max_distance; -- *hole = right_hole; -- break; -- } else -- right_hole = next_hole(right_hole, head); -- -- if (left_hole != NULL && -- obj_end - left_hole->end > max_distance) -- left_hole = NULL; -- else if (hole_size(left_hole) > memsize) { -- region_start = -- (left_hole->start - obj_end) <= max_distance ? -- left_hole->start : obj_end > max_distance ? -- obj_end - max_distance : 0; -- region_end = left_hole->end - memsize; -- *hole = left_hole; -- break; -- } else -- left_hole = prev_hole(left_hole, head); -- } -- -- if (region_start == region_end) { -- kperr("can't find suitable region for patch on '%s'\n", -- obj->name); -- return -1UL; -- } -- -- region_start = random_from_range(region_start >> PAGE_SHIFT, -- region_end >> PAGE_SHIFT); -- region_start <<= PAGE_SHIFT; -- kpdebug("Found patch region for '%s' at %lx\n", obj->name, region_start); -- -- return region_start; --} -- - int - kpatch_object_allocate_patch(struct object_file *o, - size_t sz) --- -2.23.0 - diff --git a/0039-kpatch_ptrace-Split-function-kpatch_ptrace_waitpid.patch b/0039-kpatch_ptrace-Split-function-kpatch_ptrace_waitpid.patch deleted file mode 100644 index 1ebd5e44f15b8a957f76756846dc073d8ec1b90e..0000000000000000000000000000000000000000 --- a/0039-kpatch_ptrace-Split-function-kpatch_ptrace_waitpid.patch +++ /dev/null @@ -1,501 +0,0 @@ -From 35b9c6934fc5c1e2ea4cf7e30b91b3b91e48074d Mon Sep 17 00:00:00 2001 -From: Jiajie Li -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 -Signed-off-by: Ying Fang ---- - 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "include/kpatch_process.h" -+#include "include/kpatch_common.h" -+#include "include/kpatch_ptrace.h" -+#include "include/kpatch_log.h" -+ -+#include -+ -+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 = ®s; -+ 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 *)®s_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*)®s_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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "include/kpatch_process.h" -+#include "include/kpatch_common.h" -+#include "include/kpatch_ptrace.h" -+#include "include/kpatch_log.h" -+ -+#include -+ -+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, ®s); -+ 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, ®s); -+ 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, ®s); -- 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, ®s); -- 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 - diff --git a/0040-kpatch_ptrace-Split-function-copy_regs.patch b/0040-kpatch_ptrace-Split-function-copy_regs.patch deleted file mode 100644 index 5884a748467d65e3a5b491566f3f4efbd7a75b20..0000000000000000000000000000000000000000 --- a/0040-kpatch_ptrace-Split-function-copy_regs.patch +++ /dev/null @@ -1,137 +0,0 @@ -From 8c0199836e7944569dbbeb5e571d791b8e466275 Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Mon, 12 Oct 2020 16:24:09 +0800 -Subject: [PATCH 40/89] kpatch_ptrace: Split function copy_regs - -The function copy_regs is arch related, so make two separate -definations in arch/x86/arch_ptrace.c and arch/aarch64/arch_ptrace.c - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/arch/aarch64/arch_ptrace.c | 28 ++++++++++++++++++++++++++++ - src/arch/x86/arch_ptrace.c | 22 ++++++++++++++++++++++ - src/include/kpatch_ptrace.h | 3 +++ - src/kpatch_ptrace.c | 22 ---------------------- - 4 files changed, 53 insertions(+), 22 deletions(-) - -diff --git a/src/arch/aarch64/arch_ptrace.c b/src/arch/aarch64/arch_ptrace.c -index fb19e86..0366d4f 100644 ---- a/src/arch/aarch64/arch_ptrace.c -+++ b/src/arch/aarch64/arch_ptrace.c -@@ -22,6 +22,34 @@ - - #include - -+void copy_regs(struct user_regs_struct *dst, -+ struct user_regs_struct *src) -+{ -+#define COPY_REG(x) dst->x = src->x -+ COPY_REG(regs[0]); -+ COPY_REG(regs[1]); -+ COPY_REG(regs[2]); -+ COPY_REG(regs[3]); -+ COPY_REG(regs[4]); -+ COPY_REG(regs[5]); -+ COPY_REG(regs[8]); -+ COPY_REG(regs[29]); -+ -+ COPY_REG(regs[9]); -+ COPY_REG(regs[10]); -+ COPY_REG(regs[11]); -+ COPY_REG(regs[12]); -+ COPY_REG(regs[13]); -+ COPY_REG(regs[14]); -+ COPY_REG(regs[15]); -+ COPY_REG(regs[16]); -+ COPY_REG(regs[17]); -+ COPY_REG(regs[18]); -+ COPY_REG(regs[19]); -+ COPY_REG(regs[20]); -+#undef COPY_REG -+} -+ - int - kpatch_arch_ptrace_waitpid(kpatch_process_t *proc, - struct timespec *timeout, -diff --git a/src/arch/x86/arch_ptrace.c b/src/arch/x86/arch_ptrace.c -index 6e943fd..fa23757 100644 ---- a/src/arch/x86/arch_ptrace.c -+++ b/src/arch/x86/arch_ptrace.c -@@ -22,6 +22,28 @@ - - #include - -+void copy_regs(struct user_regs_struct *dst, -+ struct user_regs_struct *src) -+{ -+#define COPY_REG(x) dst->x = src->x -+ COPY_REG(r15); -+ COPY_REG(r14); -+ COPY_REG(r13); -+ COPY_REG(r12); -+ COPY_REG(rbp); -+ COPY_REG(rbx); -+ COPY_REG(r11); -+ COPY_REG(r10); -+ COPY_REG(r9); -+ COPY_REG(r8); -+ COPY_REG(rax); -+ COPY_REG(rcx); -+ COPY_REG(rdx); -+ COPY_REG(rsi); -+ COPY_REG(rdi); -+#undef COPY_REG -+} -+ - int kpatch_arch_ptrace_waitpid(kpatch_process_t *proc, - struct timespec *timeout, - const sigset_t *sigset) -diff --git a/src/include/kpatch_ptrace.h b/src/include/kpatch_ptrace.h -index 1c7d33e..e434d68 100644 ---- a/src/include/kpatch_ptrace.h -+++ b/src/include/kpatch_ptrace.h -@@ -122,4 +122,7 @@ kpatch_arch_ptrace_waitpid(kpatch_process_t *proc, - struct timespec *timeout, - const sigset_t *sigset); - -+void copy_regs(struct user_regs_struct *dst, -+ struct user_regs_struct *src); -+ - #endif -diff --git a/src/kpatch_ptrace.c b/src/kpatch_ptrace.c -index 3c57288..180bbaa 100644 ---- a/src/kpatch_ptrace.c -+++ b/src/kpatch_ptrace.c -@@ -413,28 +413,6 @@ poke_back: - return ret; - } - --static void copy_regs(struct user_regs_struct *dst, -- struct user_regs_struct *src) --{ --#define COPY_REG(x) dst->x = src->x -- COPY_REG(r15); -- COPY_REG(r14); -- COPY_REG(r13); -- COPY_REG(r12); -- COPY_REG(rbp); -- COPY_REG(rbx); -- COPY_REG(r11); -- COPY_REG(r10); -- COPY_REG(r9); -- COPY_REG(r8); -- COPY_REG(rax); -- COPY_REG(rcx); -- COPY_REG(rdx); -- COPY_REG(rsi); -- COPY_REG(rdi); --#undef COPY_REG --} -- - static - int - kpatch_execute_remote_func(struct kpatch_ptrace_ctx *pctx, --- -2.23.0 - diff --git a/0041-kpatch_ptrace-Split-function-kpatch_execute_remote_f.patch b/0041-kpatch_ptrace-Split-function-kpatch_execute_remote_f.patch deleted file mode 100644 index ae1b197b67f604c99da479b3899f7bb8c2daf9c7..0000000000000000000000000000000000000000 --- a/0041-kpatch_ptrace-Split-function-kpatch_execute_remote_f.patch +++ /dev/null @@ -1,328 +0,0 @@ -From e312d7a74924d6e3880fa27adb4bcd04c8c25983 Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Mon, 12 Oct 2020 16:30:58 +0800 -Subject: [PATCH 41/89] kpatch_ptrace: Split function - kpatch_execute_remote_func - -The function kpatch_execute_remote_func is arch related, first -rename it with kpatch_arch_execute_remote_func, and the make separate -definations in arch/x86/arch_ptrace.c and arch/aarch64/arch_ptrace.c - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/arch/aarch64/arch_ptrace.c | 87 ++++++++++++++++++++++++++++++++++ - src/arch/x86/arch_ptrace.c | 79 ++++++++++++++++++++++++++++++ - src/include/kpatch_ptrace.h | 9 ++++ - src/kpatch_ptrace.c | 82 +------------------------------- - 4 files changed, 176 insertions(+), 81 deletions(-) - -diff --git a/src/arch/aarch64/arch_ptrace.c b/src/arch/aarch64/arch_ptrace.c -index 0366d4f..821b4e8 100644 ---- a/src/arch/aarch64/arch_ptrace.c -+++ b/src/arch/aarch64/arch_ptrace.c -@@ -22,6 +22,93 @@ - - #include - -+int -+kpatch_arch_execute_remote_func(struct kpatch_ptrace_ctx *pctx, -+ const unsigned char *code, -+ size_t codelen, -+ struct user_regs_struct *pregs, -+ int (*func)(struct kpatch_ptrace_ctx *pctx, -+ void *data), -+ void *data) -+{ -+ struct user_regs_struct orig_regs, regs; -+ struct iovec orig_regs_iov, regs_iov; -+ -+ orig_regs_iov.iov_base = &orig_regs; -+ orig_regs_iov.iov_len = sizeof(orig_regs); -+ regs_iov.iov_base = ®s; -+ regs_iov.iov_len = sizeof(regs); -+ -+ unsigned char orig_code[codelen]; -+ int ret; -+ kpatch_process_t *proc = pctx->proc; -+ unsigned long libc_base = proc->libc_base; -+ -+ -+ ret = ptrace(PTRACE_GETREGSET, pctx->pid, (void*)NT_PRSTATUS, (void*)&orig_regs_iov); -+ if (ret < 0) { -+ kplogerror("can't get regs - %d\n", pctx->pid); -+ return -1; -+ } -+ ret = kpatch_process_mem_read( -+ proc, -+ libc_base, -+ (unsigned long *)orig_code, -+ codelen); -+ if (ret < 0) { -+ kplogerror("can't peek original code - %d\n", pctx->pid); -+ return -1; -+ } -+ ret = kpatch_process_mem_write( -+ proc, -+ (unsigned long *)code, -+ libc_base, -+ codelen); -+ if (ret < 0) { -+ kplogerror("can't poke syscall code - %d\n", pctx->pid); -+ goto poke_back; -+ } -+ -+ regs = orig_regs; -+ regs.pc = libc_base; -+ -+ copy_regs(®s, pregs); -+ -+ ret = ptrace(PTRACE_SETREGSET, pctx->pid, (void*)NT_PRSTATUS, (void*)®s_iov); -+ if (ret < 0) { -+ kplogerror("can't set regs - %d\n", pctx->pid); -+ goto poke_back; -+ } -+ -+ ret = func(pctx, data); -+ if (ret < 0) { -+ kplogerror("failed call to func\n"); -+ goto poke_back; -+ } -+ -+ ret = ptrace(PTRACE_GETREGSET, pctx->pid, (void*)NT_PRSTATUS, (void*)®s_iov); -+ if (ret < 0) { -+ kplogerror("can't get updated regs - %d\n", pctx->pid); -+ goto poke_back; -+ } -+ -+ ret = ptrace(PTRACE_SETREGSET, pctx->pid, (void*)NT_PRSTATUS, (void*)&orig_regs_iov); -+ if (ret < 0) { -+ kplogerror("can't restore regs - %d\n", pctx->pid); -+ goto poke_back; -+ } -+ -+ *pregs = regs; -+ -+poke_back: -+ kpatch_process_mem_write( -+ proc, -+ (unsigned long *)orig_code, -+ libc_base, -+ codelen); -+ return ret; -+} -+ - void copy_regs(struct user_regs_struct *dst, - struct user_regs_struct *src) - { -diff --git a/src/arch/x86/arch_ptrace.c b/src/arch/x86/arch_ptrace.c -index fa23757..9239f52 100644 ---- a/src/arch/x86/arch_ptrace.c -+++ b/src/arch/x86/arch_ptrace.c -@@ -22,6 +22,85 @@ - - #include - -+int -+kpatch_arch_execute_remote_func(struct kpatch_ptrace_ctx *pctx, -+ const unsigned char *code, -+ size_t codelen, -+ struct user_regs_struct *pregs, -+ int (*func)(struct kpatch_ptrace_ctx *pctx, -+ void *data), -+ void *data) -+{ -+ struct user_regs_struct orig_regs, regs; -+ unsigned char orig_code[codelen]; -+ int ret; -+ kpatch_process_t *proc = pctx->proc; -+ unsigned long libc_base = proc->libc_base; -+ -+ ret = ptrace(PTRACE_GETREGS, pctx->pid, NULL, &orig_regs); -+ if (ret < 0) { -+ kplogerror("can't get regs - %d\n", pctx->pid); -+ return -1; -+ } -+ ret = kpatch_process_mem_read( -+ proc, -+ libc_base, -+ (unsigned long *)orig_code, -+ codelen); -+ if (ret < 0) { -+ kplogerror("can't peek original code - %d\n", pctx->pid); -+ return -1; -+ } -+ ret = kpatch_process_mem_write( -+ proc, -+ (unsigned long *)code, -+ libc_base, -+ codelen); -+ if (ret < 0) { -+ kplogerror("can't poke syscall code - %d\n", pctx->pid); -+ goto poke_back; -+ } -+ -+ regs = orig_regs; -+ regs.rip = libc_base; -+ -+ copy_regs(®s, pregs); -+ -+ ret = ptrace(PTRACE_SETREGS, pctx->pid, NULL, ®s); -+ if (ret < 0) { -+ kplogerror("can't set regs - %d\n", pctx->pid); -+ goto poke_back; -+ } -+ -+ ret = func(pctx, data); -+ if (ret < 0) { -+ kplogerror("failed call to func\n"); -+ goto poke_back; -+ } -+ -+ ret = ptrace(PTRACE_GETREGS, pctx->pid, NULL, ®s); -+ if (ret < 0) { -+ kplogerror("can't get updated regs - %d\n", pctx->pid); -+ goto poke_back; -+ } -+ -+ ret = ptrace(PTRACE_SETREGS, pctx->pid, NULL, &orig_regs); -+ if (ret < 0) { -+ kplogerror("can't restore regs - %d\n", pctx->pid); -+ goto poke_back; -+ } -+ -+ *pregs = regs; -+ -+poke_back: -+ kpatch_process_mem_write( -+ proc, -+ (unsigned long *)orig_code, -+ libc_base, -+ codelen); -+ return ret; -+} -+ - void copy_regs(struct user_regs_struct *dst, - struct user_regs_struct *src) - { -diff --git a/src/include/kpatch_ptrace.h b/src/include/kpatch_ptrace.h -index e434d68..f35aabd 100644 ---- a/src/include/kpatch_ptrace.h -+++ b/src/include/kpatch_ptrace.h -@@ -125,4 +125,13 @@ kpatch_arch_ptrace_waitpid(kpatch_process_t *proc, - void copy_regs(struct user_regs_struct *dst, - struct user_regs_struct *src); - -+int -+kpatch_arch_execute_remote_func(struct kpatch_ptrace_ctx *pctx, -+ const unsigned char *code, -+ size_t codelen, -+ struct user_regs_struct *pregs, -+ int (*func)(struct kpatch_ptrace_ctx *pctx, -+ void *data), -+ void *data); -+ - #endif -diff --git a/src/kpatch_ptrace.c b/src/kpatch_ptrace.c -index 180bbaa..9056815 100644 ---- a/src/kpatch_ptrace.c -+++ b/src/kpatch_ptrace.c -@@ -413,86 +413,6 @@ poke_back: - return ret; - } - --static --int --kpatch_execute_remote_func(struct kpatch_ptrace_ctx *pctx, -- const unsigned char *code, -- size_t codelen, -- struct user_regs_struct *pregs, -- int (*func)(struct kpatch_ptrace_ctx *pctx, -- void *data), -- void *data) --{ -- struct user_regs_struct orig_regs, regs; -- unsigned char orig_code[codelen]; -- int ret; -- kpatch_process_t *proc = pctx->proc; -- unsigned long libc_base = proc->libc_base; -- -- ret = ptrace(PTRACE_GETREGS, pctx->pid, NULL, &orig_regs); -- if (ret < 0) { -- kplogerror("can't get regs - %d\n", pctx->pid); -- return -1; -- } -- ret = kpatch_process_mem_read( -- proc, -- libc_base, -- (unsigned long *)orig_code, -- codelen); -- if (ret < 0) { -- kplogerror("can't peek original code - %d\n", pctx->pid); -- return -1; -- } -- ret = kpatch_process_mem_write( -- proc, -- (unsigned long *)code, -- libc_base, -- codelen); -- if (ret < 0) { -- kplogerror("can't poke syscall code - %d\n", pctx->pid); -- goto poke_back; -- } -- -- regs = orig_regs; -- regs.rip = libc_base; -- -- copy_regs(®s, pregs); -- -- ret = ptrace(PTRACE_SETREGS, pctx->pid, NULL, ®s); -- if (ret < 0) { -- kplogerror("can't set regs - %d\n", pctx->pid); -- goto poke_back; -- } -- -- ret = func(pctx, data); -- if (ret < 0) { -- kplogerror("failed call to func\n"); -- goto poke_back; -- } -- -- ret = ptrace(PTRACE_GETREGS, pctx->pid, NULL, ®s); -- if (ret < 0) { -- kplogerror("can't get updated regs - %d\n", pctx->pid); -- goto poke_back; -- } -- -- ret = ptrace(PTRACE_SETREGS, pctx->pid, NULL, &orig_regs); -- if (ret < 0) { -- kplogerror("can't restore regs - %d\n", pctx->pid); -- goto poke_back; -- } -- -- *pregs = regs; -- --poke_back: -- kpatch_process_mem_write( -- proc, -- (unsigned long *)orig_code, -- libc_base, -- codelen); -- return ret; --} -- - static int - wait_for_stop(struct kpatch_ptrace_ctx *pctx, - void *data) -@@ -592,7 +512,7 @@ kpatch_execute_remote(struct kpatch_ptrace_ctx *pctx, - size_t codelen, - struct user_regs_struct *pregs) - { -- return kpatch_execute_remote_func(pctx, -+ return kpatch_arch_execute_remote_func(pctx, - code, - codelen, - pregs, --- -2.23.0 - diff --git a/0042-kpatch_ptrace-Split-function-kpatch_ptrace_resolve_i.patch b/0042-kpatch_ptrace-Split-function-kpatch_ptrace_resolve_i.patch deleted file mode 100644 index d591baa7b7c4b5f537c47beee3e8ca5f500cb934..0000000000000000000000000000000000000000 --- a/0042-kpatch_ptrace-Split-function-kpatch_ptrace_resolve_i.patch +++ /dev/null @@ -1,146 +0,0 @@ -From aeeded44db6e705717bd24f3ffbbe878af47833b Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Mon, 12 Oct 2020 16:40:42 +0800 -Subject: [PATCH 42/89] kpatch_ptrace: Split function - kpatch_ptrace_resolve_ifunc - -The function kpatch_ptrace_resolve_ifunc is arch related, first -rename it with kpatch_arch_ptrace_resolve_ifunc, and then make -separate definations in arch/x86/arch_ptrace.c and arch/aarch64/arch_ptrace.c - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/arch/aarch64/arch_ptrace.c | 20 ++++++++++++++++++++ - src/arch/x86/arch_ptrace.c | 21 +++++++++++++++++++++ - src/include/kpatch_ptrace.h | 2 +- - src/kpatch_elf.c | 4 ++-- - src/kpatch_ptrace.c | 21 --------------------- - 5 files changed, 44 insertions(+), 24 deletions(-) - -diff --git a/src/arch/aarch64/arch_ptrace.c b/src/arch/aarch64/arch_ptrace.c -index 821b4e8..4dee0e5 100644 ---- a/src/arch/aarch64/arch_ptrace.c -+++ b/src/arch/aarch64/arch_ptrace.c -@@ -22,6 +22,26 @@ - - #include - -+int kpatch_arch_ptrace_resolve_ifunc(struct kpatch_ptrace_ctx *pctx, -+ unsigned long *addr) -+{ -+ struct user_regs_struct regs; -+ -+ unsigned char callrax[] = { -+ 0x00, 0x01, 0x3f, 0xd6, // blr x8 -+ 0xa0, 0x00, 0x20, 0xd4, // brk #5 -+ }; -+ int ret; -+ kpdebug("Executing callrax %lx (pid %d)\n", *addr, pctx->pid); -+ regs.regs[8] = *addr; -+ -+ ret = kpatch_execute_remote(pctx, callrax, sizeof(callrax), ®s); -+ if (ret == 0) -+ *addr = regs.regs[0]; -+ -+ return ret; -+} -+ - int - kpatch_arch_execute_remote_func(struct kpatch_ptrace_ctx *pctx, - const unsigned char *code, -diff --git a/src/arch/x86/arch_ptrace.c b/src/arch/x86/arch_ptrace.c -index 9239f52..3d49638 100644 ---- a/src/arch/x86/arch_ptrace.c -+++ b/src/arch/x86/arch_ptrace.c -@@ -22,6 +22,27 @@ - - #include - -+int kpatch_arch_ptrace_resolve_ifunc(struct kpatch_ptrace_ctx *pctx, -+ unsigned long *addr) -+{ -+ struct user_regs_struct regs; -+ -+ unsigned char callrax[] = { -+ 0xff, 0xd0, /* call *%rax */ -+ 0xcc, /* int3 */ -+ }; -+ int ret; -+ -+ kpdebug("Executing callrax %lx (pid %d)\n", *addr, pctx->pid); -+ regs.rax = *addr; -+ -+ ret = kpatch_execute_remote(pctx, callrax, sizeof(callrax), ®s); -+ if (ret == 0) -+ *addr = regs.rax; -+ -+ return ret; -+} -+ - int - kpatch_arch_execute_remote_func(struct kpatch_ptrace_ctx *pctx, - const unsigned char *code, -diff --git a/src/include/kpatch_ptrace.h b/src/include/kpatch_ptrace.h -index f35aabd..19a1b2c 100644 ---- a/src/include/kpatch_ptrace.h -+++ b/src/include/kpatch_ptrace.h -@@ -70,7 +70,7 @@ int kpatch_execute_remote(struct kpatch_ptrace_ctx *pctx, - size_t codelen, - struct user_regs_struct *pregs); - --int kpatch_ptrace_resolve_ifunc(struct kpatch_ptrace_ctx *pctx, -+int kpatch_arch_ptrace_resolve_ifunc(struct kpatch_ptrace_ctx *pctx, - unsigned long *addr); - unsigned long - kpatch_mmap_remote(struct kpatch_ptrace_ctx *pctx, -diff --git a/src/kpatch_elf.c b/src/kpatch_elf.c -index 5506292..d443001 100644 ---- a/src/kpatch_elf.c -+++ b/src/kpatch_elf.c -@@ -677,8 +677,8 @@ kpatch_resolve_undefined(struct object_file *obj, - addr = vaddr2addr(o, addr); - - if (type == STT_GNU_IFUNC) -- if (kpatch_ptrace_resolve_ifunc(proc2pctx(obj->proc), &addr) < 0) -- kpfatalerror("kpatch_ptrace_resolve_ifunc failed\n"); -+ if (kpatch_arch_ptrace_resolve_ifunc(proc2pctx(obj->proc), &addr) < 0) -+ kpfatalerror("kpatch_arch_ptrace_resolve_ifunc failed\n"); - - break; - } -diff --git a/src/kpatch_ptrace.c b/src/kpatch_ptrace.c -index 9056815..cd961e1 100644 ---- a/src/kpatch_ptrace.c -+++ b/src/kpatch_ptrace.c -@@ -672,27 +672,6 @@ static int kpatch_syscall_remote(struct kpatch_ptrace_ctx *pctx, int nr, - return ret; - } - --int kpatch_ptrace_resolve_ifunc(struct kpatch_ptrace_ctx *pctx, -- unsigned long *addr) --{ -- struct user_regs_struct regs; -- -- unsigned char callrax[] = { -- 0xff, 0xd0, /* call *%rax */ -- 0xcc, /* int3 */ -- }; -- int ret; -- -- kpdebug("Executing callrax %lx (pid %d)\n", *addr, pctx->pid); -- regs.rax = *addr; -- -- ret = kpatch_execute_remote(pctx, callrax, sizeof(callrax), ®s); -- if (ret == 0) -- *addr = regs.rax; -- -- return ret; --} -- - #define MAX_ERRNO 4095 - unsigned long - kpatch_mmap_remote(struct kpatch_ptrace_ctx *pctx, --- -2.23.0 - diff --git a/0043-kpatch_ptrace-Split-function-kpatch_arch_prctl_remot.patch b/0043-kpatch_ptrace-Split-function-kpatch_arch_prctl_remot.patch deleted file mode 100644 index 5a8e066a9b5ae9719e0ec395e80aabb5152450c3..0000000000000000000000000000000000000000 --- a/0043-kpatch_ptrace-Split-function-kpatch_arch_prctl_remot.patch +++ /dev/null @@ -1,213 +0,0 @@ -From aa39ba7326c13546f68b51d95bf55004437c3110 Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Mon, 12 Oct 2020 16:49:15 +0800 -Subject: [PATCH 43/89] kpatch_ptrace: Split function kpatch_arch_prctl_remote - -The function kpatch_arch_prctl_remote is arch related, let's make two -separate definations in arch/x86/arch_ptrace.c and arch/aarch64/arch_ptrace.c - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/arch/aarch64/arch_ptrace.c | 49 ++++++++++++++++++++++++++++++++++ - src/arch/x86/arch_ptrace.c | 45 +++++++++++++++++++++++++++++++ - src/include/kpatch_ptrace.h | 2 ++ - src/kpatch_ptrace.c | 46 ------------------------------- - 4 files changed, 96 insertions(+), 46 deletions(-) - -diff --git a/src/arch/aarch64/arch_ptrace.c b/src/arch/aarch64/arch_ptrace.c -index 4dee0e5..735927e 100644 ---- a/src/arch/aarch64/arch_ptrace.c -+++ b/src/arch/aarch64/arch_ptrace.c -@@ -22,6 +22,55 @@ - - #include - -+int kpatch_arch_prctl_remote(struct kpatch_ptrace_ctx *pctx, int code, unsigned long *addr) -+{ -+ struct user_regs_struct regs; -+ struct iovec regs_iov; -+ regs_iov.iov_base = ®s; -+ regs_iov.iov_len = sizeof(regs); -+ -+ unsigned long res, sp; -+ int ret; -+ -+ kpdebug("arch_prctl_remote: %d, %p\n", code, addr); -+ ret = ptrace(PTRACE_GETREGSET, pctx->pid, (void*)NT_PRSTATUS, (void*)®s_iov); -+ if (ret < 0) { -+ kpdebug("FAIL. Can't get regs - %s\n", strerror(errno)); -+ return -1; -+ } -+ ret = kpatch_process_mem_read(pctx->proc, -+ regs.sp, -+ &sp, -+ sizeof(sp)); -+ if (ret < 0) { -+ kplogerror("can't peek original stack data\n"); -+ return -1; -+ } -+ //ret = kpatch_syscall_remote(pctx, __NR_arch_prctl, code, regs.sp, 0, 0, 0, 0, &res); -+ if (ret < 0) -+ goto poke; -+ if (ret == 0 && res >= (unsigned long)-MAX_ERRNO) { -+ errno = -(long)res; -+ ret = -1; -+ goto poke; -+ } -+ ret = kpatch_process_mem_read(pctx->proc, -+ regs.sp, -+ &res, -+ sizeof(res)); -+ if (ret < 0) -+ kplogerror("can't peek new stack data\n"); -+ -+poke: -+ if (kpatch_process_mem_write(pctx->proc, -+ &sp, -+ regs.sp, -+ sizeof(sp))) -+ kplogerror("can't poke orig stack data\n"); -+ *addr = res; -+ return ret; -+} -+ - int kpatch_arch_ptrace_resolve_ifunc(struct kpatch_ptrace_ctx *pctx, - unsigned long *addr) - { -diff --git a/src/arch/x86/arch_ptrace.c b/src/arch/x86/arch_ptrace.c -index 3d49638..5f1e703 100644 ---- a/src/arch/x86/arch_ptrace.c -+++ b/src/arch/x86/arch_ptrace.c -@@ -22,6 +22,51 @@ - - #include - -+int kpatch_arch_prctl_remote(struct kpatch_ptrace_ctx *pctx, int code, unsigned long *addr) -+{ -+ struct user_regs_struct regs; -+ unsigned long res, rsp; -+ int ret; -+ -+ kpdebug("arch_prctl_remote: %d, %p\n", code, addr); -+ ret = ptrace(PTRACE_GETREGS, pctx->pid, NULL, ®s); -+ if (ret < 0) { -+ kpdebug("FAIL. Can't get regs - %s\n", strerror(errno)); -+ return -1; -+ } -+ ret = kpatch_process_mem_read(pctx->proc, -+ regs.rsp, -+ &rsp, -+ sizeof(rsp)); -+ if (ret < 0) { -+ kplogerror("can't peek original stack data\n"); -+ return -1; -+ } -+ ret = kpatch_syscall_remote(pctx, __NR_arch_prctl, code, regs.rsp, 0, 0, 0, 0, &res); -+ if (ret < 0) -+ goto poke; -+ if (ret == 0 && res >= (unsigned long)-MAX_ERRNO) { -+ errno = -(long)res; -+ ret = -1; -+ goto poke; -+ } -+ ret = kpatch_process_mem_read(pctx->proc, -+ regs.rsp, -+ &res, -+ sizeof(res)); -+ if (ret < 0) -+ kplogerror("can't peek new stack data\n"); -+ -+poke: -+ if (kpatch_process_mem_write(pctx->proc, -+ &rsp, -+ regs.rsp, -+ sizeof(rsp))) -+ kplogerror("can't poke orig stack data\n"); -+ *addr = res; -+ return ret; -+} -+ - int kpatch_arch_ptrace_resolve_ifunc(struct kpatch_ptrace_ctx *pctx, - unsigned long *addr) - { -diff --git a/src/include/kpatch_ptrace.h b/src/include/kpatch_ptrace.h -index 19a1b2c..ddaa9e6 100644 ---- a/src/include/kpatch_ptrace.h -+++ b/src/include/kpatch_ptrace.h -@@ -84,6 +84,8 @@ int - kpatch_munmap_remote(struct kpatch_ptrace_ctx *pctx, - unsigned long addr, - size_t length); -+ -+#define MAX_ERRNO 4095 - int kpatch_arch_prctl_remote(struct kpatch_ptrace_ctx *pctx, int code, unsigned long *addr); - - int -diff --git a/src/kpatch_ptrace.c b/src/kpatch_ptrace.c -index cd961e1..4d2223e 100644 ---- a/src/kpatch_ptrace.c -+++ b/src/kpatch_ptrace.c -@@ -672,7 +672,6 @@ static int kpatch_syscall_remote(struct kpatch_ptrace_ctx *pctx, int nr, - return ret; - } - --#define MAX_ERRNO 4095 - unsigned long - kpatch_mmap_remote(struct kpatch_ptrace_ctx *pctx, - unsigned long addr, -@@ -717,51 +716,6 @@ int kpatch_munmap_remote(struct kpatch_ptrace_ctx *pctx, - return 0; - } - --int kpatch_arch_prctl_remote(struct kpatch_ptrace_ctx *pctx, int code, unsigned long *addr) --{ -- struct user_regs_struct regs; -- unsigned long res, rsp; -- int ret; -- -- kpdebug("arch_prctl_remote: %d, %p\n", code, addr); -- ret = ptrace(PTRACE_GETREGS, pctx->pid, NULL, ®s); -- if (ret < 0) { -- kpdebug("FAIL. Can't get regs - %s\n", strerror(errno)); -- return -1; -- } -- ret = kpatch_process_mem_read(pctx->proc, -- regs.rsp, -- &rsp, -- sizeof(rsp)); -- if (ret < 0) { -- kplogerror("can't peek original stack data\n"); -- return -1; -- } -- ret = kpatch_syscall_remote(pctx, __NR_arch_prctl, code, regs.rsp, 0, 0, 0, 0, &res); -- if (ret < 0) -- goto poke; -- if (ret == 0 && res >= (unsigned long)-MAX_ERRNO) { -- errno = -(long)res; -- ret = -1; -- goto poke; -- } -- ret = kpatch_process_mem_read(pctx->proc, -- regs.rsp, -- &res, -- sizeof(res)); -- if (ret < 0) -- kplogerror("can't peek new stack data\n"); -- --poke: -- if (kpatch_process_mem_write(pctx->proc, -- &rsp, -- regs.rsp, -- sizeof(rsp))) -- kplogerror("can't poke orig stack data\n"); -- *addr = res; -- return ret; --} -- - int - kpatch_remote_write(struct kpatch_ptrace_ctx *pctx, - unsigned long dst, --- -2.23.0 - diff --git a/0044-kpatch_ptrace-Split-function-kpatch_syscall_remote.patch b/0044-kpatch_ptrace-Split-function-kpatch_syscall_remote.patch deleted file mode 100644 index fe64105211394da3722ec30af46d4cf394111ca4..0000000000000000000000000000000000000000 --- a/0044-kpatch_ptrace-Split-function-kpatch_syscall_remote.patch +++ /dev/null @@ -1,191 +0,0 @@ -From 335b90a54e629e0dc2f954ec2c3bd0b7e149aeec Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Mon, 12 Oct 2020 16:55:27 +0800 -Subject: [PATCH 44/89] kpatch_ptrace: Split function kpatch_syscall_remote - -The function kpatch_syscall_remote is arch related, first -rename it with kpatch_arch_syscall_remote, and then make -separate definations in arch/x86/arch_ptrace.c and arch/aarch64/arch_ptrace.c - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/arch/aarch64/arch_ptrace.c | 31 ++++++++++++++++++++++++++++++- - src/arch/x86/arch_ptrace.c | 31 ++++++++++++++++++++++++++++++- - src/include/kpatch_ptrace.h | 5 +++++ - src/kpatch_ptrace.c | 33 ++------------------------------- - 4 files changed, 67 insertions(+), 33 deletions(-) - -diff --git a/src/arch/aarch64/arch_ptrace.c b/src/arch/aarch64/arch_ptrace.c -index 735927e..a444285 100644 ---- a/src/arch/aarch64/arch_ptrace.c -+++ b/src/arch/aarch64/arch_ptrace.c -@@ -22,6 +22,35 @@ - - #include - -+int kpatch_arch_syscall_remote(struct kpatch_ptrace_ctx *pctx, int nr, -+ unsigned long arg1, unsigned long arg2, unsigned long arg3, -+ unsigned long arg4, unsigned long arg5, unsigned long arg6, -+ unsigned long *res) -+{ -+ struct user_regs_struct regs; -+ -+ unsigned char syscall[] = { -+ 0x01, 0x00, 0x00, 0xd4, //0xd4000001 svc #0 = syscall -+ 0xa0, 0x00, 0x20, 0xd4, //0xd42000a0 brk #5 = int3 -+ }; -+ int ret; -+ -+ kpdebug("Executing syscall %d (pid %d)...\n", nr, pctx->pid); -+ regs.regs[8] = (unsigned long)nr; -+ regs.regs[0] = arg1; -+ regs.regs[1] = arg2; -+ regs.regs[2] = arg3; -+ regs.regs[3] = arg4; -+ regs.regs[4] = arg5; -+ regs.regs[5] = arg6; -+ -+ ret = kpatch_execute_remote(pctx, syscall, sizeof(syscall), ®s); -+ if (ret == 0) -+ *res = regs.regs[0]; -+ -+ return ret; -+} -+ - int kpatch_arch_prctl_remote(struct kpatch_ptrace_ctx *pctx, int code, unsigned long *addr) - { - struct user_regs_struct regs; -@@ -46,7 +75,7 @@ int kpatch_arch_prctl_remote(struct kpatch_ptrace_ctx *pctx, int code, unsigned - kplogerror("can't peek original stack data\n"); - return -1; - } -- //ret = kpatch_syscall_remote(pctx, __NR_arch_prctl, code, regs.sp, 0, 0, 0, 0, &res); -+ //ret = kpatch_arch_syscall_remote(pctx, __NR_arch_prctl, code, regs.sp, 0, 0, 0, 0, &res); - if (ret < 0) - goto poke; - if (ret == 0 && res >= (unsigned long)-MAX_ERRNO) { -diff --git a/src/arch/x86/arch_ptrace.c b/src/arch/x86/arch_ptrace.c -index 5f1e703..10127a3 100644 ---- a/src/arch/x86/arch_ptrace.c -+++ b/src/arch/x86/arch_ptrace.c -@@ -22,6 +22,35 @@ - - #include - -+int kpatch_arch_syscall_remote(struct kpatch_ptrace_ctx *pctx, int nr, -+ unsigned long arg1, unsigned long arg2, unsigned long arg3, -+ unsigned long arg4, unsigned long arg5, unsigned long arg6, -+ unsigned long *res) -+{ -+ struct user_regs_struct regs; -+ -+ unsigned char syscall[] = { -+ 0x0f, 0x05, /* syscall */ -+ 0xcc, /* int3 */ -+ }; -+ int ret; -+ -+ kpdebug("Executing syscall %d (pid %d)...\n", nr, pctx->pid); -+ regs.rax = (unsigned long)nr; -+ regs.rdi = arg1; -+ regs.rsi = arg2; -+ regs.rdx = arg3; -+ regs.r10 = arg4; -+ regs.r8 = arg5; -+ regs.r9 = arg6; -+ -+ ret = kpatch_execute_remote(pctx, syscall, sizeof(syscall), ®s); -+ if (ret == 0) -+ *res = regs.rax; -+ -+ return ret; -+} -+ - int kpatch_arch_prctl_remote(struct kpatch_ptrace_ctx *pctx, int code, unsigned long *addr) - { - struct user_regs_struct regs; -@@ -42,7 +71,7 @@ int kpatch_arch_prctl_remote(struct kpatch_ptrace_ctx *pctx, int code, unsigned - kplogerror("can't peek original stack data\n"); - return -1; - } -- ret = kpatch_syscall_remote(pctx, __NR_arch_prctl, code, regs.rsp, 0, 0, 0, 0, &res); -+ ret = kpatch_arch_syscall_remote(pctx, __NR_arch_prctl, code, regs.rsp, 0, 0, 0, 0, &res); - if (ret < 0) - goto poke; - if (ret == 0 && res >= (unsigned long)-MAX_ERRNO) { -diff --git a/src/include/kpatch_ptrace.h b/src/include/kpatch_ptrace.h -index ddaa9e6..c8cfd41 100644 ---- a/src/include/kpatch_ptrace.h -+++ b/src/include/kpatch_ptrace.h -@@ -136,4 +136,9 @@ kpatch_arch_execute_remote_func(struct kpatch_ptrace_ctx *pctx, - void *data), - void *data); - -+int kpatch_arch_syscall_remote(struct kpatch_ptrace_ctx *pctx, int nr, -+ unsigned long arg1, unsigned long arg2, unsigned long arg3, -+ unsigned long arg4, unsigned long arg5, unsigned long arg6, -+ unsigned long *res); -+ - #endif -diff --git a/src/kpatch_ptrace.c b/src/kpatch_ptrace.c -index 4d2223e..057b08a 100644 ---- a/src/kpatch_ptrace.c -+++ b/src/kpatch_ptrace.c -@@ -643,35 +643,6 @@ kpatch_ptrace_kickstart_execve_wrapper(kpatch_process_t *proc) - return 0; - } - --static int kpatch_syscall_remote(struct kpatch_ptrace_ctx *pctx, int nr, -- unsigned long arg1, unsigned long arg2, unsigned long arg3, -- unsigned long arg4, unsigned long arg5, unsigned long arg6, -- unsigned long *res) --{ -- struct user_regs_struct regs; -- -- unsigned char syscall[] = { -- 0x0f, 0x05, /* syscall */ -- 0xcc, /* int3 */ -- }; -- int ret; -- -- kpdebug("Executing syscall %d (pid %d)...\n", nr, pctx->pid); -- regs.rax = (unsigned long)nr; -- regs.rdi = arg1; -- regs.rsi = arg2; -- regs.rdx = arg3; -- regs.r10 = arg4; -- regs.r8 = arg5; -- regs.r9 = arg6; -- -- ret = kpatch_execute_remote(pctx, syscall, sizeof(syscall), ®s); -- if (ret == 0) -- *res = regs.rax; -- -- return ret; --} -- - unsigned long - kpatch_mmap_remote(struct kpatch_ptrace_ctx *pctx, - unsigned long addr, -@@ -686,7 +657,7 @@ kpatch_mmap_remote(struct kpatch_ptrace_ctx *pctx, - - kpdebug("mmap_remote: 0x%lx+%lx, %x, %x, %d, %lx\n", addr, length, - prot, flags, fd, offset); -- ret = kpatch_syscall_remote(pctx, __NR_mmap, (unsigned long)addr, -+ ret = kpatch_arch_syscall_remote(pctx, __NR_mmap, (unsigned long)addr, - length, prot, flags, fd, offset, &res); - if (ret < 0) - return 0; -@@ -705,7 +676,7 @@ int kpatch_munmap_remote(struct kpatch_ptrace_ctx *pctx, - unsigned long res; - - kpdebug("munmap_remote: 0x%lx+%lx\n", addr, length); -- ret = kpatch_syscall_remote(pctx, __NR_munmap, (unsigned long)addr, -+ ret = kpatch_arch_syscall_remote(pctx, __NR_munmap, (unsigned long)addr, - length, 0, 0, 0, 0, &res); - if (ret < 0) - return -1; --- -2.23.0 - diff --git a/0045-kpatch_ptrace-Split-function-wait_for_mmap.patch b/0045-kpatch_ptrace-Split-function-wait_for_mmap.patch deleted file mode 100644 index 9556e2701b795f577c233ed7a32baf2f76f87368..0000000000000000000000000000000000000000 --- a/0045-kpatch_ptrace-Split-function-wait_for_mmap.patch +++ /dev/null @@ -1,239 +0,0 @@ -From 05b64620354b8f8bd36c3f782eff9cd145f57fea Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Tue, 13 Oct 2020 11:10:11 +0800 -Subject: [PATCH 45/89] kpatch_ptrace: Split function wait_for_mmap - -The function wait_for_mmap is arch related, so make two separate -definations in arch/x86/arch_ptrace.c and arch/aarch64/arch_ptrace.c - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/arch/aarch64/arch_ptrace.c | 58 ++++++++++++++++++++++++++++++++++ - src/arch/x86/arch_ptrace.c | 58 ++++++++++++++++++++++++++++++++++ - src/include/kpatch_ptrace.h | 3 ++ - src/kpatch_ptrace.c | 58 ---------------------------------- - 4 files changed, 119 insertions(+), 58 deletions(-) - -diff --git a/src/arch/aarch64/arch_ptrace.c b/src/arch/aarch64/arch_ptrace.c -index a444285..b21189e 100644 ---- a/src/arch/aarch64/arch_ptrace.c -+++ b/src/arch/aarch64/arch_ptrace.c -@@ -22,6 +22,64 @@ - - #include - -+int -+wait_for_mmap(struct kpatch_ptrace_ctx *pctx, -+ unsigned long *pbase) -+{ -+ int ret, status = 0, insyscall = 0; -+ long rv; -+ -+ while (1) { -+ ret = ptrace(PTRACE_SYSCALL, pctx->pid, NULL, -+ (void *)(uintptr_t)status); -+ if (ret < 0) { -+ kplogerror("can't PTRACE_SYSCALL tracee - %d\n", -+ pctx->pid); -+ return -1; -+ } -+ -+ ret = waitpid(pctx->pid, &status, __WALL); -+ if (ret < 0) { -+ kplogerror("can't wait tracee - %d\n", pctx->pid); -+ return -1; -+ } -+ -+ if (WIFEXITED(status)) { -+ status = WTERMSIG(status); -+ continue; -+ } else if (!WIFSTOPPED(status)) { -+ status = 0; -+ continue; -+ } -+ -+ status = 0; -+ -+ if (insyscall == 0) { -+ rv = ptrace(PTRACE_PEEKUSER, pctx->pid, -+ offsetof(struct user_regs_struct, -+ regs[29]), -+ NULL); -+ if (rv == -1) { -+ kplogerror("ptrace(PTRACE_PEEKUSER)\n"); -+ return -1; -+ } -+ insyscall = rv; -+ continue; -+ } else if (insyscall == __NR_mmap) { -+ rv = ptrace(PTRACE_PEEKUSER, pctx->pid, -+ offsetof(struct user_regs_struct, -+ regs[8]), -+ NULL); -+ *pbase = rv; -+ break; -+ } -+ -+ insyscall = !insyscall; -+ } -+ -+ return 0; -+} -+ - int kpatch_arch_syscall_remote(struct kpatch_ptrace_ctx *pctx, int nr, - unsigned long arg1, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5, unsigned long arg6, -diff --git a/src/arch/x86/arch_ptrace.c b/src/arch/x86/arch_ptrace.c -index 10127a3..0032cbd 100644 ---- a/src/arch/x86/arch_ptrace.c -+++ b/src/arch/x86/arch_ptrace.c -@@ -22,6 +22,64 @@ - - #include - -+int -+wait_for_mmap(struct kpatch_ptrace_ctx *pctx, -+ unsigned long *pbase) -+{ -+ int ret, status = 0, insyscall = 0; -+ long rv; -+ -+ while (1) { -+ ret = ptrace(PTRACE_SYSCALL, pctx->pid, NULL, -+ (void *)(uintptr_t)status); -+ if (ret < 0) { -+ kplogerror("can't PTRACE_SYSCALL tracee - %d\n", -+ pctx->pid); -+ return -1; -+ } -+ -+ ret = waitpid(pctx->pid, &status, __WALL); -+ if (ret < 0) { -+ kplogerror("can't wait tracee - %d\n", pctx->pid); -+ return -1; -+ } -+ -+ if (WIFEXITED(status)) { -+ status = WTERMSIG(status); -+ continue; -+ } else if (!WIFSTOPPED(status)) { -+ status = 0; -+ continue; -+ } -+ -+ status = 0; -+ -+ if (insyscall == 0) { -+ rv = ptrace(PTRACE_PEEKUSER, pctx->pid, -+ offsetof(struct user_regs_struct, -+ orig_rax), -+ NULL); -+ if (rv == -1) { -+ kplogerror("ptrace(PTRACE_PEEKUSER)\n"); -+ return -1; -+ } -+ insyscall = rv; -+ continue; -+ } else if (insyscall == __NR_mmap) { -+ rv = ptrace(PTRACE_PEEKUSER, pctx->pid, -+ offsetof(struct user_regs_struct, -+ rax), -+ NULL); -+ *pbase = rv; -+ break; -+ } -+ -+ insyscall = !insyscall; -+ } -+ -+ return 0; -+} -+ - int kpatch_arch_syscall_remote(struct kpatch_ptrace_ctx *pctx, int nr, - unsigned long arg1, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5, unsigned long arg6, -diff --git a/src/include/kpatch_ptrace.h b/src/include/kpatch_ptrace.h -index c8cfd41..5abcf26 100644 ---- a/src/include/kpatch_ptrace.h -+++ b/src/include/kpatch_ptrace.h -@@ -141,4 +141,7 @@ int kpatch_arch_syscall_remote(struct kpatch_ptrace_ctx *pctx, int nr, - unsigned long arg4, unsigned long arg5, unsigned long arg6, - unsigned long *res); - -+int wait_for_mmap(struct kpatch_ptrace_ctx *pctx, -+ unsigned long *pbase); -+ - #endif -diff --git a/src/kpatch_ptrace.c b/src/kpatch_ptrace.c -index 057b08a..7ab550c 100644 ---- a/src/kpatch_ptrace.c -+++ b/src/kpatch_ptrace.c -@@ -448,64 +448,6 @@ wait_for_stop(struct kpatch_ptrace_ctx *pctx, - return 0; - } - --static int --wait_for_mmap(struct kpatch_ptrace_ctx *pctx, -- unsigned long *pbase) --{ -- int ret, status = 0, insyscall = 0; -- long rv; -- -- while (1) { -- ret = ptrace(PTRACE_SYSCALL, pctx->pid, NULL, -- (void *)(uintptr_t)status); -- if (ret < 0) { -- kplogerror("can't PTRACE_SYSCALL tracee - %d\n", -- pctx->pid); -- return -1; -- } -- -- ret = waitpid(pctx->pid, &status, __WALL); -- if (ret < 0) { -- kplogerror("can't wait tracee - %d\n", pctx->pid); -- return -1; -- } -- -- if (WIFEXITED(status)) { -- status = WTERMSIG(status); -- continue; -- } else if (!WIFSTOPPED(status)) { -- status = 0; -- continue; -- } -- -- status = 0; -- -- if (insyscall == 0) { -- rv = ptrace(PTRACE_PEEKUSER, pctx->pid, -- offsetof(struct user_regs_struct, -- orig_rax), -- NULL); -- if (rv == -1) { -- kplogerror("ptrace(PTRACE_PEEKUSER)\n"); -- return -1; -- } -- insyscall = rv; -- continue; -- } else if (insyscall == __NR_mmap) { -- rv = ptrace(PTRACE_PEEKUSER, pctx->pid, -- offsetof(struct user_regs_struct, -- rax), -- NULL); -- *pbase = rv; -- break; -- } -- -- insyscall = !insyscall; -- } -- -- return 0; --} -- - int - kpatch_execute_remote(struct kpatch_ptrace_ctx *pctx, - const unsigned char *code, --- -2.23.0 - diff --git a/0046-kpatch_ptrace-Split-function-kpatch_ptrace_kickstart.patch b/0046-kpatch_ptrace-Split-function-kpatch_ptrace_kickstart.patch deleted file mode 100644 index e8aef2a0bbb830ecc256ee2010bad1b40aac308d..0000000000000000000000000000000000000000 --- a/0046-kpatch_ptrace-Split-function-kpatch_ptrace_kickstart.patch +++ /dev/null @@ -1,401 +0,0 @@ -From f53cbbe63cbe16b2b0eb0466b5c85ea35f68da2b Mon Sep 17 00:00:00 2001 -From: Jiajie Li -Date: Tue, 13 Oct 2020 11:22:27 +0800 -Subject: [PATCH 46/89] kpatch_ptrace: Split function - kpatch_ptrace_kickstart_execve_wrapper - -The function kpatch_ptrace_kickstart_execve_wrapper is arch related, -first rename it with kpatch_arch_ptrace_kickstart_execve_wrapper, -and then make separate definations in arch/x86/arch_ptrace.c and -arch/aarch64/arch_ptrace.c - -Signed-off-by: Jiajie Li -Signed-off-by: Ying Fang ---- - src/arch/aarch64/arch_ptrace.c | 99 +++++++++++++++++++++++++++++++ - src/arch/x86/arch_ptrace.c | 99 +++++++++++++++++++++++++++++++ - src/include/kpatch_ptrace.h | 5 +- - src/kpatch_process.c | 2 +- - src/kpatch_ptrace.c | 103 +-------------------------------- - 5 files changed, 205 insertions(+), 103 deletions(-) - -diff --git a/src/arch/aarch64/arch_ptrace.c b/src/arch/aarch64/arch_ptrace.c -index b21189e..9f87d10 100644 ---- a/src/arch/aarch64/arch_ptrace.c -+++ b/src/arch/aarch64/arch_ptrace.c -@@ -22,6 +22,105 @@ - - #include - -+/** -+ * This is rather tricky since we are accounting for the non-main -+ * thread calling for execve(). See `ptrace(2)` for details. -+ * -+ * FIXME(pboldin): this is broken for multi-threaded calls -+ * to execve. Sight. -+ */ -+int -+kpatch_arch_ptrace_kickstart_execve_wrapper(kpatch_process_t *proc) -+{ -+ int ret, pid = 0; -+ struct kpatch_ptrace_ctx *pctx, *ptmp, *execve_pctx = NULL; -+ long rv; -+ -+ kpdebug("kpatch_arch_ptrace_kickstart_execve_wrapper\n"); -+ -+ list_for_each_entry(pctx, &proc->ptrace.pctxs, list) { -+ /* proc->pid equals to THREAD ID of the thread -+ * executing execve.so's version of execve -+ */ -+ if (pctx->pid != proc->pid) -+ continue; -+ execve_pctx = pctx; -+ break; -+ } -+ -+ if (execve_pctx == NULL) { -+ kperr("can't find thread executing execve"); -+ return -1; -+ } -+ -+ /* Send a message to our `execve` wrapper so it will continue -+ * execution -+ */ -+ ret = send(proc->send_fd, &ret, sizeof(ret), 0); -+ if (ret < 0) { -+ kplogerror("send failed\n"); -+ return ret; -+ } -+ -+ /* Wait for it to reach BRKN instruction just before real execve */ -+ while (1) { -+ ret = wait_for_stop(execve_pctx, NULL); -+ if (ret < 0) { -+ kplogerror("wait_for_stop\n"); -+ return ret; -+ } -+ -+ rv = ptrace(PTRACE_PEEKUSER, execve_pctx->pid, -+ offsetof(struct user_regs_struct, pc), -+ NULL); -+ if (rv == -1) -+ return rv; -+ -+ rv = ptrace(PTRACE_PEEKTEXT, execve_pctx->pid, -+ rv - 1, NULL); -+ if (rv == -1) -+ return rv; -+ if ((unsigned char)rv == 0xcc) -+ break; -+ } -+ -+ /* Wait for SIGTRAP from the execve. It happens from the thread -+ * group ID, so find it if thread doing execve() is not it. */ -+ if (execve_pctx != proc2pctx(proc)) { -+ pid = get_threadgroup_id(proc->pid); -+ if (pid < 0) -+ return -1; -+ -+ proc->pid = pid; -+ } -+ -+ ret = wait_for_stop(execve_pctx, (void *)(uintptr_t)pid); -+ if (ret < 0) { -+ kplogerror("waitpid\n"); -+ return ret; -+ } -+ -+ list_for_each_entry_safe(pctx, ptmp, &proc->ptrace.pctxs, list) { -+ if (pctx->pid == proc->pid) -+ continue; -+ kpatch_ptrace_detach(pctx); -+ kpatch_ptrace_ctx_destroy(pctx); -+ } -+ -+ /* Suddenly, /proc/pid/mem gets invalidated */ -+ { -+ char buf[128]; -+ close(proc->memfd); -+ -+ snprintf(buf, sizeof(buf), "/proc/%d/mem", proc->pid); -+ proc->memfd = open(buf, O_RDWR); -+ } -+ -+ kpdebug("...done\n"); -+ -+ return 0; -+} -+ - int - wait_for_mmap(struct kpatch_ptrace_ctx *pctx, - unsigned long *pbase) -diff --git a/src/arch/x86/arch_ptrace.c b/src/arch/x86/arch_ptrace.c -index 0032cbd..ef0f460 100644 ---- a/src/arch/x86/arch_ptrace.c -+++ b/src/arch/x86/arch_ptrace.c -@@ -22,6 +22,105 @@ - - #include - -+/** -+ * This is rather tricky since we are accounting for the non-main -+ * thread calling for execve(). See `ptrace(2)` for details. -+ * -+ * FIXME(pboldin): this is broken for multi-threaded calls -+ * to execve. Sight. -+ */ -+int -+kpatch_arch_ptrace_kickstart_execve_wrapper(kpatch_process_t *proc) -+{ -+ int ret, pid = 0; -+ struct kpatch_ptrace_ctx *pctx, *ptmp, *execve_pctx = NULL; -+ long rv; -+ -+ kpdebug("kpatch_arch_ptrace_kickstart_execve_wrapper\n"); -+ -+ list_for_each_entry(pctx, &proc->ptrace.pctxs, list) { -+ /* proc->pid equals to THREAD ID of the thread -+ * executing execve.so's version of execve -+ */ -+ if (pctx->pid != proc->pid) -+ continue; -+ execve_pctx = pctx; -+ break; -+ } -+ -+ if (execve_pctx == NULL) { -+ kperr("can't find thread executing execve"); -+ return -1; -+ } -+ -+ /* Send a message to our `execve` wrapper so it will continue -+ * execution -+ */ -+ ret = send(proc->send_fd, &ret, sizeof(ret), 0); -+ if (ret < 0) { -+ kplogerror("send failed\n"); -+ return ret; -+ } -+ -+ /* Wait for it to reach BRKN instruction just before real execve */ -+ while (1) { -+ ret = wait_for_stop(execve_pctx, NULL); -+ if (ret < 0) { -+ kplogerror("wait_for_stop\n"); -+ return ret; -+ } -+ -+ rv = ptrace(PTRACE_PEEKUSER, execve_pctx->pid, -+ offsetof(struct user_regs_struct, rip), -+ NULL); -+ if (rv == -1) -+ return rv; -+ -+ rv = ptrace(PTRACE_PEEKTEXT, execve_pctx->pid, -+ rv - 1, NULL); -+ if (rv == -1) -+ return rv; -+ if ((unsigned char)rv == 0xcc) -+ break; -+ } -+ -+ /* Wait for SIGTRAP from the execve. It happens from the thread -+ * group ID, so find it if thread doing execve() is not it. */ -+ if (execve_pctx != proc2pctx(proc)) { -+ pid = get_threadgroup_id(proc->pid); -+ if (pid < 0) -+ return -1; -+ -+ proc->pid = pid; -+ } -+ -+ ret = wait_for_stop(execve_pctx, (void *)(uintptr_t)pid); -+ if (ret < 0) { -+ kplogerror("waitpid\n"); -+ return ret; -+ } -+ -+ list_for_each_entry_safe(pctx, ptmp, &proc->ptrace.pctxs, list) { -+ if (pctx->pid == proc->pid) -+ continue; -+ kpatch_ptrace_detach(pctx); -+ kpatch_ptrace_ctx_destroy(pctx); -+ } -+ -+ /* Suddenly, /proc/pid/mem gets invalidated */ -+ { -+ char buf[128]; -+ close(proc->memfd); -+ -+ snprintf(buf, sizeof(buf), "/proc/%d/mem", proc->pid); -+ proc->memfd = open(buf, O_RDWR); -+ } -+ -+ kpdebug("...done\n"); -+ -+ return 0; -+} -+ - int - wait_for_mmap(struct kpatch_ptrace_ctx *pctx, - unsigned long *pbase) -diff --git a/src/include/kpatch_ptrace.h b/src/include/kpatch_ptrace.h -index 5abcf26..f0e83c0 100644 ---- a/src/include/kpatch_ptrace.h -+++ b/src/include/kpatch_ptrace.h -@@ -55,7 +55,10 @@ int kpatch_ptrace_detach(struct kpatch_ptrace_ctx *pctx); - int kpatch_ptrace_handle_ld_linux(kpatch_process_t *proc, - unsigned long *pentry_point); - --int kpatch_ptrace_kickstart_execve_wrapper(kpatch_process_t *proc); -+ -+int wait_for_stop(struct kpatch_ptrace_ctx *pctx, void *data); -+int get_threadgroup_id(int tid); -+int kpatch_arch_ptrace_kickstart_execve_wrapper(kpatch_process_t *proc); - int kpatch_ptrace_get_entry_point(struct kpatch_ptrace_ctx *pctx, - unsigned long *pentry_point); - -diff --git a/src/kpatch_process.c b/src/kpatch_process.c -index 9561962..f987b7e 100644 ---- a/src/kpatch_process.c -+++ b/src/kpatch_process.c -@@ -856,7 +856,7 @@ kpatch_process_kickstart_execve_wrapper(kpatch_process_t *proc) - { - int ret; - -- ret = kpatch_ptrace_kickstart_execve_wrapper(proc); -+ ret = kpatch_arch_ptrace_kickstart_execve_wrapper(proc); - if (ret < 0) - return -1; - -diff --git a/src/kpatch_ptrace.c b/src/kpatch_ptrace.c -index 7ab550c..d0bfbdd 100644 ---- a/src/kpatch_ptrace.c -+++ b/src/kpatch_ptrace.c -@@ -413,7 +413,7 @@ poke_back: - return ret; - } - --static int -+int - wait_for_stop(struct kpatch_ptrace_ctx *pctx, - void *data) - { -@@ -463,7 +463,7 @@ kpatch_execute_remote(struct kpatch_ptrace_ctx *pctx, - } - - /* FIXME(pboldin) buf might be too small */ --static int -+int - get_threadgroup_id(int tid) - { - FILE *fh; -@@ -486,105 +486,6 @@ get_threadgroup_id(int tid) - return pid; - } - --/** -- * This is rather tricky since we are accounting for the non-main -- * thread calling for execve(). See `ptrace(2)` for details. -- * -- * FIXME(pboldin): this is broken for multi-threaded calls -- * to execve. Sight. -- */ --int --kpatch_ptrace_kickstart_execve_wrapper(kpatch_process_t *proc) --{ -- int ret, pid = 0; -- struct kpatch_ptrace_ctx *pctx, *ptmp, *execve_pctx = NULL; -- long rv; -- -- kpdebug("kpatch_ptrace_kickstart_execve_wrapper\n"); -- -- list_for_each_entry(pctx, &proc->ptrace.pctxs, list) { -- /* proc->pid equals to THREAD ID of the thread -- * executing execve.so's version of execve -- */ -- if (pctx->pid != proc->pid) -- continue; -- execve_pctx = pctx; -- break; -- } -- -- if (execve_pctx == NULL) { -- kperr("can't find thread executing execve"); -- return -1; -- } -- -- /* Send a message to our `execve` wrapper so it will continue -- * execution -- */ -- ret = send(proc->send_fd, &ret, sizeof(ret), 0); -- if (ret < 0) { -- kplogerror("send failed\n"); -- return ret; -- } -- -- /* Wait for it to reach BRKN instruction just before real execve */ -- while (1) { -- ret = wait_for_stop(execve_pctx, NULL); -- if (ret < 0) { -- kplogerror("wait_for_stop\n"); -- return ret; -- } -- -- rv = ptrace(PTRACE_PEEKUSER, execve_pctx->pid, -- offsetof(struct user_regs_struct, rip), -- NULL); -- if (rv == -1) -- return rv; -- -- rv = ptrace(PTRACE_PEEKTEXT, execve_pctx->pid, -- rv - 1, NULL); -- if (rv == -1) -- return rv; -- if ((unsigned char)rv == 0xcc) -- break; -- } -- -- /* Wait for SIGTRAP from the execve. It happens from the thread -- * group ID, so find it if thread doing execve() is not it. */ -- if (execve_pctx != proc2pctx(proc)) { -- pid = get_threadgroup_id(proc->pid); -- if (pid < 0) -- return -1; -- -- proc->pid = pid; -- } -- -- ret = wait_for_stop(execve_pctx, (void *)(uintptr_t)pid); -- if (ret < 0) { -- kplogerror("waitpid\n"); -- return ret; -- } -- -- list_for_each_entry_safe(pctx, ptmp, &proc->ptrace.pctxs, list) { -- if (pctx->pid == proc->pid) -- continue; -- kpatch_ptrace_detach(pctx); -- kpatch_ptrace_ctx_destroy(pctx); -- } -- -- /* Suddenly, /proc/pid/mem gets invalidated */ -- { -- char buf[128]; -- close(proc->memfd); -- -- snprintf(buf, sizeof(buf), "/proc/%d/mem", proc->pid); -- proc->memfd = open(buf, O_RDWR); -- } -- -- kpdebug("...done\n"); -- -- return 0; --} -- - unsigned long - kpatch_mmap_remote(struct kpatch_ptrace_ctx *pctx, - unsigned long addr, --- -2.23.0 - diff --git a/0047-Allow-init_t-create-lnk-file.patch b/0047-Allow-init_t-create-lnk-file.patch deleted file mode 100644 index b6b40bbeac24c2164c234c1be16fd8ed5b823d8e..0000000000000000000000000000000000000000 --- a/0047-Allow-init_t-create-lnk-file.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 7782210333c3296b68f954b46284024701ec79e4 Mon Sep 17 00:00:00 2001 -From: imxcc -Date: Wed, 8 Sep 2021 11:28:28 +0800 -Subject: [PATCH] Allow init_t create lnk file - -Bugfix: When the selinux mode is enforcing, libcare.socket cannot -create symlink libcare.sock. This will cause the libcare.service -to fail to start. - -Signed-off-by: imxcc ---- - dist/selinux/libcare.te | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/dist/selinux/libcare.te b/dist/selinux/libcare.te -index c240875..936fc34 100644 ---- a/dist/selinux/libcare.te -+++ b/dist/selinux/libcare.te -@@ -49,6 +49,8 @@ allow libcare_t libcare_file_t: file exec_file_perms; - allow libcare_t libcare_file_t: dir list_dir_perms; - allow libcare_t libcare_file_t: lnk_file read_lnk_file_perms; - -+allow init_t var_run_t:lnk_file create; -+ - # to read patient's /proc entries and be able to attach to it - allow libcare_t self: capability { dac_override dac_read_search sys_ptrace }; - --- -2.27.0 - diff --git a/README.en.md b/README.en.md index db9fc30cf180ba7366a66a69cc7fcd7e0c234a71..3077b91a3591986ac8052af185ffb15dc90a117b 100644 --- a/README.en.md +++ b/README.en.md @@ -1,40 +1,35 @@ -# libcareplus +# LibcarePlus #### Description -LibcarePlus delivers live patches to any of your Linux executables or libraries at the runtime, without the need for restart of your applications. +LibcarePlus‧is‧a‧general‧user-mode‧live‧patch‧framework.‧It delivers live patches to any of your Linux executables or libraries at the runtime, without the need for restart of your applications. -LibcarePlus is a self maintained branch derived from the LibCare project. It is released with the same LICENSE with LibCare and the original Copyright is kept. +LibcarePlus is a self-maintained branch derived from the LibCare project. It is released with the same license with LibCare and the original copyright is kept. More information about LibCare can be reached at: [https://github.com/cloudlinux/libcare](https://github.com/cloudlinux/libcare) -LibcarePlus aims at providing userspac livepatch ability -for popular architecture like x86_64 and aarch64. +LibcarePlus aims at providing user-mode live patches for popular architectures like x86_64 and AArch64. #### Software Architecture -For more information about the design of LibcarePlus, -please refer to the `LibcarePlus Design`. +For more information about the design of LibcarePlus, see the `LibcarePlus Design`. #### Installation -Please refer to the `LibcarePlus Intallation Guide` to -complete the installation of LibcarePlus. +Refer to the `LibcarePlus Intallation Guide` to install LibcarePlus. -### User Guide +#### User Guide -Please refer to: +Refer to: * LibcarePlus Patch Make Tutorial * LibcarePlus Patch Apply Tutorial -to help you to make the patch and apply it to the target process. +to help you make the patch and apply it to the target process. #### Contribution -Any contributors are wellcome to join this project, -we are glad to provide help and guide needed. -Developers can post an issue on this project and -make a pull request to join the development process. \ No newline at end of file +Any contributors are welcome to join this project, and we are glad to provide help and guidance needed. +Developers can post an issue on this project and submit a pull request to join the development process. \ No newline at end of file diff --git a/libcareplus-0.1.4.tar.gz b/libcareplus-0.1.4.tar.gz deleted file mode 100644 index b2dcc2663804de8ddfe9da3157bbb2f8758b9e22..0000000000000000000000000000000000000000 Binary files a/libcareplus-0.1.4.tar.gz and /dev/null differ diff --git a/libcareplus-1.0.0.tar.gz b/libcareplus-1.0.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..02691fe22ce031cba7f9f5d6ed70d453dcea023d Binary files /dev/null and b/libcareplus-1.0.0.tar.gz differ diff --git a/libcareplus.spec b/libcareplus.spec index 8e334e101ae4b57a438542b747e39743276a622b..ce3b1e6031adf689065f269d8efecf5f06798a9e 100644 --- a/libcareplus.spec +++ b/libcareplus.spec @@ -1,62 +1,14 @@ %define with_selinux 1 -Version: 0.1.4 +Version: 1.0.0 Name: libcareplus Summary: LibcarePlus tools -Release: 7 +Release: 0 Group: Applications/System License: GPLv2 Url: https://gitee.com/openeuler/libcareplus Source0: %{name}-%{version}.tar.gz -Patch0001: src-Makefile-install-kpatch_gensrc-into-bindir.patch -Patch0002: 0001-Split-kpatch_storage.c-from-kpatch_user.c.patch -Patch0003: 0002-Split-kpatch_patch.c-from-kpatch_user.c.patch -Patch0004: 0003-cmd_patch-pass-arguments-directly.patch -Patch0005: 0004-travis-use-VM-for-now.patch -Patch0006: 0005-scripts-pkgbuild-add-prepare_env-hook.patch -Patch0007: 0006-pkgbuild-fix-for-non-root-rpmbuild-built-root.patch -Patch0008: 0007-Toil-package-builder.patch -Patch0009: 0008-pkgbuild-use-yumdownloader-if-source-url-is-missing.patch -Patch0010: 0009-execve-abort-on-failure.patch -Patch0011: 0010-Add-test-stage-to-pkgbuild.patch -Patch0012: 0011-glibc-minimal-readme-for-toil-builder.patch -Patch0013: 0012-Fix-kpatch_process_init-kpatch_coroutines_free.patch -Patch0014: 0013-Add-libcare-stresstest.patch -Patch0015: 0014-read-auxv-from-proc-pid-auxv.patch -Patch0016: 0015-add-fail-to-unpatch-test.patch -Patch0017: 0016-Waitpid-for-finished-threads-after-detach.patch -Patch0018: 0017-.gitignore-build-artefacts.patch -Patch0019: 0018-kpatch_storage-put-an-end-to-description-string-load.patch -Patch0020: 0019-Fix-README-files.patch -Patch0021: 0020-include-Create-include-directory-for-header-files.patch -Patch0022: 0021-src-Update-header-file-position.patch -Patch0023: 0022-arch-Create-arch-directory-to-support-multi-arch.patch -Patch0024: 0023-config-configure-out-the-running-arch.patch -Patch0025: 0024-Makefile-Adapt-Makefile-for-different-architectures.patch -Patch0026: 0025-kpatch_parse-Update-asm_directives-for-aarch64.patch -Patch0027: 0026-kpatch_parse-Split-function-parse_ctype.patch -Patch0028: 0027-kpatch_parse-Split-function-init_multilines.patch -Patch0029: 0028-kpatch_parse-Split-function-is_variable_start.patch -Patch0030: 0029-kpatch_parse-Split-function-is_data_def.patch -Patch0031: 0030-kpatch_parse-Split-function-is_function_start.patch -Patch0032: 0031-kpatch_common.h-Factor-out-PAGE_SIZE-marco.patch -Patch0033: 0032-kpatch_coro-Split-function-_UCORO_access_reg.patch -Patch0034: 0033-kpatch_coro-Split-function-get_ptr_guard.patch -Patch0035: 0034-kpatch_coro-Split-function-locate_start_context_symb.patch -Patch0036: 0035-kpatch_patch-Split-function-patch_apply_hunk.patch -Patch0037: 0036-kpatch_elf-Split-function-kpatch_add_jmp_entry.patch -Patch0038: 0037-kpatch_elf-Split-function-kpatch_apply_relocate_add.patch -Patch0039: 0038-kpatch_process-Split-function-object_find_patch_regi.patch -Patch0040: 0039-kpatch_ptrace-Split-function-kpatch_ptrace_waitpid.patch -Patch0041: 0040-kpatch_ptrace-Split-function-copy_regs.patch -Patch0042: 0041-kpatch_ptrace-Split-function-kpatch_execute_remote_f.patch -Patch0043: 0042-kpatch_ptrace-Split-function-kpatch_ptrace_resolve_i.patch -Patch0044: 0043-kpatch_ptrace-Split-function-kpatch_arch_prctl_remot.patch -Patch0045: 0044-kpatch_ptrace-Split-function-kpatch_syscall_remote.patch -Patch0046: 0045-kpatch_ptrace-Split-function-wait_for_mmap.patch -Patch0047: 0046-kpatch_ptrace-Split-function-kpatch_ptrace_kickstart.patch -Patch0048: 0047-Allow-init_t-create-lnk-file.patch BuildRequires: elfutils-libelf-devel libunwind-devel gcc systemd @@ -159,6 +111,7 @@ rm -rf $RPM_BUILD_ROOT %defattr(-,root,root) %{_bindir}/libcare-ctl %{_bindir}/libcare-client +%{_bindir}/libcare-server %{_unitdir}/libcare.service %{_unitdir}/libcare.socket %{_presetdir}/90-libcare.preset @@ -167,6 +120,7 @@ rm -rf $RPM_BUILD_ROOT %defattr(-,root,root) %{_bindir}/libcare-cc %{_bindir}/libcare-patch-make +%{_bindir}/libcare-dump %{_bindir}/kpatch_gensrc %{_bindir}/kpatch_strip %{_bindir}/kpatch_make @@ -212,6 +166,47 @@ exit 0 %endif %changelog +* Mon Feb 07 2022 imxcc - 1.0.0.0 +- package init 1.0.0 + +* Mon Feb 07 2022 imxcc - 0.1.4.15 +- kpatch_user: init pid in cmd_info_user +* Mon Feb 07 2022 imxcc - 0.1.4.14 +- some bugfix +- support aarch64 UT +- fix memory RWX problem + +* Mon Feb 07 2022 imxcc - 0.1.4.13 +- add libcare-dump tool +- support test sets running on x86 +- some bugfixs + +* Mon Feb 07 2022 imxcc - 0.1.4.12 +- src/Makefile: execute config scripts before building +- kpatch_gensrc.c: support ignoring functions which we don't need +- arch/aarch64/arch_parse: modify is_variable_start for arm asm +- libcare-ctl: implement applied patch list +- libcare-ctl: introduce patch-id +- arch/aarch64/arch_elf: Add LDR and B instruction relocation +- arch/aarch64/arch_parse: improve VAR_CBLOCK start indentify +- tls: add support for TLS symbol with IE model +- arch64/arch_elf: add R_AARCH64_LDST32_ABS_LO12_NC relocation type for aarch64 +- process: fix region start calculation +- aarch64/arch_elf: Add ldr and ldrb relocation for aarch6 + +* Mon Feb 07 2022 imxcc - 0.1.4.11 +- kpatch_cc: support gcc -MQ option +- libcare-cc: add gcc iquote option support + +* Mon Feb 07 2022 imxcc - 0.1.4.10 +- kpatch_user.c: fix gcc warning + +* Mon Feb 07 2022 imxcc - 0.1.4.9 +- libcare-patch-make: add `-j|--jobs` option + +* Mon Feb 07 2022 imxcc - 0.1.4.8 +- updated the README.en.md file + * Wed Sep 08 2021 imxcc - 0.1.4.7 - selinux: Allow init_t create lnk file diff --git a/src-Makefile-install-kpatch_gensrc-into-bindir.patch b/src-Makefile-install-kpatch_gensrc-into-bindir.patch deleted file mode 100644 index 6f31adbb23def57988ff86cc11425fe0fd6f2c75..0000000000000000000000000000000000000000 --- a/src-Makefile-install-kpatch_gensrc-into-bindir.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 9221bb4ccd3f448fde2923df4598df17488978a9 Mon Sep 17 00:00:00 2001 -From: Ying Fang -Date: Tue, 8 Dec 2020 15:18:19 +0800 -Subject: [PATCH] src/Makefile: install kpatch_gensrc into bindir - -Signed-off-by: Ying Fang ---- - src/Makefile | 8 +++----- - 1 file changed, 3 insertions(+), 5 deletions(-) - -diff --git a/src/Makefile b/src/Makefile -index 72ec073..22eb623 100644 ---- a/src/Makefile -+++ b/src/Makefile -@@ -98,10 +98,8 @@ install: all - $(INSTALL) -m 0755 libcare-client $(DESTDIR)/$(bindir)/libcare-client - $(INSTALL) -m 0755 libcare-cc $(DESTDIR)/$(bindir)/libcare-cc - $(INSTALL) -m 0755 libcare-patch-make $(DESTDIR)/$(bindir)/libcare-patch-make -- -- $(INSTALL) -d $(DESTDIR)/$(libexecdir)/libcare -- $(INSTALL) -m 0755 kpatch_gensrc $(DESTDIR)/$(libexecdir)/libcare/kpatch_gensrc -- $(INSTALL) -m 0755 kpatch_make $(DESTDIR)/$(libexecdir)/libcare/kpatch_make -- $(INSTALL) -m 0755 kpatch_strip $(DESTDIR)/$(libexecdir)/libcare/kpatch_strip -+ $(INSTALL) -m 0755 kpatch_gensrc $(DESTDIR)/$(bindir)/kpatch_gensrc -+ $(INSTALL) -m 0755 kpatch_make $(DESTDIR)/$(bindir)/kpatch_make -+ $(INSTALL) -m 0755 kpatch_strip $(DESTDIR)/$(bindir)/kpatch_strip - - .PHONY: all clean test tests tests-gensrc tests-strip --- -2.25.4 -