Skip to content

Commit

Permalink
Find address of reference to symbol by its name
Browse files Browse the repository at this point in the history
Before this patch, the user could only specify
```
 #target_symbol:target_symbol_ref:addr1:addr2
```
however, those address can change when you modify the livepatch
sourcecode. Therefore, we now support:
```
 #target_symbol:target_symbol_ref
```
and now `addr1` and `addr2` will be collected analysing the target
library and livepatch container automatically on packer time.

Signed-off-by: Giuliano Belinassi <gbelinassi@suse.de>
  • Loading branch information
giulianobelinassi committed Feb 23, 2022
1 parent 8b112ae commit 4a0767f
Show file tree
Hide file tree
Showing 10 changed files with 247 additions and 15 deletions.
12 changes: 11 additions & 1 deletion lib/ulp.c
Original file line number Diff line number Diff line change
Expand Up @@ -833,7 +833,17 @@ ulp_apply_all_units(struct ulp_metadata *ulp)
/* Now patch static data references in the live patch object */
ref = ulp->refs;
while (ref) {
uintptr_t patch_address = patch_base + ref->patch_offset;
uintptr_t patch_address;
if (ref->patch_offset == 0) {
/* In case the user did not specify the patch offset, try to find the
symbol's address by its name. */
patch_address =
(uintptr_t)load_so_symbol(ref->reference_name, ulp->so_handler);
ref->patch_offset = patch_address - patch_base;
}
else {
patch_address = patch_base + ref->patch_offset;
}
if (ref->tls) {
tls_index ti = { .ti_module = tls_idx, .ti_offset = ref->target_offset };
memcpy((void *)patch_address, &ti, sizeof(ti));
Expand Down
9 changes: 9 additions & 0 deletions tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ check_LTLIBRARIES += libdozens_livepatch1.la \
libaddress_livepatch1.la \
libcontract_livepatch1.la \
libaccess_livepatch1.la \
libaccess_livepatch2.la \
libtls_livepatch1.la \
libbuildid_livepatch1.la \
libmanyprocesses_livepatch1.la
Expand Down Expand Up @@ -242,6 +243,9 @@ libcontract_livepatch1_la_LDFLAGS = $(CONVENIENCE_LDFLAGS)
libaccess_livepatch1_la_SOURCES = libaccess_livepatch1.c
libaccess_livepatch1_la_LDFLAGS = $(CONVENIENCE_LDFLAGS)

libaccess_livepatch2_la_SOURCES = libaccess_livepatch2.c
libaccess_livepatch2_la_LDFLAGS = $(CONVENIENCE_LDFLAGS)

libtls_livepatch1_la_SOURCES = libtls_livepatch1.c
libtls_livepatch1_la_LDFLAGS = $(CONVENIENCE_LDFLAGS)

Expand Down Expand Up @@ -303,6 +307,9 @@ METADATA = \
libaccess_livepatch1.dsc \
libaccess_livepatch1.ulp \
libaccess_livepatch1.rev \
libaccess_livepatch2.dsc \
libaccess_livepatch2.ulp \
libaccess_livepatch2.rev \
libtls_livepatch1.dsc \
libtls_livepatch1.ulp \
libtls_livepatch1.rev \
Expand Down Expand Up @@ -331,6 +338,7 @@ EXTRA_DIST = \
libaddress_livepatch1.in \
libcontract_livepatch1.in \
libaccess_livepatch1.in \
libaccess_livepatch2.in \
libtls_livepatch1.in \
libbuildid_livepatch1.in \
libmanyprocesses_livepatch1.in
Expand Down Expand Up @@ -482,6 +490,7 @@ TESTS = \
exception_handling.py \
missing_function.py \
access.py \
access2.py \
tls.py \
buildid.py \
libpulp_messages.py \
Expand Down
58 changes: 58 additions & 0 deletions tests/access2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* libpulp - User-space Livepatching Library
*
* Copyright (C) 2021 SUSE Software Solutions GmbH
*
* This file is part of libpulp.
*
* libpulp is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libpulp 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libpulp. If not, see <http://www.gnu.org/licenses/>.
*/

#include <errno.h>
#include <stdio.h>
#include <string.h>

#include <libaccess.h>

int
main(void)
{
char buffer[128];

/* Original banner. */
printf("Banner addr: 0x%lX\n", (unsigned long)banner_get());
printf("%s\n", banner_get());

/* Use original banner setting function. */
banner_set(strdup("Banner changed from main"));
printf("%s\n", banner_get());

/* Wait for input. */
if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
if (errno) {
perror("access");
return 1;
}
}

/*
* Use banner setting function again, which is supposed to have been
* changed by the test driver. The patched function ignores the
* argument, so 'String from main' should not be in the output.
*/
banner_set("String from main");
printf("%s\n", banner_get());

return 0;
}
37 changes: 37 additions & 0 deletions tests/access2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/env python3

# libpulp - User-space Livepatching Library
#
# Copyright (C) 2021 SUSE Software Solutions GmbH
#
# This file is part of libpulp.
#
# libpulp is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# libpulp 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with libpulp. If not, see <http://www.gnu.org/licenses/>.

import testsuite

child = testsuite.spawn('access')

child.expect('Original banner')
child.expect('Banner changed from main')

child.livepatch('libaccess_livepatch2.ulp')

child.sendline('')
child.expect('String from live patch',
reject=['String from main',
'Live patch data references not initialized'])

child.close(force=True)
exit(0)
47 changes: 47 additions & 0 deletions tests/libaccess_livepatch2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* libpulp - User-space Livepatching Library
*
* Copyright (C) 2021 SUSE Software Solutions GmbH
*
* This file is part of libpulp.
*
* libpulp is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libpulp 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libpulp. If not, see <http://www.gnu.org/licenses/>.
*/

#include <err.h>
#include <stdlib.h>

#include <libaccess.h>

char **ulpr_banner = NULL;
static char *ulpr_string = "String from live patch";

void
new_banner_set(__attribute__((unused)) char *new)
{
if (ulpr_banner == NULL)
errx(EXIT_FAILURE, "Live patch data references not initialized");

*ulpr_banner = ulpr_string;
}

/*
* Touch ulpr_banner so that it does not get optimized away or placed into
* read-only sections.
*/
void
banner_disturb(void)
{
ulpr_banner++;
}
4 changes: 4 additions & 0 deletions tests/libaccess_livepatch2.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
__ABS_BUILDDIR__/.libs/libaccess_livepatch2.so
@__ABS_BUILDDIR__/.libs/libaccess.so.0
banner_set:new_banner_set
#banner:ulpr_banner
6 changes: 4 additions & 2 deletions tests/offsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,10 @@ def find_offset(file, name):
poff = find_offset(patch, pname)

# Replace offset template patterns with actual offsets
line = line.replace('__TARGET_OFFSET__', toff)
line = line.replace('__PATCH_OFFSET__', poff)
if toff is not None:
line = line.replace('__TARGET_OFFSET__', toff)
if poff is not None:
line = line.replace('__PATCH_OFFSET__', poff)

# Write every line back to the output file
ofile.write(line)
Expand Down
3 changes: 2 additions & 1 deletion tools/introspection.c
Original file line number Diff line number Diff line change
Expand Up @@ -1687,7 +1687,8 @@ check_livepatch_functions_matches_metadata(void)
symbol = dlsym(container_handle, new_fname);

if (!symbol) {
WARN("symbol %s is not present in the livepatch container.", new_fname);
WARN("symbol %s is not present in the livepatch container: %s",
new_fname, dlerror());
ret = EINVAL;
break;
}
Expand Down
84 changes: 74 additions & 10 deletions tools/packer.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
#include "packer.h"
#include "ulp_common.h"

static int get_elf_tgt_ref_addrs(Elf *, struct ulp_reference *, Elf_Scn *,
Elf_Scn *);

void
free_metadata(struct ulp_metadata *ulp)
{
Expand Down Expand Up @@ -170,12 +173,14 @@ get_build_id_note(Elf *elf)
}

int
get_ulp_elf_metadata(const char *filename, struct ulp_object *obj)
get_ulp_elf_metadata(const char *filename, struct ulp_metadata *ulp)
{
int fd, ret;
Elf *elf;
Elf_Scn *dynsym;
Elf_Scn *symtab = NULL;
struct ulp_object *obj = ulp->objs;
struct ulp_reference *ref = ulp->refs;

fd = 0;
elf = load_elf(filename, &fd);
Expand Down Expand Up @@ -206,6 +211,12 @@ get_ulp_elf_metadata(const char *filename, struct ulp_object *obj)
goto clean_elf;
}

if (!get_elf_tgt_ref_addrs(elf, ref, dynsym, symtab)) {
WARN("Unable to get target reference addresses.");
ret = 0;
goto clean_elf;
}

ret = 1;

clean_elf:
Expand All @@ -225,6 +236,18 @@ get_object_metadata(Elf *elf, struct ulp_object *obj)
return 1;
}

/** @brief Get offsets of symbols in target library
*
* This function gather the address of all to-be-patched functions in the
* target library.
*
* @param elf The target library elf object.
* @param obj Chain of objects.
* @param st1 Symbol table 1, usually .dymsym.
* @param st2 Symbol table 2, usually .symtab if present.
*
* @return 1
*/
int
get_elf_tgt_addrs(Elf *elf, struct ulp_object *obj, Elf_Scn *st1, Elf_Scn *st2)
{
Expand All @@ -242,6 +265,40 @@ get_elf_tgt_addrs(Elf *elf, struct ulp_object *obj, Elf_Scn *st1, Elf_Scn *st2)
return 1;
}

/** @brief Get offsets of references to symbol in target library
*
* When the user doesn't specify the offset of the target symbol in the target
* library when using the # syntax, try to find it by looking into the target
* library symbols.
*
* @param elf The target library elf object.
* @param ref Chain of references.
* @param st1 Symbol table 1, usually .dymsym.
* @param st2 Symbol table 2, usually .symtab if present.
*
* @return 1
*/
static int
get_elf_tgt_ref_addrs(Elf *elf, struct ulp_reference *ref, Elf_Scn *st1,
Elf_Scn *st2)
{

while (ref != NULL) {
if (ref->target_offset == 0) {
ref->target_offset =
(uintptr_t)get_symbol_addr(elf, st1, ref->target_name);
if (ref->target_offset == 0 && st2 != NULL) {
/* In case we couldn't find the symbol there, look in the symtab, if
* available. */
ref->target_offset =
(uintptr_t)get_symbol_addr(elf, st2, ref->target_name);
}
}
ref = ref->next;
}
return 1;
}

int
create_patch_metadata_file(struct ulp_metadata *ulp, const char *filename)
{
Expand Down Expand Up @@ -496,16 +553,23 @@ parse_description(const char *filename, struct ulp_metadata *ulp)

third = second + 1;
second = strchr(third, ':');
*second = '\0';
ref->reference_name = strdup(third);

third = second + 1;
second = strchr(third, ':');
*second = '\0';
ref->target_offset = (intptr_t)strtol(third, NULL, 16);
/* Check if the user manually specified the offsets. */
if (second == NULL)
ref->reference_name = strdup(third);
else {
*second = '\0';
ref->reference_name = strdup(third);

third = second + 1;
ref->patch_offset = (intptr_t)strtol(third, NULL, 16);
third = second + 1;

second = strchr(third, ':');
*second = '\0';
ref->target_offset = (intptr_t)strtol(third, NULL, 16);

third = second + 1;
ref->patch_offset = (intptr_t)strtol(third, NULL, 16);
}

ref->next = ulp->refs;
ulp->refs = ref;
Expand Down Expand Up @@ -794,7 +858,7 @@ run_packer(struct arguments *arguments)
}
DEBUG("target library: %s.", arguments->library);

if (!get_ulp_elf_metadata(arguments->library, ulp.objs)) {
if (!get_ulp_elf_metadata(arguments->library, &ulp)) {
WARN("unable to parse target library.");
goto main_error;
}
Expand Down
2 changes: 1 addition & 1 deletion tools/packer.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Elf_Scn *get_dynsym(Elf *elf);

Elf_Scn *get_build_id_note(Elf *elf);

int get_ulp_elf_metadata(const char *filename, struct ulp_object *obj);
int get_ulp_elf_metadata(const char *filename, struct ulp_metadata *ulp);

int get_object_metadata(Elf *elf, struct ulp_object *obj);

Expand Down

0 comments on commit 4a0767f

Please sign in to comment.