Skip to content

Commit

Permalink
Add livepatchable command to check if a library is livepatchable
Browse files Browse the repository at this point in the history
The new command:

$ ulp livepatchable <library>

can be used to check if a certain library is livepatchable.

Signed-off-by: Giuliano Belinassi <gbelinassi@suse.de>
  • Loading branch information
giulianobelinassi committed Feb 17, 2022
1 parent 8ec3c8d commit 8b112ae
Show file tree
Hide file tree
Showing 10 changed files with 179 additions and 13 deletions.
1 change: 1 addition & 0 deletions tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,7 @@ TESTS = \
revert_and_patch.py \
process.py \
process_revert.py \
livepatchable.py \
manyprocesses.py

XFAIL_TESTS = \
Expand Down
27 changes: 27 additions & 0 deletions tests/livepatchable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/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

if testsuite.is_library_livepatchable('.libs/libexception.so') == True:
exit(0)

exit(1)
14 changes: 14 additions & 0 deletions tests/testsuite.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@
builddir = os.getcwd()
ulptool = builddir + '/../tools/ulp'

# Check if certain library is livepatchable.
def is_library_livepatchable(library):
command = [ulptool, "livepatchable", library]

try:
tool = subprocess.run(command, timeout=10, stderr=subprocess.STDOUT)
except subprocess.TimeoutExpired:
print('ulp tool deadlock');
return False

if tool.returncode == 0:
return True
return False

# Wrapper around pexpect.spawn that automatically sets userspace livepatching
# requirements, such as LD_PRELOAD'ing libpulp.so, as well as extends its
# functionality with live patching operations.
Expand Down
6 changes: 4 additions & 2 deletions tools/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ noinst_HEADERS = \
dump.h \
post.h \
revert.h \
messages.h
messages.h \
livepatchable.h

ulp_SOURCES = \
ulp.c \
Expand All @@ -45,7 +46,8 @@ ulp_SOURCES = \
revert.c \
messages.c \
introspection.c \
ptrace.c
ptrace.c \
livepatchable.c
ulp_LDADD = $(top_builddir)/common/libcommon.la -lelf -ldl $(LIBUNWIND_LIBS)

# Ensure access to the include directory
Expand Down
1 change: 1 addition & 0 deletions tools/arguments.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ typedef enum
ULP_POST,
ULP_REVERSE,
ULP_MESSAGES,
ULP_LIVEPATCHABLE,
} command_t;

struct arguments
Expand Down
72 changes: 72 additions & 0 deletions tools/livepatchable.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* libpulp - User-space Livepatching Library
*
* Copyright (C) 2017-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 <errno.h>
#include <fcntl.h>
#include <libelf.h>
#include <stdio.h>
#include <unistd.h>

#include "arguments.h"
#include "config.h"
#include "introspection.h"
#include "livepatchable.h"
#include "msg_queue.h"
#include "post.h"
#include "ulp_common.h"

int
run_livepatchable(struct arguments *arguments)
{
int ret = 0;
int fd;

/* Set the verbosity level in the common introspection infrastructure. */
ulp_verbose = arguments->verbose;
ulp_quiet = arguments->quiet;

fd = open(arguments->args[0], 0);
if (fd == -1)
errx(EXIT_FAILURE, "Unable to open file '%s': %s.\n", arguments->args[0],
strerror(errno));

elf_version(EV_CURRENT);
Elf *elf = elf_begin(fd, ELF_C_READ, NULL);

struct Elf_Scn *scn =
find_section_by_name(elf, "__patchable_function_entries");
if (scn == NULL) {
WARN("file '%s' is not livepatchable: Missing "
"__patchable_function_entries section.",
arguments->args[0]);
ret = 1;
}
else {
WARN("file '%s' is livepatchable.", arguments->args[0]);
ret = 0;
}

elf_end(elf);
close(fd);

return ret;
}
29 changes: 29 additions & 0 deletions tools/livepatchable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* libpulp - User-space Livepatching Library
*
* Copyright (C) 2017-2022 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/>.
*/

#ifndef LIVEPATCHABLE_H
#define LIVEPATCHABLE_H

struct arguments;

int run_livepatchable(struct arguments *);

#endif /* LIVEPATCHABLE.H */
12 changes: 6 additions & 6 deletions tools/post.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ static Elf *elf;
* such section is found. Exits in error if the string table containing
* sections names is not found.
*/
static Elf_Scn *
find_section_by_name(const char *name)
Elf_Scn *
find_section_by_name(Elf *elf, const char *name)
{
char *str;
size_t string_table;
Expand Down Expand Up @@ -95,9 +95,9 @@ merge_nops_at_addr(Elf64_Addr addr, size_t amount)
}

/* Use the .symtab if available, otherwise, the .dynsym. */
scn = find_section_by_name(".symtab");
scn = find_section_by_name(elf, ".symtab");
if (scn == NULL)
scn = find_section_by_name(".dynsym");
scn = find_section_by_name(elf, ".dynsym");
if (scn == NULL)
return;
data = elf_getdata(scn, NULL);
Expand Down Expand Up @@ -141,7 +141,7 @@ nops_fixup(void)
Elf64_Shdr *shdr;
Elf64_Addr addr;

scn = find_section_by_name("__patchable_function_entries");
scn = find_section_by_name(elf, "__patchable_function_entries");
if (scn == NULL)
return;
data = elf_getdata(scn, NULL);
Expand Down Expand Up @@ -183,7 +183,7 @@ run_post(struct arguments *arguments)
assert(elf_flagelf(elf, ELF_C_SET, ELF_F_LAYOUT));

/* Sanity check. */
scn = find_section_by_name("__patchable_function_entries");
scn = find_section_by_name(elf, "__patchable_function_entries");
if (scn == NULL)
errx(EXIT_FAILURE,
"Section __patchable_function_entries not found.\n"
Expand Down
4 changes: 4 additions & 0 deletions tools/post.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
#define POST_H

struct arguments;
struct Elf_Scn;
struct Elf;

struct Elf_Scn *find_section_by_name(struct Elf *, const char *name);

int run_post(struct arguments *);

Expand Down
26 changes: 21 additions & 5 deletions tools/ulp.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "config.h"
#include "dump.h"
#include "introspection.h"
#include "livepatchable.h"
#include "messages.h"
#include "packer.h"
#include "patches.h"
Expand Down Expand Up @@ -65,7 +66,8 @@ static const char doc[] =
" with PID\n"
" post Post process patch container (.so file) in ARG1.\n"
" reverse Create reverse livepatch from metadata in ARG1.\n"
" messages Print livepatch information contained in libpulp.\n";
" messages Print livepatch information contained in libpulp.\n"
" livepatchable Check if .so library in ARG1 is livepatchable.\n";

/* clang-format on */

Expand Down Expand Up @@ -117,10 +119,15 @@ command_from_string(const char *str)
};

static const struct entry entries[] = {
{ "patches", ULP_PATCHES }, { "check", ULP_CHECK },
{ "dump", ULP_DUMP }, { "packer", ULP_PACKER },
{ "trigger", ULP_TRIGGER }, { "post", ULP_POST },
{ "reverse", ULP_REVERSE }, { "messages", ULP_MESSAGES },
{ "patches", ULP_PATCHES },
{ "check", ULP_CHECK },
{ "dump", ULP_DUMP },
{ "packer", ULP_PACKER },
{ "trigger", ULP_TRIGGER },
{ "post", ULP_POST },
{ "reverse", ULP_REVERSE },
{ "messages", ULP_MESSAGES },
{ "livepatchable", ULP_LIVEPATCHABLE },
};

size_t i;
Expand Down Expand Up @@ -206,6 +213,11 @@ handle_end_of_arguments(const struct argp_state *state)
if (arguments->process_wildcard == 0)
argp_error(state, "process is mandatory in 'messages' command.");
break;

case ULP_LIVEPATCHABLE:
if (state->arg_num < 2) {
argp_error(state, "file is mandatory in 'livepatchable' command.");
}
}
}

Expand Down Expand Up @@ -324,6 +336,10 @@ main(int argc, char **argv)
case ULP_MESSAGES:
ret = run_messages(&arguments);
break;

case ULP_LIVEPATCHABLE:
ret = run_livepatchable(&arguments);
break;
}

return ret;
Expand Down

0 comments on commit 8b112ae

Please sign in to comment.