Skip to content

Commit

Permalink
Replace dlsym with ELF file parsing for checking for symbol existence
Browse files Browse the repository at this point in the history
Previously, a sanity check in the `ulp` tool checking if the symbols
declared in the description section is actually in the code section.
This check was done by loading the patch with dlopen. However some
security flags in openbuildservice introduces a different behaviour
on dlopen, turning it unreliable to check this.

Now we parse the file as a ELF and check if the symbol is in the
symbol table.

Signed-off-by: Giuliano Belinassi <[email protected]>
  • Loading branch information
giulianobelinassi committed Jun 28, 2023
1 parent 3c59060 commit 12a51e3
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 45 deletions.
8 changes: 4 additions & 4 deletions include/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,10 @@ void libpulp_crash_assert_func(const char *file, const char *func, int line,

/** Poison any function that makes the process to abort. */
#ifndef DISABLE_ERR_POISON
# ifdef assert
# undef assert
# endif
# pragma GCC poison errx exit assert abort
#ifdef assert
#undef assert
#endif
#pragma GCC poison errx exit assert abort
#endif

#endif /* ERROR_H */
5 changes: 4 additions & 1 deletion include/insn_queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
#define INSN_BUFFER_MAX (2 * 1024 * 1024)

/** Define the current version of the instruction queue. */
#define INSNQ_CURR_VERSION 1
#define INSNQ_CURR_VERSION 1

/** The ULP instruction queue. This works as follows:
* 1- Libpulp write instructions that should be executed on the `ulp` tool
Expand All @@ -51,6 +51,9 @@ struct insn_queue
/** Size in bytes of content. Must not be larger than INSN_BUFFER_MAX. */
int size;

/** Here to force 8-byte alignment on the buffer.*/
int _align;

/** Buffer holding the instructions. */
char buffer[INSN_BUFFER_MAX];
};
Expand Down
30 changes: 19 additions & 11 deletions tools/extract.c
Original file line number Diff line number Diff line change
Expand Up @@ -334,34 +334,42 @@ build_symbols_list(Elf *elf)
struct ulp_so_info *
parse_so_elf(const char *target_path)
{
/* Ensure that we are never called with NULL argument. */
assert(target_path != NULL && "Provide a proper string.");
if (target_path == NULL)
return NULL;

/* Load ELF. */
int fd;
Elf *elf = load_elf(target_path, &fd);
struct ulp_so_info *so_info = NULL;

/* Create the ulp_so_info object. */
struct ulp_so_info *so_info = calloc(1, sizeof(struct ulp_so_info));
assert(so_info && "Error calling calloc.");

/* Get library name. */
so_info->name = strdup(get_basename(target_path));
so_info = calloc(1, sizeof(struct ulp_so_info));
if (so_info == NULL) {
WARN("Memory allocation error\n");
goto clean_elf;
}

/* Load the build id of elf object. */
unsigned buildid_len = 0;
if (get_elf_buildid(elf, (char *)so_info->buildid, &buildid_len)) {
WARN("Elf in %s do not have a build id.", target_path);
unload_elf(&elf, &fd);
return NULL;
FREE_AND_NULLIFY(so_info);
goto clean_elf;
}

if (buildid_len != BUILDID_LEN) {
WARN("Build ID len doesn't match BUILDID_LEN macro");
FREE_AND_NULLIFY(so_info);
goto clean_elf;
}

assert(buildid_len == BUILDID_LEN &&
"Build ID len doesn't match BUILDID_LEN macro");
/* Get library name. */
so_info->name = strdup(get_basename(target_path));

/* Build list of symbols. */
so_info->symbols = build_symbols_list(elf);

clean_elf:
unload_elf(&elf, &fd);
return so_info;
}
Expand Down
45 changes: 19 additions & 26 deletions tools/introspection.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,14 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/user.h>
#include <unistd.h>
#include <sys/stat.h>

#include "config.h"
#include "elf-extra.h"
#include "error_common.h"
#include "extract.h"
#include "insn_queue_tools.h"
#include "introspection.h"
#include "packer.h"
Expand Down Expand Up @@ -2138,10 +2139,6 @@ static int
check_livepatch_functions_matches_metadata(const char *prefix)
{
const char *so_filename = ulp.so_filename;
const struct ulp_unit *curr_unit;
void *container_handle;

int ret = 0;

/* If a prefix has been passed to trigger then we should remove it from the
path, as it is only intended to get libpulp.so to find the correct path
Expand All @@ -2150,39 +2147,35 @@ check_livepatch_functions_matches_metadata(const char *prefix)
int prefix_len = strlen(prefix);

/* Check that the prefix is there in the string. */
assert(strncmp(prefix, so_filename, prefix_len) == 0);
if (strncmp(prefix, so_filename, prefix_len) != 0) {
DEBUG("Prefix error: %s %s", prefix, so_filename);
return EINVAL;
}

so_filename += prefix_len;
}

/* Open livepatch container .so file temporarly. */
container_handle = dlopen(so_filename, RTLD_LOCAL | RTLD_LAZY);

if (!container_handle) {
struct ulp_so_info *so_info = parse_so_elf(so_filename);
if (so_info == NULL) {
WARN("failed to load container livepatch file in %s: %s.", so_filename,
dlerror());
return EINVAL;
}

/* Iterate over all unit objects in the metadata file. */
for (curr_unit = ulp.objs->units; curr_unit != NULL;
curr_unit = curr_unit->next) {
const char *new_fname = curr_unit->new_fname;
void *symbol;

/* Check if symbol exists. If not, return error. */
symbol = dlsym(container_handle, new_fname);

if (!symbol) {
WARN("symbol %s is not present in the livepatch container: %s",
new_fname, dlerror());
ret = EINVAL;
break;
/* Check all symbols. */
struct ulp_unit *unit;
for (unit = ulp.objs->units; unit != NULL; unit = unit->next) {
struct symbol *s = get_symbol_with_name(so_info, unit->new_fname);
if (s == NULL) {
WARN("Symbol %s not found in livepatch container %s", unit->new_fname,
so_filename);
release_so_info(so_info);
return 1;
}
}

dlclose(container_handle);
return ret;
release_so_info(so_info);
return 0;
}

/*
Expand Down
6 changes: 3 additions & 3 deletions tools/packer.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,17 +149,17 @@ get_object_metadata(Elf *elf, struct ulp_object *obj)
return 0;
}

/** @brief Get offsets of symbols in target library
/** @brief Check if all symbols in obj is in the info object.
*
* This function gather the address of all to-be-patched functions in the
* target library.
*
* @param elf The target library elf object.
* @param info info object containing the information from elf.
* @param obj Chain of objects.
* @param st1 Symbol table 1, usually .dymsym.
* @param st2 Symbol table 2, usually .symtab if present.
*
* @return 1
* @return 1 if success, 0 otherwise.
*/
int
get_target_addrs(struct ulp_so_info *info, struct ulp_object *obj)
Expand Down

0 comments on commit 12a51e3

Please sign in to comment.