Skip to content

Commit ef06e68

Browse files
committed
Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
Pull arm64 fixes from Catalin Marinas: - Revert the moving of the jump labels initialisation before setup_machine_fdt(). The bug was fixed in drivers/char/random.c. - Ftrace fixes: branch range check and consistent handling of PLTs. - Clean rather than invalidate FROM_DEVICE buffers at start of DMA transfer (safer if such buffer is mapped in user space). A cache invalidation is done already at the end of the transfer. - A couple of clean-ups (unexport symbol, remove unused label). * tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: arm64: mm: Don't invalidate FROM_DEVICE buffers at start of DMA transfer arm64/cpufeature: Unexport set_cpu_feature() arm64: ftrace: remove redundant label arm64: ftrace: consistently handle PLTs. arm64: ftrace: fix branch range checks Revert "arm64: Initialize jump labels before setup_machine_fdt()"
2 parents cc2fb31 + c50f11c commit ef06e68

File tree

5 files changed

+69
-79
lines changed

5 files changed

+69
-79
lines changed

arch/arm64/kernel/cpufeature.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3101,7 +3101,6 @@ void cpu_set_feature(unsigned int num)
31013101
WARN_ON(num >= MAX_CPU_FEATURES);
31023102
elf_hwcap |= BIT(num);
31033103
}
3104-
EXPORT_SYMBOL_GPL(cpu_set_feature);
31053104

31063105
bool cpu_have_feature(unsigned int num)
31073106
{

arch/arm64/kernel/entry-ftrace.S

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)
102102
* x19-x29 per the AAPCS, and we created frame records upon entry, so we need
103103
* to restore x0-x8, x29, and x30.
104104
*/
105-
ftrace_common_return:
106105
/* Restore function arguments */
107106
ldp x0, x1, [sp]
108107
ldp x2, x3, [sp, #S_X2]

arch/arm64/kernel/ftrace.c

Lines changed: 66 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -78,47 +78,76 @@ static struct plt_entry *get_ftrace_plt(struct module *mod, unsigned long addr)
7878
}
7979

8080
/*
81-
* Turn on the call to ftrace_caller() in instrumented function
81+
* Find the address the callsite must branch to in order to reach '*addr'.
82+
*
83+
* Due to the limited range of 'BL' instructions, modules may be placed too far
84+
* away to branch directly and must use a PLT.
85+
*
86+
* Returns true when '*addr' contains a reachable target address, or has been
87+
* modified to contain a PLT address. Returns false otherwise.
8288
*/
83-
int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
89+
static bool ftrace_find_callable_addr(struct dyn_ftrace *rec,
90+
struct module *mod,
91+
unsigned long *addr)
8492
{
8593
unsigned long pc = rec->ip;
86-
u32 old, new;
87-
long offset = (long)pc - (long)addr;
94+
long offset = (long)*addr - (long)pc;
95+
struct plt_entry *plt;
8896

89-
if (offset < -SZ_128M || offset >= SZ_128M) {
90-
struct module *mod;
91-
struct plt_entry *plt;
97+
/*
98+
* When the target is within range of the 'BL' instruction, use 'addr'
99+
* as-is and branch to that directly.
100+
*/
101+
if (offset >= -SZ_128M && offset < SZ_128M)
102+
return true;
92103

93-
if (!IS_ENABLED(CONFIG_ARM64_MODULE_PLTS))
94-
return -EINVAL;
104+
/*
105+
* When the target is outside of the range of a 'BL' instruction, we
106+
* must use a PLT to reach it. We can only place PLTs for modules, and
107+
* only when module PLT support is built-in.
108+
*/
109+
if (!IS_ENABLED(CONFIG_ARM64_MODULE_PLTS))
110+
return false;
95111

96-
/*
97-
* On kernels that support module PLTs, the offset between the
98-
* branch instruction and its target may legally exceed the
99-
* range of an ordinary relative 'bl' opcode. In this case, we
100-
* need to branch via a trampoline in the module.
101-
*
102-
* NOTE: __module_text_address() must be called with preemption
103-
* disabled, but we can rely on ftrace_lock to ensure that 'mod'
104-
* retains its validity throughout the remainder of this code.
105-
*/
112+
/*
113+
* 'mod' is only set at module load time, but if we end up
114+
* dealing with an out-of-range condition, we can assume it
115+
* is due to a module being loaded far away from the kernel.
116+
*
117+
* NOTE: __module_text_address() must be called with preemption
118+
* disabled, but we can rely on ftrace_lock to ensure that 'mod'
119+
* retains its validity throughout the remainder of this code.
120+
*/
121+
if (!mod) {
106122
preempt_disable();
107123
mod = __module_text_address(pc);
108124
preempt_enable();
125+
}
109126

110-
if (WARN_ON(!mod))
111-
return -EINVAL;
127+
if (WARN_ON(!mod))
128+
return false;
112129

113-
plt = get_ftrace_plt(mod, addr);
114-
if (!plt) {
115-
pr_err("ftrace: no module PLT for %ps\n", (void *)addr);
116-
return -EINVAL;
117-
}
118-
119-
addr = (unsigned long)plt;
130+
plt = get_ftrace_plt(mod, *addr);
131+
if (!plt) {
132+
pr_err("ftrace: no module PLT for %ps\n", (void *)*addr);
133+
return false;
120134
}
121135

136+
*addr = (unsigned long)plt;
137+
return true;
138+
}
139+
140+
/*
141+
* Turn on the call to ftrace_caller() in instrumented function
142+
*/
143+
int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
144+
{
145+
unsigned long pc = rec->ip;
146+
u32 old, new;
147+
148+
if (!ftrace_find_callable_addr(rec, NULL, &addr))
149+
return -EINVAL;
150+
122151
old = aarch64_insn_gen_nop();
123152
new = aarch64_insn_gen_branch_imm(pc, addr, AARCH64_INSN_BRANCH_LINK);
124153

@@ -132,6 +161,11 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
132161
unsigned long pc = rec->ip;
133162
u32 old, new;
134163

164+
if (!ftrace_find_callable_addr(rec, NULL, &old_addr))
165+
return -EINVAL;
166+
if (!ftrace_find_callable_addr(rec, NULL, &addr))
167+
return -EINVAL;
168+
135169
old = aarch64_insn_gen_branch_imm(pc, old_addr,
136170
AARCH64_INSN_BRANCH_LINK);
137171
new = aarch64_insn_gen_branch_imm(pc, addr, AARCH64_INSN_BRANCH_LINK);
@@ -181,54 +215,15 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
181215
unsigned long addr)
182216
{
183217
unsigned long pc = rec->ip;
184-
bool validate = true;
185218
u32 old = 0, new;
186-
long offset = (long)pc - (long)addr;
187219

188-
if (offset < -SZ_128M || offset >= SZ_128M) {
189-
u32 replaced;
190-
191-
if (!IS_ENABLED(CONFIG_ARM64_MODULE_PLTS))
192-
return -EINVAL;
193-
194-
/*
195-
* 'mod' is only set at module load time, but if we end up
196-
* dealing with an out-of-range condition, we can assume it
197-
* is due to a module being loaded far away from the kernel.
198-
*/
199-
if (!mod) {
200-
preempt_disable();
201-
mod = __module_text_address(pc);
202-
preempt_enable();
203-
204-
if (WARN_ON(!mod))
205-
return -EINVAL;
206-
}
207-
208-
/*
209-
* The instruction we are about to patch may be a branch and
210-
* link instruction that was redirected via a PLT entry. In
211-
* this case, the normal validation will fail, but we can at
212-
* least check that we are dealing with a branch and link
213-
* instruction that points into the right module.
214-
*/
215-
if (aarch64_insn_read((void *)pc, &replaced))
216-
return -EFAULT;
217-
218-
if (!aarch64_insn_is_bl(replaced) ||
219-
!within_module(pc + aarch64_get_branch_offset(replaced),
220-
mod))
221-
return -EINVAL;
222-
223-
validate = false;
224-
} else {
225-
old = aarch64_insn_gen_branch_imm(pc, addr,
226-
AARCH64_INSN_BRANCH_LINK);
227-
}
220+
if (!ftrace_find_callable_addr(rec, mod, &addr))
221+
return -EINVAL;
228222

223+
old = aarch64_insn_gen_branch_imm(pc, addr, AARCH64_INSN_BRANCH_LINK);
229224
new = aarch64_insn_gen_nop();
230225

231-
return ftrace_modify_code(pc, old, new, validate);
226+
return ftrace_modify_code(pc, old, new, true);
232227
}
233228

234229
void arch_ftrace_update_code(int command)

arch/arm64/kernel/setup.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -303,14 +303,13 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)
303303
early_fixmap_init();
304304
early_ioremap_init();
305305

306+
setup_machine_fdt(__fdt_pointer);
307+
306308
/*
307309
* Initialise the static keys early as they may be enabled by the
308-
* cpufeature code, early parameters, and DT setup.
310+
* cpufeature code and early parameters.
309311
*/
310312
jump_label_init();
311-
312-
setup_machine_fdt(__fdt_pointer);
313-
314313
parse_early_param();
315314

316315
/*

arch/arm64/mm/cache.S

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,6 @@ SYM_FUNC_ALIAS(__dma_flush_area, __pi___dma_flush_area)
218218
*/
219219
SYM_FUNC_START(__pi___dma_map_area)
220220
add x1, x0, x1
221-
cmp w2, #DMA_FROM_DEVICE
222-
b.eq __pi_dcache_inval_poc
223221
b __pi_dcache_clean_poc
224222
SYM_FUNC_END(__pi___dma_map_area)
225223
SYM_FUNC_ALIAS(__dma_map_area, __pi___dma_map_area)

0 commit comments

Comments
 (0)