Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RHEL好きの集い vol2.1 kpatchの深堀り

Avatar for OMO OMO
December 20, 2019

RHEL好きの集い vol2.1 kpatchの深堀り

RHEL好きの集い vol2.1でのkpatchの動作を解説した資料です。

Avatar for OMO

OMO

December 20, 2019
Tweet

More Decks by OMO

Other Decks in Technology

Transcript

  1. ftraceの動きを見てみる [root@rhel81 ~]# cat /sys/kernel/debug/tracing/available_tracers hwlat blk function_graph wakeup_dl wakeup_rt

    wakeup function nop /sys/kernel/debug/tracing/current_tracer [root@rhel81 ~]# echo 1 > /sys/kernel/debug/tracing/tracing_on [root@rhel81 ~]# ls anaconda-ks.cfg initial-setup-ks.cfg kpatch.log [root@rhel81 ~]# pwd /root [root@rhel81 ~]# echo 0 > /sys/kernel/debug/tracing/tracing_on
  2. ftraceの動きを見てみる [root@rhel81 ~]# cat /sys/kernel/debug/tracing/trace_pipe > trace.log [root@rhel81 ~]# cat

    trace.log ------------------------------ CPU:0 [LOST 2183845 EVENTS] pool-2670 [000] .... 348.077183: selinux_file_permission <-security_file_permission pool-2670 [000] .... 348.077184: __inode_security_revalidate <-selinux_file_permission pool-2670 [000] .... 348.077184: _cond_resched <-__inode_security_revalidate pool-2670 [000] .... 348.077184: rcu_all_qs <-_cond_resched pool-2670 [000] .... 348.077184: file_has_perm <-security_file_permission pool-2670 [000] .... 348.077184: bpf_fd_pass <-file_has_perm pool-2670 [000] .... 348.077184: inode_has_perm.isra.43 <-file_has_perm 成る程。 関数のTraceとか出来るのね。
  3. /samples/livepatch/livepatch-sample.c static struct klp_func funcs[] = { { .old_name =

    "cmdline_proc_show", .new_func = livepatch_cmdline_proc_show, }, { } }; static struct klp_object objs[] = { { /* name being NULL means vmlinux */ .funcs = funcs, }, { } }; static struct klp_patch patch = { .mod = THIS_MODULE, .objs = objs, };
  4. include/linux/livepatch.h : klp_func構造体) include/linux/livepatch.h : klp_func構造体) /** * struct klp_func

    - function structure for live patching * @old_name: name of the function to be patched * @new_func: pointer to the patched function code * @old_sympos: a hint indicating which symbol position the old function * can be found (optional) * @old_func: pointer to the function being patched * @kobj: kobject for sysfs resources * @node: list node for klp_object func_list * @stack_node: list node for klp_ops func_stack list * @old_size: size of the old function * @new_size: size of the new function ...
  5. include/linux/livepatch.h : klp_object構造体 /** * struct klp_object - kernel object

    structure for live patching * @name: module name (or NULL for vmlinux) * @funcs: function entries for functions to be patched in the object * @callbacks: functions to be executed pre/post (un)patching * @kobj: kobject for sysfs resources * @func_list: dynamic list of the function entries * @node: list node for klp_patch obj_list * @mod: kernel module associated with the patched object * (NULL for vmlinux) * @dynamic: temporary object for nop functions; dynamically allocated * @patched: the object's funcs have been added to the klp_ops list */ struct klp_object { /* external */ const char *name;
  6. include/linux/livepatch.h : klp_patch構造体 /** * struct klp_patch - patch structure

    for live patching * @mod: reference to the live patch module * @objs: object entries for kernel objects to be patched * @replace: replace all actively used patches * @list: list node for global list of actively used patches * @kobj: kobject for sysfs resources * @obj_list: dynamic list of the object entries * @enabled: the patch is enabled (but operation may be incomplete) * @forced: was involved in a forced transition * @free_work: patch cleanup from workqueue-context * @finish: for waiting till it is safe to remove the patch module */ struct klp_patch {
  7. kernel/livepatch/core.c static int __init klp_init(void) { klp_root_kobj = kobject_create_and_add("livepatch", kernel_kobj);

    if (!klp_root_kobj) return -ENOMEM; return 0; } module_init(klp_init); モジュールの初期化
  8. klp_enable_patch static int __klp_enable_patch(struct klp_patch *patch) { ---snip--- /* *

    Enforce the order of the func->transition writes in * klp_init_transition() and the ops->func_stack writes in * klp_patch_object(), so that klp_ftrace_handler() will see the * func->transition updates before the handler is registered and the * new funcs become visible to the handler. */ ---snip--- ret = klp_patch_object(obj); if (ret) {
  9. klp_patch_func static int klp_patch_func(struct klp_func *func) { ---snip--- ops =

    klp_find_ops(func->old_func); if (!ops) { unsigned long ftrace_loc; ftrace_loc = klp_get_ftrace_location((unsigned long)func->old_func); #ifndef klp_get_ftrace_location static unsigned long klp_get_ftrace_location(unsigned long faddr) { return faddr; } #endif
  10. klp_ftrace_handler static void notrace klp_ftrace_handler(unsigned long ip, (略) { --snip--

    /* * NOPs are used to replace existing patches with original code. * Do nothing! Setting pc would cause an infinite loop. */ if (func->nop) goto unlock; klp_arch_set_pc(regs, (unsigned long)func->new_func); --------------------- static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip) { regs->ip = ip; }
  11. kpatchとlivepatch sios@localhost:~/SIOS/RHEL/kpatch/tmp/patch$ ls Makefile kpatch-patch-hook.c kpatch.lds.S livepatch-test.mod.o patch-hook.c Module.symvers kpatch-patch.h

    livepatch-patch-hook.c livepatch-test.o patch-hook.o built-in.o kpatch.h livepatch-test.ko modules.order tmp.ko kpatch-macros.h kpatch.lds livepatch-test.mod.c output.o tmp_output.o
  12. kpatchでpatchが作れないケース 1. データ構造の変更とか (kpatchはあくまでも”関数”を対象) https://github.com/dynup/kpatch/blob/master/doc/patch-author-guide.md “kpatch patches functions, not data.

    If the original patch involves a change to a data structure, the patch will require some rework, as changes to data structures are not allowed by default.”
  13. kpatchでpatchが作れないケース 2. データセマンティックの変更 (shadow variable(kpatchの変数)の追加とか) https://github.com/dynup/kpatch/blob/master/doc/patch-author-guide.md diff --git a/fs/aio.c b/fs/aio.c

    index ebd06fd0de89..6a33b73c9107 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -280,6 +280,8 @@ static void free_ioctx_rcu(struct rcu_head *head) * and ctx->users has dropped to 0, so we know no more kiocbs can be submitted - * now it's safe to cancel any that need to be. */ +#include <linux/livepatch.h> +#define KPATCH_SHADOW_REQS_ACTIVE_V2 1
  14. kpatchモジュールの作成 [root@cent7 work]# kpatch-build -t vmlinux /root/test.patch Using cache at

    /root/.kpatch/src Testing patch file(s) Reading special section data Building original source Building patched source Extracting new and modified ELF sections read_write.o: changed function: vfs_write read_write.o: changed function: vfs_read namespace.o: changed function: do_mount read_write.o: changed function: vfs_write read_write.o: changed function: vfs_read namespace.o: changed function: do_mount Patched objects: vmlinux Building patch module: livepatch-test.ko SUCCESS
  15. kpatchモジュールの作成とロード [root@cent7 work]# ls livepatch-test.ko [root@cent7 work]# kpatch load livepatch-test.ko

    loading patch module: livepatch-test.ko waiting (up to 15 seconds) for patch transition to complete... patch transition has stalled! signaling stalled process(es): waiting (up to 60 seconds) for patch transition to complete... transition complete (1 seconds) kpatchモジュール
  16. kpatchモジュールのロード dmesg ) [ 1176.794796] livepatch: enabling patch 'livepatch_test' [

    1176.881381] livepatch: 'livepatch_test': starting patching transition [ 1192.031557] livepatch: signaling remaining tasks [ 1192.381182] livepatch: 'livepatch_test': patching complete コマンドだと(kpatch list) [root@cent7 work]# kpatch list Loaded patch modules: livepatch_test [enabled] Installed patch modules:
  17. kpatchモジュールのアンロード [root@cent7 work]# kpatch unload livepatch_test disabling patch module: livepatch_test

    waiting (up to 15 seconds) for patch transition to complete... patch transition has stalled! signaling stalled process(es): waiting (up to 60 seconds) for patch transition to complete... transition complete (1 seconds) unloading patch module: livepatch_test [root@cent7 work]# kpatch list Loaded patch modules: Installed patch modules: [root@cent7 work]#
  18. RHのkpatchモジュールの適用 普通にrpmコマンドでOK [root@rhel77 ~]# rpm -ivh /home/sios/rhel77/kpatch-patch-3_10_0-1062-1-1.el7.x86_64.rpm 警告: /home/sios/rhel77/kpatch-patch-3_10_0-1062-1-1.el7.x86_64.rpm: ヘッダー

    V3 RSA/SHA256 Signature、鍵 ID fd431d51: NOKEY 準備しています... ################################# [100%] 更新中 / インストール中... 1:kpatch-patch-3_10_0-1062-1-1.el7 ################################# [100%] loading patch module: /usr/lib/kpatch/3.10.0-1062.el7.x86_64/kpatch-3_10_0-1062-1-1.ko installing /usr/lib/kpatch/3.10.0-1062.el7.x86_64/kpatch-3_10_0-1062-1-1.ko (3.10.0-1062.el7.x86_64) [root@rhel77 ~]# ls /usr/lib/kpatch/3.10.0-1062.el7.x86_64/ kpatch-3_10_0-1062-1-1.ko
  19. RHのkpatchモジュールの適用 kpatchがロードされています。 [root@rhel77 ~]# kpatch list Loaded patch modules: kpatch_3_10_0_1062_1_1

    [enabled] Installed patch modules: kpatch_3_10_0_1062_1_1 (3.10.0-1062.el7.x86_64) (ちなみに再起動してもロードされます。 「再起動は許すがkernelのバージョンはミドルウェアのサポートの関係で変更できない」 という環境には有用。)
  20. Q&A