History

livepatch: Apply vmlinux-specific KLP relocations early

KLP relocations are livepatch-specific relocations which are applied to a KLP module's text or data. They exist for two reasons: 1) Unexported symbols: replacement functions often need to access unexported symbols (e.g. static functions), which "normal" relocations don't allow. 2) Late module patching: this is the ability for a KLP module to bypass normal module dependencies, such that the KLP module can be loaded *before* a to-be-patched module. This means that relocations which need to access symbols in the to-be-patched module might need to be applied to the KLP module well after it has been loaded. Non-late-patched KLP relocations are applied from the KLP module's init function. That usually works fine, unless the patched code wants to use alternatives, paravirt patching, jump tables, or some other special section which needs relocations. Then we run into ordering issues and crashes. In order for those special sections to work properly, the KLP relocations should be applied *before* the special section init code runs, such as apply_paravirt(), apply_alternatives(), or jump_label_apply_nops(). You might think the obvious solution would be to move the KLP relocation initialization earlier, but it's not necessarily that simple. The problem is the above-mentioned late module patching, for which KLP relocations can get applied well after the KLP module is loaded. To "fix" this issue in the past, we created .klp.arch sections: .klp.arch.{module}..altinstructions .klp.arch.{module}..parainstructions Those sections allow KLP late module patching code to call apply_paravirt() and apply_alternatives() after the module-specific KLP relocations (.klp.rela.{module}.{section}) have been applied. But that has a lot of drawbacks, including code complexity, the need for arch-specific code, and the (per-arch) danger that we missed some special section -- for example the __jump_table section which is used for jump labels. It turns out there's a simpler and more functional approach. There are two kinds of KLP relocation sections: 1) vmlinux-specific KLP relocation sections .klp.rela.vmlinux.{sec} These are relocations (applied to the KLP module) which reference unexported vmlinux symbols. 2) module-specific KLP relocation sections .klp.rela.{module}.{sec}: These are relocations (applied to the KLP module) which reference unexported or exported module symbols. Up until now, these have been treated the same. However, they're inherently different. Because of late module patching, module-specific KLP relocations can be applied very late, thus they can create the ordering headaches described above. But vmlinux-specific KLP relocations don't have that problem. There's nothing to prevent them from being applied earlier. So apply them at the same time as normal relocations, when the KLP module is being loaded. This means that for vmlinux-specific KLP relocations, we no longer have any ordering issues. vmlinux-referencing jump labels, alternatives, and paravirt patching will work automatically, without the need for the .klp.arch hacks. All that said, for module-specific KLP relocations, the ordering problems still exist and we *do* still need .klp.arch. Or do we? Stay tuned.

Josh Poimboeuf committed 6 years ago

Commit 7c8e2bd1 parent dcf550e3 files · +106 −55Browse files

Unified · Split

3 files
  1. include/linux/livepatch.h +14 −0
  2. kernel/livepatch/core.c +86 −51
  3. kernel/module.c +6 −4
include/linux/livepatch.h+14−0
@@ -234,6 +234,11 @@ void klp_shadow_free_all(unsigned long id, klp_shadow_dtor_t dtor); · 233 unmodified lines
234struct klp_state *klp_get_state(struct klp_patch *patch, unsigned long id);234struct klp_state *klp_get_state(struct klp_patch *patch, unsigned long id);
235struct klp_state *klp_get_prev_state(unsigned long id);235struct klp_state *klp_get_prev_state(unsigned long id);
236 236
237int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs,
238 const char *shstrtab, const char *strtab,
239 unsigned int symindex, unsigned int secindex,
240 const char *objname);
241
237#else /* !CONFIG_LIVEPATCH */242#else /* !CONFIG_LIVEPATCH */
238 243
239static inline int klp_module_coming(struct module *mod) { return 0; }244static inline int klp_module_coming(struct module *mod) { return 0; }
@@ -242,6 +247,15 @@ static inline bool klp_patch_pending(struct task_struct *task) { return false; } · 2 unmodified lines
242static inline void klp_update_patch_state(struct task_struct *task) {}247static inline void klp_update_patch_state(struct task_struct *task) {}
243static inline void klp_copy_process(struct task_struct *child) {}248static inline void klp_copy_process(struct task_struct *child) {}
244 249
250static inline
251int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs,
252 const char *shstrtab, const char *strtab,
253 unsigned int symindex, unsigned int secindex,
254 const char *objname)
255{
256 return 0;
257}
258
245#endif /* CONFIG_LIVEPATCH */259#endif /* CONFIG_LIVEPATCH */
246 260
247#endif /* _LINUX_LIVEPATCH_H_ */261#endif /* _LINUX_LIVEPATCH_H_ */
kernel/livepatch/core.c+86−51
@@ -191,12 +191,12 @@ static int klp_find_object_symbol(const char *objname, const char *name, · 190 unmodified lines
191 return -EINVAL;191 return -EINVAL;
192}192}
193 193
194static int klp_resolve_symbols(Elf_Shdr *relasec, struct module *pmod)194static int klp_resolve_symbols(Elf64_Shdr *sechdrs, const char *strtab,
195 unsigned int symndx, Elf_Shdr *relasec)
195{196{
196 int i, cnt, vmlinux, ret;197 int i, cnt, vmlinux, ret;
197 char objname[MODULE_NAME_LEN];198 char objname[MODULE_NAME_LEN];
198 char symname[KSYM_NAME_LEN];199 char symname[KSYM_NAME_LEN];
199 char *strtab = pmod->core_kallsyms.strtab;
200 Elf_Rela *relas;200 Elf_Rela *relas;
201 Elf_Sym *sym;201 Elf_Sym *sym;
202 unsigned long sympos, addr;202 unsigned long sympos, addr;
@@ -216,7 +216,7 @@ static int klp_resolve_symbols(Elf_Shdr *relasec, struct module *pmod) · 13 unmodified lines
216 relas = (Elf_Rela *) relasec->sh_addr;216 relas = (Elf_Rela *) relasec->sh_addr;
217 /* For each rela in this klp relocation section */217 /* For each rela in this klp relocation section */
218 for (i = 0; i < relasec->sh_size / sizeof(Elf_Rela); i++) {218 for (i = 0; i < relasec->sh_size / sizeof(Elf_Rela); i++) {
219 sym = pmod->core_kallsyms.symtab + ELF_R_SYM(relas[i].r_info);219 sym = (Elf64_Sym *)sechdrs[symndx].sh_addr + ELF_R_SYM(relas[i].r_info);
220 if (sym->st_shndx != SHN_LIVEPATCH) {220 if (sym->st_shndx != SHN_LIVEPATCH) {
221 pr_err("symbol %s is not marked as a livepatch symbol\n",221 pr_err("symbol %s is not marked as a livepatch symbol\n",
222 strtab + sym->st_name);222 strtab + sym->st_name);
@@ -246,54 +246,59 @@ static int klp_resolve_symbols(Elf_Shdr *relasec, struct module *pmod) · 23 unmodified lines
246 return 0;246 return 0;
247}247}
248 248
249static int klp_write_object_relocations(struct module *pmod,249/*
250 struct klp_object *obj)250 * At a high-level, there are two types of klp relocation sections: those which
251 * reference symbols which live in vmlinux; and those which reference symbols
252 * which live in other modules. This function is called for both types:
253 *
254 * 1) When a klp module itself loads, the module code calls this function to
255 * write vmlinux-specific klp relocations (.klp.rela.vmlinux.* sections).
256 * These relocations are written to the klp module text to allow the patched
257 * code/data to reference unexported vmlinux symbols. They're written as
258 * early as possible to ensure that other module init code (.e.g.,
259 * jump_label_apply_nops) can access any unexported vmlinux symbols which
260 * might be referenced by the klp module's special sections.
261 *
262 * 2) When a to-be-patched module loads -- or is already loaded when a
263 * corresponding klp module loads -- klp code calls this function to write
264 * module-specific klp relocations (.klp.rela.{module}.* sections). These
265 * are written to the klp module text to allow the patched code/data to
266 * reference symbols which live in the to-be-patched module or one of its
267 * module dependencies. Exported symbols are supported, in addition to
268 * unexported symbols, in order to enable late module patching, which allows
269 * the to-be-patched module to be loaded and patched sometime *after* the
270 * klp module is loaded.
271 */
272int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs,
273 const char *shstrtab, const char *strtab,
274 unsigned int symndx, unsigned int secndx,
275 const char *objname)
251{276{
252 int i, cnt, ret = 0;277 int cnt, ret;
253 const char *objname, *secname;
254 char sec_objname[MODULE_NAME_LEN];278 char sec_objname[MODULE_NAME_LEN];
255 Elf_Shdr *sec;279 Elf_Shdr *sec = sechdrs + secndx;
256 280
257 if (WARN_ON(!klp_is_object_loaded(obj)))281 /*
282 * Format: .klp.rela.sec_objname.section_name
283 * See comment in klp_resolve_symbols() for an explanation
284 * of the selected field width value.
285 */
286 cnt = sscanf(shstrtab + sec->sh_name, ".klp.rela.%55[^.]",
287 sec_objname);
288 if (cnt != 1) {
289 pr_err("section %s has an incorrectly formatted name\n",
290 shstrtab + sec->sh_name);
258 return -EINVAL;291 return -EINVAL;
292 }
259 293
260 objname = klp_is_module(obj) ? obj->name : "vmlinux";294 if (strcmp(objname ? objname : "vmlinux", sec_objname))
261 295 return 0;
262 /* For each klp relocation section */
263 for (i = 1; i < pmod->klp_info->hdr.e_shnum; i++) {
264 sec = pmod->klp_info->sechdrs + i;
265 secname = pmod->klp_info->secstrings + sec->sh_name;
266 if (!(sec->sh_flags & SHF_RELA_LIVEPATCH))
267 continue;
268
269 /*
270 * Format: .klp.rela.sec_objname.section_name
271 * See comment in klp_resolve_symbols() for an explanation
272 * of the selected field width value.
273 */
274 cnt = sscanf(secname, ".klp.rela.%55[^.]", sec_objname);
275 if (cnt != 1) {
276 pr_err("section %s has an incorrectly formatted name\n",
277 secname);
278 ret = -EINVAL;
279 break;
280 }
281
282 if (strcmp(objname, sec_objname))
283 continue;
284
285 ret = klp_resolve_symbols(sec, pmod);
286 if (ret)
287 break;
288 296
289 ret = apply_relocate_add(pmod->klp_info->sechdrs,297 ret = klp_resolve_symbols(sechdrs, strtab, symndx, sec);
290 pmod->core_kallsyms.strtab,298 if (ret)
291 pmod->klp_info->symndx, i, pmod);299 return ret;
292 if (ret)
293 break;
294 }
295 300
296 return ret;301 return apply_relocate_add(sechdrs, strtab, symndx, secndx, pmod);
297}302}
298 303
299/*304/*
@@ -730,6 +735,28 @@ void __weak arch_klp_init_object_loaded(struct klp_patch *patch, · 430 unmodified lines
730{735{
731}736}
732 737
738int klp_apply_object_relocs(struct klp_patch *patch, struct klp_object *obj)
739{
740 int i, ret;
741 struct klp_modinfo *info = patch->mod->klp_info;
742
743 for (i = 1; i < info->hdr.e_shnum; i++) {
744 Elf_Shdr *sec = info->sechdrs + i;
745
746 if (!(sec->sh_flags & SHF_RELA_LIVEPATCH))
747 continue;
748
749 ret = klp_apply_section_relocs(patch->mod, info->sechdrs,
750 info->secstrings,
751 patch->mod->core_kallsyms.strtab,
752 info->symndx, i, obj->name);
753 if (ret)
754 return ret;
755 }
756
757 return 0;
758}
759
733/* parts of the initialization that is done only when the object is loaded */760/* parts of the initialization that is done only when the object is loaded */
734static int klp_init_object_loaded(struct klp_patch *patch,761static int klp_init_object_loaded(struct klp_patch *patch,
735 struct klp_object *obj)762 struct klp_object *obj)
@@ -738,18 +765,26 @@ static int klp_init_object_loaded(struct klp_patch *patch, · 2 unmodified lines
738 int ret;765 int ret;
739 766
740 mutex_lock(&text_mutex);767 mutex_lock(&text_mutex);
741
742 module_disable_ro(patch->mod);768 module_disable_ro(patch->mod);
743 ret = klp_write_object_relocations(patch->mod, obj);769
744 if (ret) {770 if (klp_is_module(obj)) {
745 module_enable_ro(patch->mod, true);771 /*
746 mutex_unlock(&text_mutex);772 * Only write module-specific relocations here
747 return ret;773 * (.klp.rela.{module}.*). vmlinux-specific relocations were
774 * written earlier during the initialization of the klp module
775 * itself.
776 */
777 ret = klp_apply_object_relocs(patch, obj);
778 if (ret) {
779 module_enable_ro(patch->mod, true);
780 mutex_unlock(&text_mutex);
781 return ret;
782 }
748 }783 }
749 784
750 arch_klp_init_object_loaded(patch, obj);785 arch_klp_init_object_loaded(patch, obj);
751 module_enable_ro(patch->mod, true);
752 786
787 module_enable_ro(patch->mod, true);
753 mutex_unlock(&text_mutex);788 mutex_unlock(&text_mutex);
754 789
755 klp_for_each_func(obj, func) {790 klp_for_each_func(obj, func) {
kernel/module.c+6−4
@@ -2334,11 +2334,13 @@ static int apply_relocations(struct module *mod, const struct load_info *info) · 2333 unmodified lines
2334 if (!(info->sechdrs[infosec].sh_flags & SHF_ALLOC))2334 if (!(info->sechdrs[infosec].sh_flags & SHF_ALLOC))
2335 continue;2335 continue;
2336 2336
2337 /* Livepatch relocation sections are applied by livepatch */
2338 if (info->sechdrs[i].sh_flags & SHF_RELA_LIVEPATCH)2337 if (info->sechdrs[i].sh_flags & SHF_RELA_LIVEPATCH)
2339 continue;2338 err = klp_apply_section_relocs(mod, info->sechdrs,
2340 2339 info->secstrings,
2341 if (info->sechdrs[i].sh_type == SHT_REL)2340 info->strtab,
2341 info->index.sym, i,
2342 NULL);
2343 else if (info->sechdrs[i].sh_type == SHT_REL)
2342 err = apply_relocate(info->sechdrs, info->strtab,2344 err = apply_relocate(info->sechdrs, info->strtab,
2343 info->index.sym, i, mod);2345 info->index.sym, i, mod);
2344 else if (info->sechdrs[i].sh_type == SHT_RELA)2346 else if (info->sechdrs[i].sh_type == SHT_RELA)

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t