From 3d04265899c3b81bd47b1ace8896eef092e6e379 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Fri, 18 May 2018 14:55:25 -0500 Subject: [PATCH] create-klp-module: Properly align merged .parainstructions sections When a patch is composed of multiple .o files which have .parainstructions sections, loading the patch causes a panic: general protection fault: 0000 [#1] SMP Modules linked in: livepatch_4_9_88_1_20180518_1(OK+) livepatch_4_9_88_1_20180510_1(OK) ... CPU: 1 PID: 17257 Comm: insmod Tainted: G O K 4.9.0-6-amd64 #1 Debian 4.9.88-1 Hardware name: HP ProLiant MicroServer Gen8, BIOS J06 11/02/2015 task: ffff9ff3411a4480 task.stack: ffffac8f8271c000 RIP: 0010:[] [] apply_paravirt+0xc0/0x140 RSP: 0018:ffffac8f8271f9a0 EFLAGS: 00010216 RAX: 00010749ffffffff RBX: ffffffffc0940658 RCX: 0000000000000085 RDX: 00000000bfebfbff RSI: ffffac8f8271f9a2 RDI: 0000000000000246 RBP: ffffac8f8271f9a2 R08: 0000000000000085 R09: ffffffff8ae5acb0 R10: 0000000000000001 R11: ffff9ff3544b4400 R12: ffffffffc0940660 R13: 0000000000000000 R14: ffff9ff3544b49c0 R15: ffff9ff3b43f0800 FS: 00007f04c1cea700(0000) GS:ffff9ff3ca640000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000560cfd63e460 CR3: 00000001455c6000 CR4: 0000000000160670 Stack: 401f0ff889486973 6172007172006b00 746c00650031312e 007265746e655f69 74006e6f69007870 ffffac8f006e6f69 00ffac8f8271fa28 ffffffff8b13ae86 ffffac8f8271fa68 ffffffffc09471ec ffffffff8b7da9eb 0000000affffffff Call Trace: [] ? vsscanf+0x4c6/0x800 [] ? sscanf+0x4e/0x70 [] ? arch_klp_init_object_loaded+0x105/0x130 [] ? vsscanf+0x6fe/0x800 [] ? sscanf+0x4e/0x70 [] ? klp_init_object_loaded+0xf8/0x210 [] ? klp_register_patch+0x285/0x390 [] ? patch_init+0x1fa/0x1000 [livepatch_4_9_88_1_20180518_1] [] ? 0xffffffffc0949000 [] ? do_one_initcall+0x4e/0x180 [] ? __vunmap+0x6d/0xc0 [] ? __vunmap+0x6d/0xc0 [] ? do_init_module+0x5b/0x1ed [] ? load_module+0x2596/0x2ab0 [] ? __symbol_put+0x60/0x60 [] ? SYSC_finit_module+0xc6/0xf0 [] ? do_syscall_64+0x8d/0xf0 [] ? entry_SYSCALL_64_after_swapgs+0x58/0xc6 Code: 8d 7c 05 00 e8 62 f7 ff ff 0f b6 53 f9 48 8b 7b f0 48 89 ee e8 f2 f8 ff ff 49 39 dc 76 57 44 0f b6 43 09 41 80 f8 ff 75 84 0f 0b <48> 8b 10 48 8d 7d 08 48 83 e7 f8 48 89 55 00 89 ca 48 8b 74 10 RIP [] apply_paravirt+0xc0/0x140 RSP ---[ end trace 128c0fa6efe85d9e ]--- The panic is caused by a corrupt .klp.arch.vmlinux..parainstructions section: Relocation section [208] '.rela.klp.arch.vmlinux..parainstructions' for section [207] '.klp.arch.vmlinux..parainstructions' at offset 0x29dc78 contains 10 entries: Offset Type Value Addend Name 000000000000000000 X86_64_64 000000000000000000 +750 __get_user_pages 0x0000000000000010 X86_64_64 000000000000000000 +823 __get_user_pages 0x0000000000000020 X86_64_64 000000000000000000 +890 __get_user_pages 0x0000000000000030 X86_64_64 000000000000000000 +941 __get_user_pages 0x0000000000000040 X86_64_64 000000000000000000 +1631 __get_user_pages 0x0000000000000050 X86_64_64 000000000000000000 +1671 __get_user_pages 0x000000000000005c X86_64_64 000000000000000000 +1245 handle_userfault 0x000000000000006c X86_64_64 000000000000000000 +1340 handle_userfault 0x000000000000007c X86_64_64 000000000000000000 +1417 handle_userfault 0x000000000000008c X86_64_64 000000000000000000 +1717 handle_userfault The entries are supposed to be 16 bytes each, but notice they become misaligned starting with the 'handle_userfault' entry. This happens because the kernel linking process lies about the .parainstructions section size, underreporting it by four bytes. So when two .parainstructions sections are merged together, it results in a corrupted .klp.arch.vmlinux..parainstructions section. Fix it by properly aligning the section before merging it with another one. Fixes #852. Signed-off-by: Josh Poimboeuf --- kpatch-build/create-klp-module.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/kpatch-build/create-klp-module.c b/kpatch-build/create-klp-module.c index b3dbaef..00f8f8f 100644 --- a/kpatch-build/create-klp-module.c +++ b/kpatch-build/create-klp-module.c @@ -292,6 +292,27 @@ static void create_klp_arch_sections(struct kpatch_elf *kelf, char *strings) * single .klp.arch.vmlinux..parainstructions section */ old_size = sec->data->d_size; + + /* + * Due to a quirk in how .parainstructions gets linked, the + * section size doesn't encompass the last 4 bytes of the last + * entry. Align the old size properly before merging. + */ + if (!strcmp(base->name, ".parainstructions")) { + char *str; + static int align_mask = 0; + + if (!align_mask) { + str = getenv("PARA_STRUCT_SIZE"); + if (!str) + ERROR("PARA_STRUCT_SIZE not set"); + + align_mask = atoi(str) - 1; + } + + old_size = (old_size + align_mask) & ~align_mask; + } + new_size = old_size + base->data->d_size; sec->data->d_buf = realloc(sec->data->d_buf, new_size); sec->data->d_size = new_size;