From d0bd28247e41b9cec11d61f0d1b6a86f78a4dabd Mon Sep 17 00:00:00 2001 From: ningyu <405888464@qq.com> Date: Fri, 9 Aug 2024 14:33:01 +0800 Subject: [PATCH] upatch-manage: fix find upatch region bug Signed-off-by: ningyu <405888464@qq.com> --- upatch-manage/arch/aarch64/process.h | 28 --------- upatch-manage/arch/x86_64/process.h | 28 --------- upatch-manage/upatch-patch.c | 2 +- upatch-manage/upatch-process.c | 91 ++++++---------------------- upatch-manage/upatch-process.h | 6 +- 5 files changed, 23 insertions(+), 132 deletions(-) delete mode 100644 upatch-manage/arch/aarch64/process.h delete mode 100644 upatch-manage/arch/x86_64/process.h diff --git a/upatch-manage/arch/aarch64/process.h b/upatch-manage/arch/aarch64/process.h deleted file mode 100644 index 8acf04b..0000000 --- a/upatch-manage/arch/aarch64/process.h +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * upatch-manage - * Copyright (C) 2024 Huawei Technologies Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef __PROCESS__ -#define __PROCESS__ - -#ifndef MAX_DISTANCE -#define MAX_DISTANCE 0x8000000 -#endif - -#endif \ No newline at end of file diff --git a/upatch-manage/arch/x86_64/process.h b/upatch-manage/arch/x86_64/process.h deleted file mode 100644 index 5de8fc3..0000000 --- a/upatch-manage/arch/x86_64/process.h +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * upatch-manage - * Copyright (C) 2024 Huawei Technologies Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef __PROCESS__ -#define __PROCESS__ - -#ifndef MAX_DISTANCE -#define MAX_DISTANCE 0x80000000 -#endif - -#endif \ No newline at end of file diff --git a/upatch-manage/upatch-patch.c b/upatch-manage/upatch-patch.c index 8a1ad41..c9fcbc9 100644 --- a/upatch-manage/upatch-patch.c +++ b/upatch-manage/upatch-patch.c @@ -271,7 +271,7 @@ static void *upatch_alloc(struct object_file *obj, size_t sz) unsigned long addr; struct vm_hole *hole = NULL; - addr = object_find_patch_region_nolimit(obj, sz, &hole); + addr = object_find_patch_region(obj, sz, &hole); if (!addr) return NULL; diff --git a/upatch-manage/upatch-process.c b/upatch-manage/upatch-process.c index 84ec030..f4033cb 100644 --- a/upatch-manage/upatch-process.c +++ b/upatch-manage/upatch-process.c @@ -33,7 +33,6 @@ #include "list.h" #include "log.h" -#include "process.h" #include "upatch-common.h" #include "upatch-elf.h" #include "upatch-process.h" @@ -804,8 +803,9 @@ int vm_hole_split(struct vm_hole *hole, unsigned long alloc_start, * 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. + * Due to relocation constraints, the hole position should be whin 4GB range + * from the obj. + * eg: R_AARCH64_ADR_GOT_PAGE */ unsigned long object_find_patch_region(struct object_file *obj, size_t memsize, struct vm_hole **hole) @@ -813,96 +813,41 @@ unsigned long object_find_patch_region(struct object_file *obj, size_t memsize, struct list_head *head = &obj->proc->vmaholes; struct vm_hole *left_hole = obj->previous_hole; struct vm_hole *right_hole = next_hole(left_hole, head); - unsigned long max_distance = MAX_DISTANCE; + unsigned long region_start = 0; struct obj_vm_area *sovma; - unsigned long obj_start, obj_end; - unsigned long region_start = 0, region_end = 0; - - log_debug("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 = (obj_end - left_hole->start) <= - 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) { - log_error("Cannot find suitable region for patch '%s'\n", obj->name); - return -1UL; - } - - region_start = (region_start >> (unsigned long)PAGE_SHIFT) << (unsigned long)PAGE_SHIFT; - log_debug("Found patch region for '%s' at 0x%lx\n", obj->name, - region_start); - - return region_start; -} -unsigned long object_find_patch_region_nolimit(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; - struct vm_hole *right_hole = next_hole(left_hole, head); - unsigned long region_start = 0; - log_debug("Looking for patch region for '%s'...\n", obj->name); - while (right_hole != NULL) { + while (right_hole != NULL || left_hole != NULL) { if (hole_size(right_hole) > memsize) { *hole = right_hole; + region_start = right_hole->start; + if (region_start + memsize - obj_start > MAX_DISTANCE) { + continue; + } goto found; - } else - right_hole = next_hole(right_hole, head); - - while (left_hole != NULL) + } if (hole_size(left_hole) > memsize) { *hole = left_hole; + region_start = left_hole->end - memsize; + if (obj_end - region_start > MAX_DISTANCE) { + continue; + } goto found; - } else - left_hole = prev_hole(left_hole, head); + } + right_hole = next_hole(right_hole, head); + left_hole = prev_hole(left_hole, head); } - log_error("Cannot find suitable region for patch '%s'\n", obj->name); return -1UL; found: - region_start = ((*hole)->start >> PAGE_SHIFT) << PAGE_SHIFT; + region_start = (region_start >> PAGE_SHIFT) << PAGE_SHIFT; log_debug("Found patch region for '%s' 0xat %lx\n", obj->name, region_start); diff --git a/upatch-manage/upatch-process.h b/upatch-manage/upatch-process.h index be44cb5..fdbd752 100644 --- a/upatch-manage/upatch-process.h +++ b/upatch-manage/upatch-process.h @@ -33,6 +33,10 @@ #define ELFMAG "\177ELF" #define SELFMAG 4 +#ifndef MAX_DISTANCE +#define MAX_DISTANCE (1UL << 32) +#endif + enum { MEM_READ, MEM_WRITE, @@ -143,7 +147,5 @@ int vm_hole_split(struct vm_hole *, unsigned long, unsigned long); unsigned long object_find_patch_region(struct object_file *, size_t, struct vm_hole **); -unsigned long object_find_patch_region_nolimit(struct object_file *, size_t, - struct vm_hole **); #endif -- 2.34.1