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

Showing the changes to include/linux (1 of 3 files). Show all

Unified · Split

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_ */