diff options
Diffstat (limited to 'kernel/livepatch/core.c')
| -rw-r--r-- | kernel/livepatch/core.c | 72 | 
1 files changed, 50 insertions, 22 deletions
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 201f0c0482fb..4bd2d5e10f20 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -118,7 +118,6 @@ static struct klp_object *klp_find_object(struct klp_patch *patch,  }  struct klp_find_arg { -	const char *objname;  	const char *name;  	unsigned long addr;  	unsigned long count; @@ -148,15 +147,9 @@ static int klp_find_callback(void *data, const char *name,  {  	struct klp_find_arg *args = data; -	if ((mod && !args->objname) || (!mod && args->objname)) -		return 0; -  	if (strcmp(args->name, name))  		return 0; -	if (args->objname && strcmp(args->objname, mod->name)) -		return 0; -  	return klp_match_callback(data, addr);  } @@ -164,7 +157,6 @@ static int klp_find_object_symbol(const char *objname, const char *name,  				  unsigned long sympos, unsigned long *addr)  {  	struct klp_find_arg args = { -		.objname = objname,  		.name = name,  		.addr = 0,  		.count = 0, @@ -172,7 +164,7 @@ static int klp_find_object_symbol(const char *objname, const char *name,  	};  	if (objname) -		module_kallsyms_on_each_symbol(klp_find_callback, &args); +		module_kallsyms_on_each_symbol(objname, klp_find_callback, &args);  	else  		kallsyms_on_each_match_symbol(klp_match_callback, name, &args); @@ -268,6 +260,14 @@ static int klp_resolve_symbols(Elf_Shdr *sechdrs, const char *strtab,  	return 0;  } +void __weak clear_relocate_add(Elf_Shdr *sechdrs, +		   const char *strtab, +		   unsigned int symindex, +		   unsigned int relsec, +		   struct module *me) +{ +} +  /*   * At a high-level, there are two types of klp relocation sections: those which   * reference symbols which live in vmlinux; and those which reference symbols @@ -291,10 +291,10 @@ static int klp_resolve_symbols(Elf_Shdr *sechdrs, const char *strtab,   *    the to-be-patched module to be loaded and patched sometime *after* the   *    klp module is loaded.   */ -int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs, -			     const char *shstrtab, const char *strtab, -			     unsigned int symndx, unsigned int secndx, -			     const char *objname) +static int klp_write_section_relocs(struct module *pmod, Elf_Shdr *sechdrs, +				    const char *shstrtab, const char *strtab, +				    unsigned int symndx, unsigned int secndx, +				    const char *objname, bool apply)  {  	int cnt, ret;  	char sec_objname[MODULE_NAME_LEN]; @@ -316,11 +316,26 @@ int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs,  	if (strcmp(objname ? objname : "vmlinux", sec_objname))  		return 0; -	ret = klp_resolve_symbols(sechdrs, strtab, symndx, sec, sec_objname); -	if (ret) -		return ret; +	if (apply) { +		ret = klp_resolve_symbols(sechdrs, strtab, symndx, +					  sec, sec_objname); +		if (ret) +			return ret; + +		return apply_relocate_add(sechdrs, strtab, symndx, secndx, pmod); +	} + +	clear_relocate_add(sechdrs, strtab, symndx, secndx, pmod); +	return 0; +} -	return apply_relocate_add(sechdrs, strtab, symndx, secndx, pmod); +int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs, +			     const char *shstrtab, const char *strtab, +			     unsigned int symndx, unsigned int secndx, +			     const char *objname) +{ +	return klp_write_section_relocs(pmod, sechdrs, shstrtab, strtab, symndx, +					secndx, objname, true);  }  /* @@ -769,8 +784,9 @@ static int klp_init_func(struct klp_object *obj, struct klp_func *func)  			   func->old_sympos ? func->old_sympos : 1);  } -static int klp_apply_object_relocs(struct klp_patch *patch, -				   struct klp_object *obj) +static int klp_write_object_relocs(struct klp_patch *patch, +				   struct klp_object *obj, +				   bool apply)  {  	int i, ret;  	struct klp_modinfo *info = patch->mod->klp_info; @@ -781,10 +797,10 @@ static int klp_apply_object_relocs(struct klp_patch *patch,  		if (!(sec->sh_flags & SHF_RELA_LIVEPATCH))  			continue; -		ret = klp_apply_section_relocs(patch->mod, info->sechdrs, +		ret = klp_write_section_relocs(patch->mod, info->sechdrs,  					       info->secstrings,  					       patch->mod->core_kallsyms.strtab, -					       info->symndx, i, obj->name); +					       info->symndx, i, obj->name, apply);  		if (ret)  			return ret;  	} @@ -792,6 +808,18 @@ static int klp_apply_object_relocs(struct klp_patch *patch,  	return 0;  } +static int klp_apply_object_relocs(struct klp_patch *patch, +				   struct klp_object *obj) +{ +	return klp_write_object_relocs(patch, obj, true); +} + +static void klp_clear_object_relocs(struct klp_patch *patch, +				    struct klp_object *obj) +{ +	klp_write_object_relocs(patch, obj, false); +} +  /* parts of the initialization that is done only when the object is loaded */  static int klp_init_object_loaded(struct klp_patch *patch,  				  struct klp_object *obj) @@ -1179,7 +1207,7 @@ static void klp_cleanup_module_patches_limited(struct module *mod,  			klp_unpatch_object(obj);  			klp_post_unpatch_callback(obj); - +			klp_clear_object_relocs(patch, obj);  			klp_free_object_loaded(obj);  			break;  		}  |