1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Read the intermediate KLP reloc/symbol representations created by klp diff 4 * and convert them to the proper format required by livepatch. This needs to 5 * run last to avoid linker wreckage. Linkers don't tend to handle the "two 6 * rela sections for a single base section" case very well, nor do they like 7 * SHN_LIVEPATCH. 8 * 9 * This is the final tool in the livepatch module generation pipeline: 10 * 11 * kernel builds -> objtool klp diff -> module link -> objtool klp post-link 12 */ 13 14 #include <fcntl.h> 15 #include <gelf.h> 16 #include <objtool/objtool.h> 17 #include <objtool/warn.h> 18 #include <objtool/klp.h> 19 #include <objtool/util.h> 20 #include <linux/livepatch_external.h> 21 22 static int fix_klp_relocs(struct elf *elf) 23 { 24 struct section *symtab, *klp_relocs; 25 26 klp_relocs = find_section_by_name(elf, KLP_RELOCS_SEC); 27 if (!klp_relocs) 28 return 0; 29 30 symtab = find_section_by_name(elf, ".symtab"); 31 if (!symtab) { 32 ERROR("missing .symtab"); 33 return -1; 34 } 35 36 for (int i = 0; i < sec_size(klp_relocs) / sizeof(struct klp_reloc); i++) { 37 struct klp_reloc *klp_reloc; 38 unsigned long klp_reloc_off; 39 struct section *sec, *tmp, *klp_rsec; 40 unsigned long offset; 41 struct reloc *reloc; 42 char sym_modname[64]; 43 char rsec_name[SEC_NAME_LEN]; 44 u64 addend; 45 struct symbol *sym, *klp_sym; 46 47 klp_reloc_off = i * sizeof(*klp_reloc); 48 klp_reloc = klp_relocs->data->d_buf + klp_reloc_off; 49 50 /* 51 * Read __klp_relocs[i]: 52 */ 53 54 /* klp_reloc.sec_offset */ 55 reloc = find_reloc_by_dest(elf, klp_relocs, 56 klp_reloc_off + offsetof(struct klp_reloc, offset)); 57 if (!reloc) { 58 ERROR("malformed " KLP_RELOCS_SEC " section"); 59 return -1; 60 } 61 62 sec = reloc->sym->sec; 63 offset = reloc_addend(reloc); 64 65 /* klp_reloc.sym */ 66 reloc = find_reloc_by_dest(elf, klp_relocs, 67 klp_reloc_off + offsetof(struct klp_reloc, sym)); 68 if (!reloc) { 69 ERROR("malformed " KLP_RELOCS_SEC " section"); 70 return -1; 71 } 72 73 klp_sym = reloc->sym; 74 addend = reloc_addend(reloc); 75 76 /* symbol format: .klp.sym.modname.sym_name,sympos */ 77 if (sscanf(klp_sym->name + strlen(KLP_SYM_PREFIX), "%55[^.]", sym_modname) != 1) 78 ERROR("can't find modname in klp symbol '%s'", klp_sym->name); 79 80 /* 81 * Create the KLP rela: 82 */ 83 84 /* section format: .klp.rela.sec_objname.section_name */ 85 if (snprintf_check(rsec_name, SEC_NAME_LEN, 86 KLP_RELOC_SEC_PREFIX "%s.%s", 87 sym_modname, sec->name)) 88 return -1; 89 90 klp_rsec = find_section_by_name(elf, rsec_name); 91 if (!klp_rsec) { 92 klp_rsec = elf_create_section(elf, rsec_name, 0, 93 elf_rela_size(elf), 94 SHT_RELA, elf_addr_size(elf), 95 SHF_ALLOC | SHF_INFO_LINK | SHF_RELA_LIVEPATCH); 96 if (!klp_rsec) 97 return -1; 98 99 klp_rsec->sh.sh_link = symtab->idx; 100 klp_rsec->sh.sh_info = sec->idx; 101 klp_rsec->base = sec; 102 } 103 104 tmp = sec->rsec; 105 sec->rsec = klp_rsec; 106 if (!elf_create_reloc(elf, sec, offset, klp_sym, addend, klp_reloc->type)) 107 return -1; 108 sec->rsec = tmp; 109 110 /* 111 * Fix up the corresponding KLP symbol: 112 */ 113 114 klp_sym->sym.st_shndx = SHN_LIVEPATCH; 115 if (!gelf_update_sym(symtab->data, klp_sym->idx, &klp_sym->sym)) { 116 ERROR_ELF("gelf_update_sym"); 117 return -1; 118 } 119 120 /* 121 * Disable the original non-KLP reloc by converting it to R_*_NONE: 122 */ 123 124 reloc = find_reloc_by_dest(elf, sec, offset); 125 sym = reloc->sym; 126 sym->sym.st_shndx = SHN_LIVEPATCH; 127 set_reloc_type(elf, reloc, 0); 128 if (!gelf_update_sym(symtab->data, sym->idx, &sym->sym)) { 129 ERROR_ELF("gelf_update_sym"); 130 return -1; 131 } 132 } 133 134 return 0; 135 } 136 137 /* 138 * This runs on the livepatch module after all other linking has been done. It 139 * converts the intermediate __klp_relocs section into proper KLP relocs to be 140 * processed by livepatch. This needs to run last to avoid linker wreckage. 141 * Linkers don't tend to handle the "two rela sections for a single base 142 * section" case very well, nor do they appreciate SHN_LIVEPATCH. 143 */ 144 int cmd_klp_post_link(int argc, const char **argv) 145 { 146 struct elf *elf; 147 148 argc--; 149 argv++; 150 151 if (argc != 1) { 152 fprintf(stderr, "%d\n", argc); 153 fprintf(stderr, "usage: objtool link <file.ko>\n"); 154 return -1; 155 } 156 157 elf = elf_open_read(argv[0], O_RDWR); 158 if (!elf) 159 return -1; 160 161 if (fix_klp_relocs(elf)) 162 return -1; 163 164 if (elf_write(elf)) 165 return -1; 166 167 return elf_close(elf); 168 } 169