Git Product home page Git Product logo

llpatch's Introduction

LLpatch: LLVM-based Kernel Livepatch Generation

LLpatch generates, from a source patch, a kernel loadable module or binary package, that can update Linux kernel without rebooting a machine. It uses LLVM IR (Intermediate Representation) to generate Linux kernel livepatch. Livepatch generation by LLpatch is not affected by machine architecture, types of linkers, and kernel versions. In addition, it does not require a whole kernel build with special compiler options, which makes livepatch generation much faster while keeping original kernel repository unchanged.

Benefits of LLpatch

LLpatch has lots of benefits compared to the existing livepatch generation tools. These are important benefits:

  1. Architecture-Agnostic: The core algorithm for kernel livepatch generation is to "diff" patched.c against original.c and distill the differences. Rather than a source-level diff, LLpatch uses LLVM IR for diffing to abstract away all the specifics/details on machine architecture, types of linkers, and kernel version.

  2. Easy Callbacks and LLpatch Symbols: LLpatch helps the livepatch developer implement four callbacks before/after patching/unpatching the livepatch. The developer can implement those callbacks in their local .c file and feed the file to LLpatch. In addition, in their callbacks, LLpatch provies simple macros to access global varaibles (it doesn't matter if they are local static or not) defined in kernel modules and/or vmlinux on a "running" machine. This helps and simplifies development for kernel livepatch.

  3. Slim Livepatch: LLpatch uses 'llvm-diff' to perform the diffing and generates LLVM IR code that distills the differences. This allows compiler-backend to fully optimize a final ELF binary for kernel livepatch. (e.g., no redundant global variables not used in livepatch.

  4. Better Checking and Validation: LLVM IR contains much more information than ELF binary. So, it's possible to implement lots of useful checking and validation mechanism for livepatch generation. (e.g., changes in function prototype should not be allowed.)

  5. Ultra-Fast Livepatch Generation and Unchanged Kernel Repository

    • LLpatch doesn't require special compiler options for the diffing. So the kernel doesn't need to be re-compiled.
    • Assuming that a kernel repository is already built, LLpatch parses a .patch file to figure out what files are changed by the .patch file. Compile options are derived from *.o.cmd files. For a simple livepatch generation, LLpatch takes just a few seconds.
  6. Semi-Automatic Livepatch Generation and Easy Debugging

    • LLpatch respects Unix philasophy, "One command does one task very well." To this end, LLpatch implements small commands (livepatch, llpatch-merge, livepatch-compile, update-patch, ...) that runs one task very well. llpatch puts them together to orchestrate livepatch generation.
    • LLpatch can stop livepatch generation at any micro steps, allow manual intervention, and resume the generation from where it left. This is essential to use (pre|post)-(patch|unpatch) callbacks and initialize shadow variable if required.
    • Log every micro steps and their results for livepatch generation. In case that generation doesn't go through smoothly, developer can have enough information for reproducing and debugging the bug.
  7. Handling Duplicate Symbol Names

    • LLpatch makes use of thin archive to resolve duplicate symbol names when generating kernel livepatch. This greatly simplies logic for the symbol handling.

Supported Architectures

The livepatch generation by LLpatch is not affected by machine architecture. As long as the 'clang' is available for the architecture and Linux kernel can be compiled with the 'clang', LLpatch should work. For now, LLpatch is well tested on the following architectures.

  • x86-64
  • arm64

How to Build LLpatch

LLpatch is implemented in C++ and bash scripts. The followings are prerequisites to build and run LLpatch.

Prerequisites for C++

  1. clang++

The 'Makefile' for LLpatch uses 'clang++' to compile the source codes. The source codes for LLpatch uses c++17 standard. Hence, please install clang 11 or later to build LLpatch.

  • Ubuntu: clang-11
  • ...
  1. llvm-11

LLpatch generates and parses LLVM IR for the livepatch generation. To this end, LLpatch requires LLVM library. Current LLpatch is implemented with llvm-11 (or later) library. This is a package name for llvm-11.

  • Ubuntu: llvm-11-dev
  • ...
  1. ELF library

At the final step for livepatch generation, LLpatch creates special ELF sections in the kernel loadable module, kernel livepatch. The sections are used by Linux kernel to apply the livepatch properly. To parse and manipulate ELF sections, ELF library is used.

  • Ubuntu: libelf-dev
  • ...

Prerequisites for llpatch

The llpatch uses couple of commands to orchestrate the generation process for kernel livepatch. The following packages are required.

  • Ubuntu: binutils, binutils-aarch64-linux-gnu, diffstat, gawk, git, grep, kmod, make, patch, sed
  • ...

Build LLpatch

LLpatch provides a simple 'Makefile' to build. Please open the 'Makefile' to check the path to the LLVM and ELF libraries. If the paths are correct in the 'Makefile', please issue the following command.

# print out help message on how we want to build
$ make

# clean up
$ make distclean

# build LLpatch
$ make CONFIG=optimize all -j `nproc`

Recommendations/Assumptions on .patch File

LLpatch makes few recommendations/assumptions on .patch file, input file, for livepatch generation.

  1. Changes in header files are highly discouraged.

    • This is intentional not to allow big livepatch. It has been observed that large livepatch is hard to be applied under heavy workload.
  2. No changes made in kbuild, makefiles for Linux kernel.

  3. Changes in either a single kernel module or vmlinux

    • This is intentional design choice to simplify livepatch generation logic in LLpatch.
    • If it's required to generate livepatch that patches several kernel modules and/or vmlinux, LLpatch provides '--multi' option to do that.
    • Again, large kernel livepatch is highly discouraged.
  4. No fuzzy matching for applying .patch file

    • To reduce the complexity in distilling changed code by .patch file, no fuzzy matching is allowed for .patch file.
    • If 'llpatch' denies .patch file, use 'update-patch' command to avoid fuzzy matching.

Preparation for Kernel Livepatch Generation

LLpatch assumes that Linux kernel is already built. If a fresh kernel repository is just created, please build Linux kernel first.

Once Linux kernel is built, next step is to ensure that .patch file, input to LLpatch, can be applied properly onto the kernel repository. For this, please run the following command for dry-run.

# assuming that you are under root of kernel repository.
$ patch -N -p1 -d `pwd` --dry-run -i "${PATCH_FILE}"

If dry-run sees fuzzy-matching, use the following command to make the patch well-aligned with the kernel repository.

$ update-patch --help
Usage: update-patch [IN_FILE] [OUT_FILE]
Update .patch file, [IN_FILE] to [OUT_FILE]

File: patch file

$ update-patch "${PATCH_FILE}" "${UPDATED_PATCH_FILE}"

How to Generate Kernel Livepatch by LLpatch

LLpatch requires two inputs to generate kernel livepatch. The first input is a path to the root of "pre-built" kernel repository. The second input is a .patch file. With the given inputs, livepatch generation is very simple. Just one command, 'llpatch'. The following shows list of command-line options to create a kernel livepatch.

# prints out help message
$ ${path_to_llpatch}/llpatch --help
Usage: llpatch [OPTIONS] [FILE]
Build a package for kernel livepatch.

File: .patch file to use for the livepatch package build.
      The patch is applied temporarily to kernel.

Options:
  --arch            CPU architecture for livepatch. arm64 and x86_64 are supported.
                    Default is x86_64.
  -c, --callbacks   .c file implementing callbacks for livepatch
                    Find templates/llpatch-callbacks.c and tweak it
  -h, --help        This help message.
  -k, --kdir        Path to kernel repository. If not specified, $CWD is used.
  -o, --odir        Path to output directory. If not specified, '/pkgs' is used.

Developer Options:  (for internal testing, not production use)
  --multi           Allow changes in multiple kmods and/or vmlinux
                    This is highly discouraged option to avoid "large" livepatch
  --skip-pkg-build  Produce livepatch-<diffname>.ko rather than livepatch package
  --slow-path       use kbuild to build llvm ir files
  --debug-dir       Dir for debugging with all intermediate files for klp generation


# generates kernel livepatch for x86_64 platform and creates binary package, 
# tarball, under ${kdir}/pkgs. ${kdir} is a path to a root of "pre-built" 
# kernel repository. If -k option is not given, CWD (Current Working Directory)
# is assumed to be ${kdir}
$ ${path_to_llpatch}/llpatch --kdir=${kdir} ${patch_file}

# generates kernel livepatch for x86_64 platform and creates binary package.
# ${callback.c} is used for the callbacks for kernel livepatch.
# Find example code under $llpatch/examples.
$ ${path_to_llpatch}/llpatch --callbacks=${callback.c} ${patch_file}

# generates kernel livepatch for arm64 platform and creates binary package, 
# tarball, under ${klp_dir}
$ ${path_to_llpatch}/llpatch --arch=arm64 --odir=${klp_dir} ${patch_file}

Semi-Automatic Livepatch Generation (Advanced)

Upstream kernel livepatch provides a way to implement custom callback functions, (post|pre)-(patch|unpatch). The callbacks can be called before/after the livepatch gets applied/reverted. If some actions should take place before/after patching/unpatching, the callback can be implemented and passed to Linux kernel. Please see the following steps for the callback implementation.

# create livepatch wrapper, livepatch.c, under ${OUT_DIR}
$ llpatch --skip-pkg-build --odir=${OUT_DIR} ${PATCH_FILE}

# once the wrapper is generated, edit ${OUT_DIR}/(${KMOD}|vmlinux)/livepatch.c
# to implement the callbacks.

# with the callbacks implemented in livepatch.c, next step is to build livepatch
$ cd ${OUT_DIR}/(${KMOD}|vmlinux)
$ make CLANG=1 LLVM=1

# create RELA sections for kernel livepatch.
$ livepatch fixup --rela ${OUT_DIR}/(${KMOD}|vmlinux)/${LIVEPACH}.ko

# create package for the livepatch.
# KERNEL_RELEASE="$(strings "init/version.o" | awk '/^Linux version/ { print $3 }')"
$ create-package ${OUT_DIR}/(${KMOD}|vmlinux)/${LIVEPATCH}.ko \
    --buildinfo=${OUT_DIR}/(${KMOD}|vmlinux)/buildinfo \
    --patch=${OUT_DIR}/(${KMOD}|vmlinux)/klp_test_meminfo.patch  \
    --output=kernelpatch-${PATCH_FILE_NAME}-${KERNEL_RELEASE}.${CPU_ARCH}.msvp.tar.xz

Semi-Automatic Livepatch Generation for Multiple Kernel Modules (Advanced)

'llpatch' provides a way to manually generate kernel livepatch patching vmlinux and/or several kernel modules. For the livepatch generation, two steps are required.

Step1: generate kernel livepatches for the .patch files with '--skip-pkg-build' option.

Step2: merge the generated kernel livepatches.

The following shows list of commands and their options for the livepatch generation.

# Step1: generate kernel livepatches. Assuming that each patches modifies a single
#        ${KMOD} or vmlinux.
$ ${path_to_llpatch}/llpatch --skip-pkg-build ${patch_file_1} -o ${livepatch_1}
$ ${path_to_llpatch}/llpatch --skip-pkg-build ${patch_file_2} -o ${livepatch_2}
...
$ ${path_to_llpatch}/llpatch --skip-pkg-build ${patch_file_n} -o ${livepatch_n}

# Step2: merge kernel livepatches and put package binary under ${livepatch}
$ ${path_to_llpatch}/llpatch-merge -n ${name_of_livepatch} -o ${livepatch} \
      ${livepatch_1}/${KMOD1} ${livepatch_2}/${KMOD2} ... ${livepatch_n}/${KMODn}

Debug Kernel Livepatch Generation (Advanced)

LLpatch can generate lots of useful files to help debugging the livepatch generation. To this end, LLpatch implements --debug-dir option.

$ llpatch --debug-dir ${DEBUG_DIR} ${PATCH_FILE}

With the --debug-dir option, LLpatch generates couple of files and directories to help understanding on livepatch generation. See the following.

${DEBUG_DIR}/
├── llpatch.cmds
├── obj_patched_map.txt
├── ${PATH_TO_PATCHED_SRCS}
│   ├──  ${PATCHED_C_FILE}.c__klp_diff.ll
│   ├──  ${PATCHED_C_FILE}__original.c
│   ├──  ${PATCHED_C_FILE}__original.c__aligned
│   ├──  ${PATCHED_C_FILE}__original.ll
│   ├──  ${PATCHED_C_FILE}__patched.c
│   ├──  ${PATCHED_C_FILE}__patched.c__aligned
│   └──  ${PATCHED_C_FILE}__patched.ll
└── ${KMOD}|vmlinux
    ├──  buildinfo
    ├──  klp_patch.o
    ├──  klp_patch.o.bak
    ├──  ${PATCH_FILE}
    ├──  livepatch.c
    ├──  livepatch.lds
    └──  Makefile

'llpatch.cmds' contains list of commands that 'llpatch' ran for livepatch generation. 'obj_patched_map.txt' shows what kernel modules changes which .c files. When it comes to ${FILE}__original.c, it is a original kernel code while ${FILE}__patched.c is a file w/ .patch file applied. ${FILE}*__aligned is an output file of 'livepatch align' command for ${FILE}.c. ${FILE}.c__klp_diff.ll contains LLVM codes that distills difference between original and patched code.

Notes

Please be advised that kernel livepatch could not handle all corner cases automatically when patching linux kernel. (e.g., livepatched function A and B have dependencies between them) So, please test your kernel livepatch before deploying it to real production environment. Please be warned for possible kernel crash.

llpatch's People

Contributors

bwendling avatar swine avatar yonghyun-hwang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

llpatch's Issues

Seeking clarification on generating a live patch with LLpatch

Hi,

I have been trying to use LLpatch for creating live patches. However, I am having some issues making it work, probably because my setup/understanding is not correct. Therefore, I was wondering if you could kindly help me clarify a few of my confusions listed below.

Which compiler to use for building LLpatch?

The README states that LLpatch is implemented in C++ and Bash scripts and that the prerequisite for C++ is clang++. However, the Makefile indicates that if the compiler is not specified, CC = gcc and CXX = g++. Does this mean it is supposed to work with g++ as well?

Which compiler to use for building Linux?

I find it a bit unclear. The README mentions that as long as 'clang' is available for the architecture and the Linux kernel can be compiled with 'clang', LLpatch should work. It also says that LLpatch assumes the Linux kernel is already built. Does this essentially mean that the kernel should be built with clang first, and not gcc? This thread says that in principle, this should work with gcc-built kernels, but it's not recommended. Anyway, I tried building Linux v6.4 with gcc v8.3.0 and LLpatch with LLVM v17.0.6, and got the following error.

llpatch[ OK |12/05 02:40]:: Aligning is done
llpatch[INFO|12/05 02:40]:: Building LLVM IR files for the 'original'
/tmp/livepatch.OXuw6hP07K/block/bdev.c
cc1: error: output filename specified twice 

Does both compilers need to be the same?

The answers to the previous two questions might already cover this, but I wanted to ask for clarification: Is it necessary to use the same compiler for building both Linux and LLpatch?

What should be the compiler version/s?

If I need to use the same compiler for both Linux and LLpatch, which versions of it can I use? Do I need to use the same version of the compiler for both Linux and LLpatch?

What versions of Linux kernels are required?

Are there any version restrictions on the Linux kernel that we intend to patch and the kernel for the host OS? Do they need to be the same, i.e., does LLpatch require the target kernel to be running to generate a live patch for it?

I tried to create a live patch for the kernel v5.15 and got the following error, where both LLpatch and kernel was built with LLVM v17.0.6.

llpatch[ OK |12/05 02:26]:: Livepatch is ready to be packaged.
llpatch[INFO|12/05 02:26]:: Building kernel livepatch
llpatch[INFO|12/05 02:26]:: Build livepatch.o and resolve LLPatch symbols
make: Entering directory '/data00/mehrab/livepatch/linux'
  CC [M]  /tmp/livepatch.Fg34H9yfZY/vmlinux/livepatch.o
make: Leaving directory '/data00/mehrab/livepatch/linux'
cat: '*.thin': No such file or directory

However, for kernel v6.4, I get a different error. Is it because v6.4 generates vmlinux.a, whereas v5.15 does not?

llpatch[ OK |12/04 23:35]:: Computing diffs is done
llpatch[INFO|12/04 23:35]:: Building LLVM IR diff files
/tmp/livepatch.aOF8WokHWD/block/bdev.c__klp_diff.ll
clang-17: error: argument unused during compilation: '-MMD' [-Werror,-Wunused-command-line-argument]
clang-17: error: argument unused during compilation: '-MF block/.bdev.o.d' [-Werror,-Wunused-command-line-argument]
clang-17: error: argument unused during compilation: '-I ./arch/x86/include' [-Werror,-Wunused-command-line-argument]
clang-17: error: argument unused during compilation: '-I ./arch/x86/include/generated' [-Werror,-Wunused-command-line-argument]
clang-17: error: argument unused during compilation: '-I ./include' [-Werror,-Wunused-command-line-argument]
clang-17: error: argument unused during compilation: '-I ./arch/x86/include/uapi' [-Werror,-Wunused-command-line-argument]
clang-17: error: argument unused during compilation: '-I ./arch/x86/include/generated/uapi' [-Werror,-Wunused-command-line-argument]
clang-17: error: argument unused during compilation: '-I ./include/uapi' [-Werror,-Wunused-command-line-argument]
clang-17: error: argument unused during compilation: '-I ./include/generated/uapi' [-Werror,-Wunused-command-line-argument]
clang-17: error: argument unused during compilation: '-include ./include/linux/compiler-version.h' [-Werror,-Wunused-command-line-argument]
clang-17: error: argument unused during compilation: '-include ./include/linux/kconfig.h' [-Werror,-Wunused-command-line-argument]
clang-17: error: argument unused during compilation: '-include ./include/linux/compiler_types.h' [-Werror,-Wunused-command-line-argument]
clang-17: error: argument unused during compilation: '-fmacro-prefix-map=./=' [-Werror,-Wunused-command-line-argument]
clang-17: error: argument unused during compilation: '-I block' [-Werror,-Wunused-command-line-argument]
livepatch-compile[ERR |12/04 23:35]:: trap at line: 218, with error:1.
livepatch-compile[ERR |12/04 23:35]:: trap at line: 1, with error:1.
llpatch[ERR |12/04 23:35]:: trap at line: 154, with error:1.
llpatch[ERR |12/04 23:35]:: trap at line: 1, with error:1.

I used the following command to run llpatch.

LLpatch/llpatch --kdir=path_to_linux_source block.patch

The block.patch file looks like the following.

diff --git a/block/bdev.c b/block/bdev.c
index 21c63bfef323..495da805eb3e 100644
--- a/block/bdev.c
+++ b/block/bdev.c
@@ -86,6 +86,7 @@ void invalidate_bdev(struct block_device *bdev)
                lru_add_drain_all();    /* make sure all lru add caches are flushed */
                invalidate_mapping_pages(mapping, 0, -1);
        }
+       printk("Patched function: invalidate_bdev\n");
 }
 EXPORT_SYMBOL(invalidate_bdev);

Specifications

  • LLpatch version: Commit 262113a
  • Host OS: Debian GNU/Linux 10 (buster)

The answers to these questions are probably straightforward and obvious. However, since I failed to make it work, I started asking myself these simple questions. I would greatly appreciate it if you could kindly help me with some clarifications to clear my confusions.

Thanks,
Mehrab

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.