Skip to content

Commit 73f44fe

Browse files
jpoimboeIngo Molnar
authored andcommitted
static_call: Allow module use without exposing static_call_key
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) <[email protected]> Signed-off-by: Josh Poimboeuf <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Link: https://lkml.kernel.org/r/20210127231837.ifddpn7rhwdaepiu@treble
1 parent e59e10f commit 73f44fe

File tree

7 files changed

+149
-11
lines changed

7 files changed

+149
-11
lines changed

arch/x86/include/asm/static_call.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,11 @@
3737
#define ARCH_DEFINE_STATIC_CALL_NULL_TRAMP(name) \
3838
__ARCH_DEFINE_STATIC_CALL_TRAMP(name, "ret; nop; nop; nop; nop")
3939

40+
41+
#define ARCH_ADD_TRAMP_KEY(name) \
42+
asm(".pushsection .static_call_tramp_key, \"a\" \n" \
43+
".long " STATIC_CALL_TRAMP_STR(name) " - . \n" \
44+
".long " STATIC_CALL_KEY_STR(name) " - . \n" \
45+
".popsection \n")
46+
4047
#endif /* _ASM_STATIC_CALL_H */

include/asm-generic/vmlinux.lds.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,10 @@
393393
. = ALIGN(8); \
394394
__start_static_call_sites = .; \
395395
KEEP(*(.static_call_sites)) \
396-
__stop_static_call_sites = .;
396+
__stop_static_call_sites = .; \
397+
__start_static_call_tramp_key = .; \
398+
KEEP(*(.static_call_tramp_key)) \
399+
__stop_static_call_tramp_key = .;
397400

398401
/*
399402
* Allow architectures to handle ro_after_init data on their

include/linux/static_call.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,12 @@ struct static_call_key {
138138
};
139139
};
140140

141+
/* For finding the key associated with a trampoline */
142+
struct static_call_tramp_key {
143+
s32 tramp;
144+
s32 key;
145+
};
146+
141147
extern void __static_call_update(struct static_call_key *key, void *tramp, void *func);
142148
extern int static_call_mod_init(struct module *mod);
143149
extern int static_call_text_reserved(void *start, void *end);
@@ -165,11 +171,18 @@ extern long __static_call_return0(void);
165171
#define EXPORT_STATIC_CALL(name) \
166172
EXPORT_SYMBOL(STATIC_CALL_KEY(name)); \
167173
EXPORT_SYMBOL(STATIC_CALL_TRAMP(name))
168-
169174
#define EXPORT_STATIC_CALL_GPL(name) \
170175
EXPORT_SYMBOL_GPL(STATIC_CALL_KEY(name)); \
171176
EXPORT_SYMBOL_GPL(STATIC_CALL_TRAMP(name))
172177

178+
/* Leave the key unexported, so modules can't change static call targets: */
179+
#define EXPORT_STATIC_CALL_TRAMP(name) \
180+
EXPORT_SYMBOL(STATIC_CALL_TRAMP(name)); \
181+
ARCH_ADD_TRAMP_KEY(name)
182+
#define EXPORT_STATIC_CALL_TRAMP_GPL(name) \
183+
EXPORT_SYMBOL_GPL(STATIC_CALL_TRAMP(name)); \
184+
ARCH_ADD_TRAMP_KEY(name)
185+
173186
#elif defined(CONFIG_HAVE_STATIC_CALL)
174187

175188
static inline int static_call_init(void) { return 0; }
@@ -216,11 +229,16 @@ static inline long __static_call_return0(void)
216229
#define EXPORT_STATIC_CALL(name) \
217230
EXPORT_SYMBOL(STATIC_CALL_KEY(name)); \
218231
EXPORT_SYMBOL(STATIC_CALL_TRAMP(name))
219-
220232
#define EXPORT_STATIC_CALL_GPL(name) \
221233
EXPORT_SYMBOL_GPL(STATIC_CALL_KEY(name)); \
222234
EXPORT_SYMBOL_GPL(STATIC_CALL_TRAMP(name))
223235

236+
/* Leave the key unexported, so modules can't change static call targets: */
237+
#define EXPORT_STATIC_CALL_TRAMP(name) \
238+
EXPORT_SYMBOL(STATIC_CALL_TRAMP(name))
239+
#define EXPORT_STATIC_CALL_TRAMP_GPL(name) \
240+
EXPORT_SYMBOL_GPL(STATIC_CALL_TRAMP(name))
241+
224242
#else /* Generic implementation */
225243

226244
static inline int static_call_init(void) { return 0; }

include/linux/static_call_types.h

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define STATIC_CALL_KEY_PREFIX_STR __stringify(STATIC_CALL_KEY_PREFIX)
1111
#define STATIC_CALL_KEY_PREFIX_LEN (sizeof(STATIC_CALL_KEY_PREFIX_STR) - 1)
1212
#define STATIC_CALL_KEY(name) __PASTE(STATIC_CALL_KEY_PREFIX, name)
13+
#define STATIC_CALL_KEY_STR(name) __stringify(STATIC_CALL_KEY(name))
1314

1415
#define STATIC_CALL_TRAMP_PREFIX __SCT__
1516
#define STATIC_CALL_TRAMP_PREFIX_STR __stringify(STATIC_CALL_TRAMP_PREFIX)
@@ -39,17 +40,39 @@ struct static_call_site {
3940

4041
#ifdef CONFIG_HAVE_STATIC_CALL
4142

43+
#define __raw_static_call(name) (&STATIC_CALL_TRAMP(name))
44+
45+
#ifdef CONFIG_HAVE_STATIC_CALL_INLINE
46+
4247
/*
4348
* __ADDRESSABLE() is used to ensure the key symbol doesn't get stripped from
4449
* the symbol table so that objtool can reference it when it generates the
4550
* .static_call_sites section.
4651
*/
52+
#define __STATIC_CALL_ADDRESSABLE(name) \
53+
__ADDRESSABLE(STATIC_CALL_KEY(name))
54+
4755
#define __static_call(name) \
4856
({ \
49-
__ADDRESSABLE(STATIC_CALL_KEY(name)); \
50-
&STATIC_CALL_TRAMP(name); \
57+
__STATIC_CALL_ADDRESSABLE(name); \
58+
__raw_static_call(name); \
5159
})
5260

61+
#else /* !CONFIG_HAVE_STATIC_CALL_INLINE */
62+
63+
#define __STATIC_CALL_ADDRESSABLE(name)
64+
#define __static_call(name) __raw_static_call(name)
65+
66+
#endif /* CONFIG_HAVE_STATIC_CALL_INLINE */
67+
68+
#ifdef MODULE
69+
#define __STATIC_CALL_MOD_ADDRESSABLE(name)
70+
#define static_call_mod(name) __raw_static_call(name)
71+
#else
72+
#define __STATIC_CALL_MOD_ADDRESSABLE(name) __STATIC_CALL_ADDRESSABLE(name)
73+
#define static_call_mod(name) __static_call(name)
74+
#endif
75+
5376
#define static_call(name) __static_call(name)
5477

5578
#else

kernel/static_call.c

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
extern struct static_call_site __start_static_call_sites[],
1414
__stop_static_call_sites[];
15+
extern struct static_call_tramp_key __start_static_call_tramp_key[],
16+
__stop_static_call_tramp_key[];
1517

1618
static bool static_call_initialized;
1719

@@ -323,10 +325,59 @@ static int __static_call_mod_text_reserved(void *start, void *end)
323325
return ret;
324326
}
325327

328+
static unsigned long tramp_key_lookup(unsigned long addr)
329+
{
330+
struct static_call_tramp_key *start = __start_static_call_tramp_key;
331+
struct static_call_tramp_key *stop = __stop_static_call_tramp_key;
332+
struct static_call_tramp_key *tramp_key;
333+
334+
for (tramp_key = start; tramp_key != stop; tramp_key++) {
335+
unsigned long tramp;
336+
337+
tramp = (long)tramp_key->tramp + (long)&tramp_key->tramp;
338+
if (tramp == addr)
339+
return (long)tramp_key->key + (long)&tramp_key->key;
340+
}
341+
342+
return 0;
343+
}
344+
326345
static int static_call_add_module(struct module *mod)
327346
{
328-
return __static_call_init(mod, mod->static_call_sites,
329-
mod->static_call_sites + mod->num_static_call_sites);
347+
struct static_call_site *start = mod->static_call_sites;
348+
struct static_call_site *stop = start + mod->num_static_call_sites;
349+
struct static_call_site *site;
350+
351+
for (site = start; site != stop; site++) {
352+
unsigned long addr = (unsigned long)static_call_key(site);
353+
unsigned long key;
354+
355+
/*
356+
* Is the key is exported, 'addr' points to the key, which
357+
* means modules are allowed to call static_call_update() on
358+
* it.
359+
*
360+
* Otherwise, the key isn't exported, and 'addr' points to the
361+
* trampoline so we need to lookup the key.
362+
*
363+
* We go through this dance to prevent crazy modules from
364+
* abusing sensitive static calls.
365+
*/
366+
if (!kernel_text_address(addr))
367+
continue;
368+
369+
key = tramp_key_lookup(addr);
370+
if (!key) {
371+
pr_warn("Failed to fixup __raw_static_call() usage at: %ps\n",
372+
static_call_addr(site));
373+
return -EINVAL;
374+
}
375+
376+
site->key = (key - (long)&site->key) |
377+
(site->key & STATIC_CALL_SITE_FLAGS);
378+
}
379+
380+
return __static_call_init(mod, start, stop);
330381
}
331382

332383
static void static_call_del_module(struct module *mod)

tools/include/linux/static_call_types.h

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define STATIC_CALL_KEY_PREFIX_STR __stringify(STATIC_CALL_KEY_PREFIX)
1111
#define STATIC_CALL_KEY_PREFIX_LEN (sizeof(STATIC_CALL_KEY_PREFIX_STR) - 1)
1212
#define STATIC_CALL_KEY(name) __PASTE(STATIC_CALL_KEY_PREFIX, name)
13+
#define STATIC_CALL_KEY_STR(name) __stringify(STATIC_CALL_KEY(name))
1314

1415
#define STATIC_CALL_TRAMP_PREFIX __SCT__
1516
#define STATIC_CALL_TRAMP_PREFIX_STR __stringify(STATIC_CALL_TRAMP_PREFIX)
@@ -39,17 +40,39 @@ struct static_call_site {
3940

4041
#ifdef CONFIG_HAVE_STATIC_CALL
4142

43+
#define __raw_static_call(name) (&STATIC_CALL_TRAMP(name))
44+
45+
#ifdef CONFIG_HAVE_STATIC_CALL_INLINE
46+
4247
/*
4348
* __ADDRESSABLE() is used to ensure the key symbol doesn't get stripped from
4449
* the symbol table so that objtool can reference it when it generates the
4550
* .static_call_sites section.
4651
*/
52+
#define __STATIC_CALL_ADDRESSABLE(name) \
53+
__ADDRESSABLE(STATIC_CALL_KEY(name))
54+
4755
#define __static_call(name) \
4856
({ \
49-
__ADDRESSABLE(STATIC_CALL_KEY(name)); \
50-
&STATIC_CALL_TRAMP(name); \
57+
__STATIC_CALL_ADDRESSABLE(name); \
58+
__raw_static_call(name); \
5159
})
5260

61+
#else /* !CONFIG_HAVE_STATIC_CALL_INLINE */
62+
63+
#define __STATIC_CALL_ADDRESSABLE(name)
64+
#define __static_call(name) __raw_static_call(name)
65+
66+
#endif /* CONFIG_HAVE_STATIC_CALL_INLINE */
67+
68+
#ifdef MODULE
69+
#define __STATIC_CALL_MOD_ADDRESSABLE(name)
70+
#define static_call_mod(name) __raw_static_call(name)
71+
#else
72+
#define __STATIC_CALL_MOD_ADDRESSABLE(name) __STATIC_CALL_ADDRESSABLE(name)
73+
#define static_call_mod(name) __static_call(name)
74+
#endif
75+
5376
#define static_call(name) __static_call(name)
5477

5578
#else

tools/objtool/check.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -502,8 +502,21 @@ static int create_static_call_sections(struct objtool_file *file)
502502

503503
key_sym = find_symbol_by_name(file->elf, tmp);
504504
if (!key_sym) {
505-
WARN("static_call: can't find static_call_key symbol: %s", tmp);
506-
return -1;
505+
if (!module) {
506+
WARN("static_call: can't find static_call_key symbol: %s", tmp);
507+
return -1;
508+
}
509+
510+
/*
511+
* For modules(), the key might not be exported, which
512+
* means the module can make static calls but isn't
513+
* allowed to change them.
514+
*
515+
* In that case we temporarily set the key to be the
516+
* trampoline address. This is fixed up in
517+
* static_call_add_module().
518+
*/
519+
key_sym = insn->call_dest;
507520
}
508521
free(key_name);
509522

0 commit comments

Comments
 (0)