Skip to content

Commit

Permalink
Fix build id mismatch problems with glibc 2.40
Browse files Browse the repository at this point in the history
Libpulp showed a weird behavior when loaded with glibc 2.40: some tests
failed with a buildid mismatch.  The source of the issue is the faulty
buildid computation algorithm.  Replace it by another one written by
Richard Biener in:

https://gcc.gnu.org/legacy-ml/gcc/2019-02/msg00120.html

Signed-off-by: Giuliano Belinassi <[email protected]>
  • Loading branch information
giulianobelinassi committed Dec 19, 2024
1 parent ca291a0 commit 6bcc4c6
Showing 1 changed file with 46 additions and 54 deletions.
100 changes: 46 additions & 54 deletions lib/ulp.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@
#include <sys/mman.h>
#include <unistd.h>

#include "arch_common.h"
#include "config.h"
#include "error.h"
#include "insn_queue_lib.h"
#include "interpose.h"
#include "msg_queue.h"
#include "ulp.h"
#include "arch_common.h"

/* ulp data structures */
struct ulp_patching_state __ulp_state = { 0, NULL };
Expand Down Expand Up @@ -958,76 +958,68 @@ check_patch_dependencies(struct ulp_metadata *ulp)
return 0;
}

/** build_id_note structure, holding information about the build id. */
struct build_id_note
{
/* The NHdr ELF. See elf.h for more information. */

/** Size of the name structure. */
uint32_t namesz;
/** Length of the build id. */
uint32_t descsz;
/** Unknown. */
uint32_t type;
/** Name. */
char name[4]; /* Note name for build-id is "GNU\0" */
/** Build id. */
unsigned char build_id[0];
};

/** @brief Function used by dl_iterate_phdr to check if there are some library
* that matches the buildid in the `data` ulp_metadata object.
*/
int
compare_build_ids(struct dl_phdr_info *info,
size_t __attribute__((unused)) size, void *data)
{
int i;
char *note_ptr, *build_id_ptr, *note_sec;
uint32_t note_type, build_id_len, name_len, sec_size, next = 0;
struct ulp_metadata *ulp;
ulp = (struct ulp_metadata *)data;

/* algorithm goes as follows:
* 1 - check every object inside ulp_metadata
* 1.1 - if object is main, match loaded object whose name length is 0
* 1.2 - else, match ulp object and loaded object names
* 2 - check every phdr for loaded object and match all PT_NOTE
* 3 - trespass PT_NOTE searching for NT_GNU_BUILD_ID
* 3.1 - once found, match contents with ulp object build id
* 3.2 - if match, mark ulp object as checked and break dl_iterate (return 1)
* 3.3 - else, continue looking for the library by returning 0
*
* Algorithm assumes that objects will only have one NT_GNU_BUILD_ID entry
*/

for (i = 0; i < info->dlpi_phnum; i++) {
if (info->dlpi_phdr[i].p_type != PT_NOTE)
continue;

note_sec = (char *)(info->dlpi_phdr[i].p_vaddr + info->dlpi_addr);
sec_size = info->dlpi_phdr[i].p_memsz;
/** Align `val` to `align` bytes. */
#define ALIGN(val, align) (((val) + (align) - 1) & ~((align) - 1))

for (note_ptr = note_sec, note_type = (uint32_t) * (note_ptr + 8);
note_type != NT_GNU_BUILD_ID && note_ptr < note_sec + sec_size;
note_ptr = note_sec + next, note_type = (uint32_t) * (note_ptr + 8)) {
struct ulp_metadata *ulp = (struct ulp_metadata *)data;

build_id_len = (uint32_t) * (note_ptr + 4);
name_len = (uint32_t)*note_ptr;

/* fix paddings */
build_id_len += build_id_len % 4;
name_len += name_len % 4;

next = next + build_id_len + name_len + 12;
}

/* could not fid the build id in the note section, go to next sec */
if (note_type != NT_GNU_BUILD_ID)
for (unsigned i = 0; i < info->dlpi_phnum; ++i) {
if (info->dlpi_phdr[i].p_type != PT_NOTE)
continue;

build_id_len = (uint32_t) * (note_ptr + 4);
build_id_len += build_id_len % 4;
if (build_id_len != ulp->objs->build_id_len)
return 0;
struct build_id_note *note =
(struct build_id_note *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
ptrdiff_t size = info->dlpi_phdr[i].p_filesz;

/* we compute, but currently do not check note names */
name_len = (uint32_t)*note_ptr;
name_len += name_len % 4;
while (size >= (ptrdiff_t)sizeof(struct build_id_note)) {
if (note->type == NT_GNU_BUILD_ID && note->namesz == 4 &&
note->descsz >= 16) {

build_id_ptr = note_ptr + 12 + name_len;
if (memcmp(ulp->objs->build_id, build_id_ptr, build_id_len) == 0) {
ulp->objs->build_id_check = 1;
return 1;
}
else {
return 0;
/* Check if build matches. */
if (note->descsz == ulp->objs->build_id_len &&
memcmp(ulp->objs->build_id, note->build_id, note->descsz)) {
ulp->objs->build_id_check = 1;
return 1;
}

/* Does not match. Go to another lib. */
break;
}
size_t offset = (sizeof(uint32_t) * 3 + ALIGN(note->namesz, 4) +
ALIGN(note->descsz, 4));
note = (struct build_id_note *)((char *)note + offset);
size -= offset;
}
}

return 0;

#undef ALIGN
}

/** @brief Check if the build id in the patch matches some .
Expand Down

0 comments on commit 6bcc4c6

Please sign in to comment.