Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce GDB interface #218

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion common/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@ noinst_LTLIBRARIES = libcommon.la
# Ensure access to the include directory
AM_CFLAGS += -I$(abs_top_srcdir)/include

libcommon_la_SOURCES = common.c
# Add -fno-strict-alias to the insn_queue code.
insn_queue.lo : CFLAGS += -fno-strict-aliasing

libcommon_la_SOURCES = common.c insn_queue.c
128 changes: 128 additions & 0 deletions common/insn_queue.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/*
* libpulp - User-space Livepatching Library
*
* Copyright (C) 2023 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 "ulp_common.h"
#include "insn_queue.h"
#include "error_common.h"

#include <assert.h>
#include <stdio.h>

/** @brief Interpret a print instruction.
*
* @param insn Instruction to interpet. Must be a print instruction.
*
* @return Size of interpreted instruction.
*/
int
insn_interpret_print(struct ulp_insn *insn)
{
struct ulp_insn_print *p_insn = (struct ulp_insn_print *)insn;

printf("%s\n", p_insn->bytes);
return insn->size;
}

/** @brief Interpret NOP instruction.
*
* @param insn Instruction to interpet. Must be a NOP instruction.
*
* @return Size of interpreted instruction (always 1 byte).
*/
int
insn_interpret_nop(struct ulp_insn *insn)
{
return sizeof(*insn);
}

/* Writes are specific from libpulp and libpulp-tools:
* - On tools, use ptrace.
* - On libpulp, set text permission and use memcpy.
*/
int
insn_interpret_write(struct ulp_insn *insn);

/** Table of decoders. Index must match the `enum ulp_insn_table` object. */
static int (*decoders[ULP_NUM_INSNS])(struct ulp_insn *insn) = {
insn_interpret_nop,
insn_interpret_print,
insn_interpret_write,
};

/** @brief Interpret the given instruction.
*
* This function will interpret the given instruction.
*
* @param insn Instruction to interpret.
*
* @return Size of instruction interpreted.
*/
int
insn_interpret(struct ulp_insn *insn)
{
int index = (int)insn->type;
return (decoders[index])(insn);
}

/** @brief Interpret the instructions in queue.
*
* Interpret all instructions inserted into the queue object.
*
* @param queue
*/
int
insnq_interpret(insn_queue_t *queue)
{
int pc = 0; /* Like a CPU program counter. */
int num_insns_executed = 0;

int size = queue->size;
int num_insns = queue->num_insns;
char *buffer = queue->buffer;

while (num_insns_executed < num_insns) {
struct ulp_insn *insn = (struct ulp_insn *)&buffer[pc];
if (ulp_insn_valid(insn)) {
pc += insn_interpret(insn);
num_insns_executed++;
}
else {
/* Abort if an invalid insn is received. */
WARN("insnq: invalid insn with opcode %d. Further insns will be "
"ignored.", (int)insn->type);
return EINSNQ;
}
}

/* The pc should stop at the size of the queue. */
if (pc != size) {
WARN("insnq: there are bytes left in the instruction queue");
return EINSNQ;
}

/* Number of instructions should match what is in the queue. */
if (num_insns_executed != num_insns) {
WARN("insnq: not all instructions executed");
return EINSNQ;
}

return 0;
}
10 changes: 10 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,16 @@ AC_SUBST([LIBUNWIND_LIBS], ["-lunwind-generic -lunwind-ptrace -lunwind"])
AC_DEFINE(ENABLE_STACK_CHECK, 1, [Enable stack checking routines]),
AC_DEFINE(ENABLE_STACK_CHECK, 0, [Disable stack checking routines]))

# Enable a gdb interface so that livepatches can be triggered within gdb.
AC_ARG_ENABLE(gdb-interface,
AS_HELP_STRING([--enable-gdb-interface],
[build and exposes an interface for livepatching withing gdb. [default=no]]),
[enable_gdb_interface=yes],
[enable_gdb_interface=no; break])

AS_IF([test "$enable_gdb_interface" = "yes"],
AC_DEFINE(ENABLE_GDB_INTERFACE, 1, [Enable gdb interface for livepatching]))

# Check if libseccomp is present. This is required for testing.
CFLAGS="$CFLAGS -I/usr/include/libseccomp/"
AC_CHECK_HEADER([seccomp.h],,
Expand Down
3 changes: 2 additions & 1 deletion include/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ noinst_HEADERS = \
terminal_colors.h \
ld_rtld.h \
insn_queue.h \
insn_queue_lib.h
insn_queue_lib.h \
minielf.h

# Workaround a bug in Autoconf 2.69
if CPU_X86_64
Expand Down
9 changes: 9 additions & 0 deletions include/insn_queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,13 @@ ulp_insn_valid(struct ulp_insn *insn)
}
}


/** @brief Interpret the instructions in queue.
*
* Interpret all instructions inserted into the queue object.
*
* @param queue
*/
int insnq_interpret(insn_queue_t *queue);

#endif /* INSNQ_H */
8 changes: 8 additions & 0 deletions include/insn_queue_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,12 @@ ulp_error_t insnq_insert_write(void *addr, int n, const void *bytes);

int insnq_ensure_emptiness(void);

/* Not necessary if compiling without gdb interface. */
#ifdef ENABLE_GDB_INTERFACE

/** Interpret the global instruction queue from process side. */
int insnq_interpret_from_lib(void);

#endif //ENABLE_GDB_INTERFACE

#endif
74 changes: 74 additions & 0 deletions include/minielf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* libpulp - User-space Livepatching Library
*
* Copyright (C) 2024 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/>.
*/

/* Small parser for elf, not depending on larger libraries such as libelf
* and with very small memory footprint. No allocation on the heap is done
* in this library.
*/

/* This file is not needed if we are compiling without gdb interface. */
#ifdef ENABLE_GDB_INTERFACE

#include <elf.h>

/** Maximum size of the Section String Table. */
#define STRTBL_SIZE_MAX 0x500

/** Typedefs so we can adjust according to architecture. */
typedef Elf64_Ehdr Elf_Ehdr;
typedef Elf64_Shdr Elf_Shdr;
typedef Elf64_Half Elf_Half;
typedef Elf64_Off Elf_Off;

/** Read the Elf File Header. */
Elf_Ehdr *Elf_Parse_Ehdr(Elf_Ehdr *ehdr, int fd);

/** Get an ELF section by its name.
*
* OBS: use `readelf -S <file>` to show section names.
*/
Elf_Shdr *Elf_Get_Shdr_By_Name(Elf_Shdr *shdr, const char *name, int fd,
const Elf_Ehdr *ehdr, const char strtbl[]);


/** Get an ELF section by its index.
*
* OBS: use `readelf -S <file>` to show section index [<idx>].
*/
Elf_Shdr *Elf_Get_Shdr(Elf_Shdr *shdr, Elf_Half index,
int fd, const Elf_Ehdr *ehdr);

/** Get the section string table. */
long Elf_Load_Strtbl(char strtbl[STRTBL_SIZE_MAX], const Elf_Ehdr *ehdr, int fd);

/** Load Section into `dest` buffer. */
long Elf_Load_Section(unsigned dest_size, unsigned char *dest,
const Elf_Shdr *shdr, int fd);

/** ----- ELF functions related to ULP ----- . */

/** Get the .ulp section from the given ELF file. */
long Get_ULP_Section(unsigned dest_size, unsigned char *dest, const char *file);

/** Get the .ulp.rev section from the given ELF file. */
long Get_ULP_REV_Section(unsigned dest_size, unsigned char *dest, const char *file);

#endif //ENABLE_GDB_INTERFACE
2 changes: 2 additions & 0 deletions include/ulp_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@
#ifndef _ULP_LIB_COMMON_
#define _ULP_LIB_COMMON_

#include "config.h"
#include <elf.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <time.h>
#include <sys/types.h>

#define OUT_PATCH_NAME "metadata.ulp"
#define OUT_REVERSE_NAME "reverse.ulp"
Expand Down
4 changes: 3 additions & 1 deletion lib/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ libpulp_la_SOURCES = \
interpose.c \
msg_queue.c \
insn_queue.c \
error.c
error.c \
minielf.c \
gdb_interface.c

libpulp_la_LDFLAGS = \
-ldl \
Expand Down
Loading
Loading