static_call: Allow module use without exposing static_call_key
[ Upstream commit 73f44fe19d359635a607e8e8daa0da4001c1cfc2 ] When exporting static_call_key; with EXPORT_STATIC_CALL*(), the module can use static_call_update() to change the function called. This is not desirable in general. Not exporting static_call_key however also disallows usage of static_call(), since objtool needs the key to construct the static_call_site. Solve this by allowing objtool to create the static_call_site using the trampoline address when it builds a module and cannot find the static_call_key symbol. The module loader will then try and map the trampole back to a key before it constructs the normal sites list. Doing this requires a trampoline -> key associsation, so add another magic section that keeps those. Originally-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Ingo Molnar <mingo@kernel.org> Link: https://lkml.kernel.org/r/20210127231837.ifddpn7rhwdaepiu@treble Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
433cd7ca38
commit
a63068e939
@@ -12,6 +12,8 @@
|
||||
|
||||
extern struct static_call_site __start_static_call_sites[],
|
||||
__stop_static_call_sites[];
|
||||
extern struct static_call_tramp_key __start_static_call_tramp_key[],
|
||||
__stop_static_call_tramp_key[];
|
||||
|
||||
static bool static_call_initialized;
|
||||
|
||||
@@ -332,10 +334,59 @@ static int __static_call_mod_text_reserved(void *start, void *end)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned long tramp_key_lookup(unsigned long addr)
|
||||
{
|
||||
struct static_call_tramp_key *start = __start_static_call_tramp_key;
|
||||
struct static_call_tramp_key *stop = __stop_static_call_tramp_key;
|
||||
struct static_call_tramp_key *tramp_key;
|
||||
|
||||
for (tramp_key = start; tramp_key != stop; tramp_key++) {
|
||||
unsigned long tramp;
|
||||
|
||||
tramp = (long)tramp_key->tramp + (long)&tramp_key->tramp;
|
||||
if (tramp == addr)
|
||||
return (long)tramp_key->key + (long)&tramp_key->key;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int static_call_add_module(struct module *mod)
|
||||
{
|
||||
return __static_call_init(mod, mod->static_call_sites,
|
||||
mod->static_call_sites + mod->num_static_call_sites);
|
||||
struct static_call_site *start = mod->static_call_sites;
|
||||
struct static_call_site *stop = start + mod->num_static_call_sites;
|
||||
struct static_call_site *site;
|
||||
|
||||
for (site = start; site != stop; site++) {
|
||||
unsigned long addr = (unsigned long)static_call_key(site);
|
||||
unsigned long key;
|
||||
|
||||
/*
|
||||
* Is the key is exported, 'addr' points to the key, which
|
||||
* means modules are allowed to call static_call_update() on
|
||||
* it.
|
||||
*
|
||||
* Otherwise, the key isn't exported, and 'addr' points to the
|
||||
* trampoline so we need to lookup the key.
|
||||
*
|
||||
* We go through this dance to prevent crazy modules from
|
||||
* abusing sensitive static calls.
|
||||
*/
|
||||
if (!kernel_text_address(addr))
|
||||
continue;
|
||||
|
||||
key = tramp_key_lookup(addr);
|
||||
if (!key) {
|
||||
pr_warn("Failed to fixup __raw_static_call() usage at: %ps\n",
|
||||
static_call_addr(site));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
site->key = (key - (long)&site->key) |
|
||||
(site->key & STATIC_CALL_SITE_FLAGS);
|
||||
}
|
||||
|
||||
return __static_call_init(mod, start, stop);
|
||||
}
|
||||
|
||||
static void static_call_del_module(struct module *mod)
|
||||
|
Reference in New Issue
Block a user