Skip to content

Commit

Permalink
Merge pull request #3 from yonghyun-hwang/main
Browse files Browse the repository at this point in the history
1) update README, add example code, 2) generate txt for thin archive under corresponding kmod and vmlinux dir
  • Loading branch information
swine committed Sep 2, 2021
2 parents 6ffa816 + b8a15fe commit 262113a
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 29 deletions.
64 changes: 39 additions & 25 deletions README.md
Expand Up @@ -21,16 +21,32 @@ These are important benefits:
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. **Slim Livepatch**: LLpatch uses 'llvm-diff' to perform the diffing and generates LLVM IR
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.

3. **Better Checking and Validation**: LLVM IR contains much more information than ELF
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.)

4. **Semi-Automatic Livepatch Generation and Easy Debugging**
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
Expand All @@ -42,15 +58,7 @@ These are important benefits:
generation doesn't go through smoothly, developer can have enough information for
reproducing and debugging the bug.

5. **Ultra-Fast Livepatch Generation and Unchanged Kernel Repository**
+ LLpatch doesn't require special compiler options for the diffing. So, kernel doesn't
need to be re-compiled differently.
+ Assuming that kernel repository is already built, LLpatch parses .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 few
seconds.

6. **Handling Duplicate Symbol Names**
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.

Expand Down Expand Up @@ -88,7 +96,7 @@ source codes for LLpatch uses c++17 standard. Hence, please install clang

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

- Ubuntu: llvm-11-dev
- ...
Expand Down Expand Up @@ -200,18 +208,20 @@ 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.
-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
--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,
Expand All @@ -220,6 +230,10 @@ Developer Options: (for internal testing, not production use)
# 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}
Expand Down
114 changes: 114 additions & 0 deletions examples/llpatch-callback-shadow-var.c
@@ -0,0 +1,114 @@
/*
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author: Yonghyun Hwang <yonghyun@google.com>
*/
/*
* This file implements example code to show
*
* 1) how to implement callbacks for kernel livepatch,
*
* 2) how to access global variables defined in kernel module or vmlinux.
*
* For more details, refer to ${llpatch}/templates/llpatch.h and
* ${llpatch}/templates/llpatch-callbacks.c
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/livepatch.h>

#include "llpatch.h"

typedef char c_array_t[PAGE_SIZE];

// c_array_t: type of global variable defined in kernel module
// apple_fruit: alias to the variable
// kernel/livepatch/test/test-attr-apple.c: path to the file w/ the variable
// fruit: name of variable in the file for the kernel module
LLPATCH_DECLARE_SYMBOL(c_array_t, apple_fruit,
kernel/livepatch/test/test-attr-apple.c, fruit);

LLPATCH_DECLARE_SYMBOL(
c_array_t, banana_fruit,
kernel/livepatch/test/test-attr-banana.c, fruit);

#define SHADOW_DATA_ID 1

/* Executed on object patching (ie, patch enablement) */
static int pre_patch_callback(struct klp_object *obj)
{
char *shadow_apple, *shadow_banana;

pr_info("\nAccessing llpatch symbol in %s\n", __func__);

pr_info("apple_fruit is %s at %p\n",
LLPATCH_SYMBOL(apple_fruit),
LLPATCH_SYMBOL(apple_fruit));
pr_info("banana_fruit is %s at %p\n",
LLPATCH_SYMBOL(banana_fruit),
LLPATCH_SYMBOL(banana_fruit));

/*
* @obj: pointer to parent object
* @id: data identifier
* @size: size of attached data
* @gfp_flags: GFP mask for allocation
* @ctor: custom constructor to initialize the shadow data (optional)
* @ctor_data: pointer to any data needed by @ctor (optional)
*/
shadow_apple = klp_shadow_alloc(/*obj*/LLPATCH_SYMBOL(apple_fruit),
/*id*/SHADOW_DATA_ID,
/*size*/sizeof(c_array_t),
/*gfp_flags*/GFP_KERNEL,
/*ctor*/NULL, /*ctor_data*/NULL);
strcpy(shadow_apple, "Pink Lady");
pr_info("shadow for apple is added\n");

shadow_banana = klp_shadow_alloc(/*obj*/LLPATCH_SYMBOL(banana_fruit),
/*id*/SHADOW_DATA_ID,
/*size*/sizeof(c_array_t),
/*gfp_flags*/GFP_KERNEL,
/*ctor*/NULL, /*ctor_data*/NULL);
strcpy(shadow_banana, "Plantain");
pr_info("shadow for banana is added\n");

pr_info("Done in %s\n\n", __func__);

return 0;
}

/* Executed after object patching */
static void post_patch_callback(struct klp_object *obj)
{
}

/* Executed on object unpatching */
static void pre_unpatch_callback(struct klp_object *obj)
{
}

/* Executed after object unpatching */
static void post_unpatch_callback(struct klp_object *obj)
{
pr_info("\nAccessing llpatch symbol in %s\n", __func__);

pr_info("freeing shadow data for apple at %p\n", LLPATCH_SYMBOL(apple_fruit));
klp_shadow_free(LLPATCH_SYMBOL(apple_fruit), SHADOW_DATA_ID, NULL);

pr_info("freeing shadow data for banana at %p\n", LLPATCH_SYMBOL(banana_fruit));
klp_shadow_free(LLPATCH_SYMBOL(banana_fruit), SHADOW_DATA_ID, NULL);

pr_info("Done in %s\n\n", __func__);
}
5 changes: 3 additions & 2 deletions llpatch
Expand Up @@ -581,7 +581,8 @@ function generate_thin_archive_txt()
return 0
fi

local -r __THIN_ARCHIVE_TXT="${G_TMP_DIR}/$(basename "${__THIN_ARCHIVE}").${G_SUFFIX_TAR}"
local -r __KLP_OBJ_ROOT="$(get_klp_obj_root "${__OBJ_PARENT}")"
local -r __THIN_ARCHIVE_TXT="${__KLP_OBJ_ROOT}/$(basename "${__THIN_ARCHIVE}").${G_SUFFIX_TAR}"
if [[ -f ${__THIN_ARCHIVE_TXT} ]]; then
eval "${__RETVAL}"="${__THIN_ARCHIVE_TXT}"
return 0
Expand Down Expand Up @@ -885,7 +886,7 @@ function package_build()
util::log_info "Build ${LIVEPATCH_OBJ} and resolve LLPatch symbols"
run_command "${BUILD_COMMAND[@]}" -C "${G_KDIR}" "${LIVEPATCH_OBJ}"

cat "${G_TMP_DIR}/"*".${G_SUFFIX_TAR}" >| "${G_TMP_TAR_FILE}"
cat *".${G_SUFFIX_TAR}" >| "${G_TMP_TAR_FILE}"
run_command "${G_LIVEPATCH_BIN}" fixup -q \
--symbol_map="${KLP_OBJ_ROOT}/${G_LLPATCH_SYMBOL_MAP_FILE}" \
--thin_archive="${G_TMP_TAR_FILE}" \
Expand Down
7 changes: 5 additions & 2 deletions llpatch-merge
Expand Up @@ -488,8 +488,11 @@ function build_livepatch()

run_command "${BUILD_COMMAND[@]}" -C "${G_KDIR}" "${LIVEPATCH_OBJ}"

# TODO: we need thin archive files here. need to add a new option to get dir for thin archives
>| "${G_TMP_TAR_FILE}"
local klp_dir=""
for klp_dir in ${G_KLP_DIRS[@]}; do
cat "${klp_dir}/"*".${G_SUFFIX_TAR}"
done >| "${G_TMP_TAR_FILE}"

run_command "${G_LIVEPATCH_BIN}" fixup -q \
--symbol_map="${G_TMP_DIR}/${G_LLPATCH_SYMBOL_MAP_FILE}" \
--thin_archive="${G_TMP_TAR_FILE}" \
Expand Down
7 changes: 7 additions & 0 deletions templates/README
Expand Up @@ -11,5 +11,12 @@ livepatch. There are three files under this directory.
3) Makefile.tmpl
- makefile to build kernel livepatch.

4) llpatch.h
- defines macro for LLpatch symbols

5) llpatch-callbacks.c
- implements default callbacks for kernel livepatch
- this can be tweaked to implement customized callbacks

Each template contains {{MARKER}} in it hoping that they are replaced by
either `llpatch` or `livepatch gen` command.

0 comments on commit 262113a

Please sign in to comment.