Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libpulp for openSUSE:Factory checked in at 2025-02-25 16:47:59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libpulp (Old) and /work/SRC/openSUSE:Factory/.libpulp.new.1873 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libpulp" Tue Feb 25 16:47:59 2025 rev:8 rq:1248355 version:0.3.11 Changes: -------- --- /work/SRC/openSUSE:Factory/libpulp/libpulp.changes 2025-02-11 21:25:37.404729212 +0100 +++ /work/SRC/openSUSE:Factory/.libpulp.new.1873/libpulp.changes 2025-02-25 16:48:07.984278715 +0100 @@ -1,0 +2,8 @@ +Tue Feb 25 12:20:15 UTC 2025 - Giuliano Belinassi <[email protected]> + +- Update package with libpulp-0.3.11: + - Detect whenever the process was loaded in a custom starting address. + - ulp_stack now allocates multiples of page size. + - Fix livepatching of `malloc` in ppc64le (jsc#PED-11850). + +------------------------------------------------------------------- Old: ---- libpulp-0.3.10.tar.gz New: ---- libpulp-0.3.11.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libpulp.spec ++++++ --- /var/tmp/diff_new_pack.Sr9Mci/_old 2025-02-25 16:48:08.592304127 +0100 +++ /var/tmp/diff_new_pack.Sr9Mci/_new 2025-02-25 16:48:08.592304127 +0100 @@ -17,7 +17,7 @@ Name: libpulp -Version: 0.3.10 +Version: 0.3.11 Release: 0 Summary: Userspace live patching library and tools License: LGPL-2.1-or-later ++++++ libpulp-0.3.10.tar.gz -> libpulp-0.3.11.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libpulp-0.3.10/configure new/libpulp-0.3.11/configure --- old/libpulp-0.3.10/configure 2025-02-10 21:30:36.000000000 +0100 +++ new/libpulp-0.3.11/configure 2025-02-25 13:12:18.000000000 +0100 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.72 for libpulp 0.3.10. +# Generated by GNU Autoconf 2.72 for libpulp 0.3.11. # # Report bugs to <[email protected]>. # @@ -614,8 +614,8 @@ # Identity of this package. PACKAGE_NAME='libpulp' PACKAGE_TARNAME='libpulp' -PACKAGE_VERSION='0.3.10' -PACKAGE_STRING='libpulp 0.3.10' +PACKAGE_VERSION='0.3.11' +PACKAGE_STRING='libpulp 0.3.11' PACKAGE_BUGREPORT='[email protected]' PACKAGE_URL='' @@ -1420,7 +1420,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -'configure' configures libpulp 0.3.10 to adapt to many kinds of systems. +'configure' configures libpulp 0.3.11 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1492,7 +1492,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of libpulp 0.3.10:";; + short | recursive ) echo "Configuration of libpulp 0.3.11:";; esac cat <<\_ACEOF @@ -1628,7 +1628,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -libpulp configure 0.3.10 +libpulp configure 0.3.11 generated by GNU Autoconf 2.72 Copyright (C) 2023 Free Software Foundation, Inc. @@ -1979,7 +1979,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by libpulp $as_me 0.3.10, which was +It was created by libpulp $as_me 0.3.11, which was generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw @@ -3823,7 +3823,7 @@ # Define the identity of the package. PACKAGE='libpulp' - VERSION='0.3.10' + VERSION='0.3.11' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h @@ -20219,7 +20219,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by libpulp $as_me 0.3.10, which was +This file was extended by libpulp $as_me 0.3.11, which was generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -20287,7 +20287,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -libpulp config.status 0.3.10 +libpulp config.status 0.3.11 configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libpulp-0.3.10/configure.ac new/libpulp-0.3.11/configure.ac --- old/libpulp-0.3.10/configure.ac 2025-02-10 21:24:43.000000000 +0100 +++ new/libpulp-0.3.11/configure.ac 2025-02-25 01:45:32.000000000 +0100 @@ -1,6 +1,6 @@ # libpulp - User-space Livepatching Library # -# Copyright (C) 2020-2024 SUSE Software Solutions GmbH +# Copyright (C) 2020-2025 SUSE Software Solutions GmbH # # This file is part of libpulp. # @@ -17,7 +17,7 @@ # You should have received a copy of the GNU General Public License # along with libpulp. If not, see <http://www.gnu.org/licenses/>. -AC_INIT([libpulp],[0.3.10],[[email protected]]) +AC_INIT([libpulp],[0.3.11],[[email protected]]) # Keep most generated files under the config directory. AC_CONFIG_AUX_DIR([config]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libpulp-0.3.10/include/arch/powerpc64le/arch_common.h new/libpulp-0.3.11/include/arch/powerpc64le/arch_common.h --- old/libpulp-0.3.10/include/arch/powerpc64le/arch_common.h 2025-01-30 21:56:54.000000000 +0100 +++ new/libpulp-0.3.11/include/arch/powerpc64le/arch_common.h 2025-02-25 01:45:18.000000000 +0100 @@ -4,9 +4,6 @@ /** Offset of TLS pointer. */ #define TLS_DTV_OFFSET 0x8000 -/* Program load bias, which can be recovered by running `ld --verbose`. */ -#define EXECUTABLE_START 0x10000000UL - /* The Red zone. */ #define RED_ZONE_LEN 512 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libpulp-0.3.10/include/arch/x86_64/arch_common.h new/libpulp-0.3.11/include/arch/x86_64/arch_common.h --- old/libpulp-0.3.10/include/arch/x86_64/arch_common.h 2024-10-17 21:20:16.000000000 +0200 +++ new/libpulp-0.3.11/include/arch/x86_64/arch_common.h 2025-02-25 01:45:18.000000000 +0100 @@ -22,9 +22,6 @@ /** Set the GLOBAL ENTRYPOINT REGISTER, which in x86_64 doesn't exist. */ #define SET_GLOBAL_ENTRYPOINT_REG(reg, val) -/** Program load bias, which can be recovered by running `ld --verbose`. */ -#define EXECUTABLE_START 0x400000UL - /** The red zone. */ #define RED_ZONE_LEN 128 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libpulp-0.3.10/lib/arch/powerpc64le/patch.c new/libpulp-0.3.11/lib/arch/powerpc64le/patch.c --- old/libpulp-0.3.10/lib/arch/powerpc64le/patch.c 2025-01-30 21:56:54.000000000 +0100 +++ new/libpulp-0.3.11/lib/arch/powerpc64le/patch.c 2025-02-25 01:45:18.000000000 +0100 @@ -256,17 +256,18 @@ caller), so just assert it here. */ libpulp_assert(ulp_stack[ULP_STACK_REAL_SIZE] <= ulp_stack[ULP_STACK_USED_SIZE]); + /* NOTE: be careful with the functions we call here. If we call a certain + function here, then we may have problems livepatching it. */ + /* Storage depleted, allocate a new stack. */ unsigned long old_size = ulp_stack[ULP_STACK_REAL_SIZE]; - /* Setup new size. */ - ulp_stack[ULP_STACK_REAL_SIZE] += 32; + /* Setup new stack size. Increase by PAGESIZE to be optimal */ + ulp_stack[ULP_STACK_REAL_SIZE] += sysconf(_SC_PAGESIZE); ulp_stack[ULP_STACK_REAL_SIZE] *= 2; void *old = (void *)ulp_stack[ULP_STACK_PTR]; - DEBUG("thread %lu: expanding stack to %lu bytes", pthread_self(), ulp_stack[ULP_STACK_REAL_SIZE]); - /* Allocate buffer for our stack. */ void *new = mmap(NULL, ulp_stack[ULP_STACK_REAL_SIZE], PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); @@ -280,7 +281,17 @@ /* In case we have a previous allocated buffer, then copy this. */ if (old != NULL) { - memcpy(new, old, old_size); + + /* We can't use memcpy here, hence do our thing. */ + unsigned char *restrict oldp = old; + unsigned char *restrict newp = new; + unsigned long s = old_size; + + while (s > 0) { + *newp++ = *oldp++; + s--; + } + munmap(old, old_size); old = NULL; } @@ -288,6 +299,8 @@ ulp_stack[ULP_STACK_PTR] = (unsigned long) new; libpulp_assert(ulp_stack[ULP_STACK_PTR] != 0L); + DEBUG("thread %lu: expanded stack to %lu bytes", pthread_self(), ulp_stack[ULP_STACK_REAL_SIZE]); + /* Setup destructor for mmap memory, so we don't leak memory when a thread is destroyed. */ pthread_once(&ulp_once_control, ulp_pthread_key_init); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libpulp-0.3.10/tests/notes.py new/libpulp-0.3.11/tests/notes.py --- old/libpulp-0.3.10/tests/notes.py 2025-02-10 22:51:59.000000000 +0100 +++ new/libpulp-0.3.11/tests/notes.py 2025-02-25 01:45:18.000000000 +0100 @@ -22,11 +22,6 @@ import testsuite import platform -if platform.processor() == 'ppc64le': - # Skip this test on ppc64le, as for some reason the build id of the - # main process is not found by libpulp. - exit(77) - child = testsuite.spawn('notes') child.expect('Ready.') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libpulp-0.3.10/tools/introspection.c new/libpulp-0.3.11/tools/introspection.c --- old/libpulp-0.3.10/tools/introspection.c 2025-02-05 21:01:07.000000000 +0100 +++ new/libpulp-0.3.11/tools/introspection.c 2025-02-25 01:45:18.000000000 +0100 @@ -517,6 +517,74 @@ } #endif // ENABLE_DLINFO_CACHE + +/** @brief Parsers /proc/pid/maps to figure the EHDR mapping of dynamic object. + * + * This function reads the /proc/pid/maps to find the EHDR mapping of the + * dynamic object. Usually this can be found by looking at the link_map.l_addr + * field, however for the main process this information is not available there. + * + * @param p process to analyze. + * @param obj Object representing a library, or the main program itself, from p. + * + * @return 0 on success, anything else on failure. + */ +ElfW(Addr) +get_ehdr_addr(struct ulp_process *p, struct ulp_dynobj *obj) +{ + if (obj->link_map.l_addr) { + return obj->link_map.l_addr; + } + + const char *format_str = "/proc/%d/maps"; + char filename[strlen(format_str) + 10]; + sprintf(filename, format_str, p->pid); + + FILE *maps = fopen(filename, "r"); + if (maps == NULL) { + DEBUG("error: unable to open maps."); + return 0; + } + + char *line = NULL; + size_t len = 0; + ssize_t n; + + while ((n = getline(&line, &len, maps)) != -1) { + const char *str_addr1 = strtok(line, "-"); + /* clang-format off */ + + /* const char *str_addr2 = */ strtok(NULL, " "); + /* const char *str_perm = */ strtok(NULL, " "); + /* const char *str_offset = */ strtok(NULL, " "); + /* const char *str_dev = */ strtok(NULL, " "); + /* const char *str_inode = */ strtok(NULL, " "); + const char *str_path = strtok(NULL, " "); + + /* clang-format on */ + + /* Get the basename (last string after all /) and remove the newline there + if it exists. */ + char *bin_name = (char *) get_basename(str_path); + unsigned bin_len = strlen(bin_name); + if (bin_name[bin_len-1] == '\n') { + bin_name[bin_len-1] = '\0'; + } + + if (strcmp(bin_name, p->dynobj_main->filename) == 0) { + ElfW(Addr) addr1 = strtoul(str_addr1, NULL, 16); + fclose(maps); + FREE_AND_NULLIFY(line); + return addr1; + } + } + + fclose(maps); + FREE_AND_NULLIFY(line); + + return 0UL; +} + /** @brief Parses ELF headers of dynobj `obj` from process with pid `pid`. * * This function read the remote process memory to locate the following @@ -533,8 +601,12 @@ * @return 0 on success, anything else on failure. */ int -parse_dynobj_elf_headers(int pid, struct ulp_dynobj *obj) +parse_dynobj_elf_headers(struct ulp_process *p, struct ulp_dynobj *obj) { + pid_t pid = p->pid; + + ElfW(Addr) l_addr = 0; + ElfW(Addr) ehdr_addr = 0; ElfW(Ehdr) ehdr; ElfW(Addr) phdr_addr = 0; @@ -559,18 +631,10 @@ return ENOLINKMAP; } - /* l_addr holds the pointer to the ELF header. */ - ehdr_addr = obj->link_map.l_addr; + l_addr = obj->link_map.l_addr; + ehdr_addr = get_ehdr_addr(p, obj); - /* Read ELF header from remote process. */ - if (ehdr_addr == 0) { - /* If l_addr is zero, it means that there is no load bias. In that case, - * the elf address is on address 0x400000 on x86_64. */ - ret = read_memory((char *)&ehdr, sizeof(ehdr), pid, EXECUTABLE_START); - } - else { - ret = read_memory((char *)&ehdr, sizeof(ehdr), pid, ehdr_addr); - } + ret = read_memory((char *)&ehdr, sizeof(ehdr), pid, ehdr_addr); if (ret != 0) { DEBUG("Unable to read ELF header from process %d\n", pid); return ETARGETHOOK; @@ -584,8 +648,6 @@ /* Get first process header address. */ phdr_addr = ehdr_addr + ehdr.e_phoff; - if (ehdr_addr == 0) - phdr_addr += EXECUTABLE_START; /* Iterate over each process header. */ for (i = 0; i < ehdr.e_phnum; i++) { @@ -602,7 +664,7 @@ /* Look for the dynamic section. */ if (phdr.p_type == PT_DYNAMIC && !pt_dynamic_ran) { ElfW(Dyn) dyn; - ElfW(Addr) dyn_addr = ehdr_addr + phdr.p_paddr; + ElfW(Addr) dyn_addr = l_addr + phdr.p_vaddr; /* Iterate over each tag in this section. */ do { @@ -647,8 +709,7 @@ } else if (phdr.p_type == PT_NOTE) { /* We are after the build id. */ - - ElfW(Addr) note_addr = ehdr_addr + phdr.p_paddr; + ElfW(Addr) note_addr = l_addr + phdr.p_vaddr; unsigned sec_size = phdr.p_memsz; ElfW(Addr) note_addr_end = note_addr + sec_size; @@ -1115,7 +1176,7 @@ return ret; } - parse_dynobj_elf_headers(process->pid, obj); + parse_dynobj_elf_headers(process, obj); return 0; } @@ -1158,7 +1219,7 @@ /* Pointers to linux-vdso.so are invalid, so skip this library. */ if (strcmp(obj->filename, "linux-vdso.so.1") && strcmp(obj->filename, "linux-vdso64.so.1")) - parse_dynobj_elf_headers(pid, obj); + parse_dynobj_elf_headers(process, obj); /* Only libpulp.so should have those symbols exported. */ if (strstr(libname, "libpulp.so")) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libpulp-0.3.10/tools/introspection.h new/libpulp-0.3.11/tools/introspection.h --- old/libpulp-0.3.10/tools/introspection.h 2024-10-17 21:20:16.000000000 +0200 +++ new/libpulp-0.3.11/tools/introspection.h 2025-02-25 01:45:18.000000000 +0100 @@ -205,6 +205,8 @@ return get_basename(process->dynobj_main->filename); } +ElfW(Addr) get_ehdr_addr(struct ulp_process *, struct ulp_dynobj *); + ulp_error_t get_libpulp_error_state_remote(struct ulp_process *); const char *adjust_prefix_for_chroot(struct ulp_process *, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libpulp-0.3.10/tools/patches.c new/libpulp-0.3.11/tools/patches.c --- old/libpulp-0.3.10/tools/patches.c 2024-10-17 21:20:16.000000000 +0200 +++ new/libpulp-0.3.11/tools/patches.c 2025-02-25 01:45:18.000000000 +0100 @@ -451,14 +451,15 @@ * * @param patch The list of patches loaded in the target process. * @param obj The libary object. - * @param pid Pid of target process. + * @param p The process to analyze. * * @return True if livepatchable, False if not. */ static bool is_library_livepatchable(struct ulp_applied_patch *patch, - struct ulp_dynobj *obj, pid_t pid) + struct ulp_dynobj *obj, struct ulp_process *p) { + pid_t pid = p->pid; int i, ret; if (has_livepatch_loaded(patch, obj->filename)) return true; @@ -469,15 +470,9 @@ goto detach_process; } - ElfW(Addr) ehdr_addr = obj->link_map.l_addr; + ElfW(Addr) ehdr_addr = get_ehdr_addr(p, obj); ElfW(Addr) dynsym_addr = obj->dynsym_addr; - if (ehdr_addr == 0) { - /* If l_addr is zero, it means that there is no load bias. In that case, - * the elf address is on address 0x400000 on x86_64. */ - ehdr_addr = EXECUTABLE_START; - } - /* FIXME: Some applications take a very long time to decide if library is livepatchable because the library has a lot of symbols. In this case we limit the number of symbols to read to a constant value. Statistics shows @@ -561,7 +556,7 @@ if (!object_item) printf(" (none)\n"); while (object_item) { - if (is_library_livepatchable(patch, object_item, pid)) { + if (is_library_livepatchable(patch, object_item, process)) { printf(" in %s", object_item->filename); if (print_buildid) printf(" (%s)", buildid_to_string(object_item->build_id));
