Skip to content

Commit 76734d2

Browse files
pccwilldeacon
authored andcommitted
arm64: Change the on_*stack functions to take a size argument
unwind_frame() was previously implicitly checking that the frame record is in bounds of the stack by enforcing that FP is both aligned to 16 and in bounds of the stack. Once the FP alignment requirement is relaxed to 8 this will not be sufficient because it does not account for the case where FP points to 8 bytes before the end of the stack. Make the check explicit by changing the on_*stack functions to take a size argument and adjusting the callers to pass the appropriate sizes. Signed-off-by: Peter Collingbourne <pcc@google.com> Link: https://linux-review.googlesource.com/id/Ib7a3eb3eea41b0687ffaba045ceb2012d077d8b4 Reviewed-by: Mark Rutland <mark.rutland@arm.com> Tested-by: Mark Rutland <mark.rutland@arm.com> Link: https://lore.kernel.org/r/20210526174927.2477847-1-pcc@google.com Signed-off-by: Will Deacon <will@kernel.org>
1 parent 7d7b720 commit 76734d2

6 files changed

Lines changed: 37 additions & 34 deletions

File tree

arch/arm64/include/asm/processor.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -329,13 +329,13 @@ long get_tagged_addr_ctrl(struct task_struct *task);
329329
* of header definitions for the use of task_stack_page.
330330
*/
331331

332-
#define current_top_of_stack() \
333-
({ \
334-
struct stack_info _info; \
335-
BUG_ON(!on_accessible_stack(current, current_stack_pointer, &_info)); \
336-
_info.high; \
332+
#define current_top_of_stack() \
333+
({ \
334+
struct stack_info _info; \
335+
BUG_ON(!on_accessible_stack(current, current_stack_pointer, 1, &_info)); \
336+
_info.high; \
337337
})
338-
#define on_thread_stack() (on_task_stack(current, current_stack_pointer, NULL))
338+
#define on_thread_stack() (on_task_stack(current, current_stack_pointer, 1, NULL))
339339

340340
#endif /* __ASSEMBLY__ */
341341
#endif /* __ASM_PROCESSOR_H */

arch/arm64/include/asm/sdei.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,17 @@ unsigned long sdei_arch_get_entry_point(int conduit);
4242

4343
struct stack_info;
4444

45-
bool _on_sdei_stack(unsigned long sp, struct stack_info *info);
46-
static inline bool on_sdei_stack(unsigned long sp,
45+
bool _on_sdei_stack(unsigned long sp, unsigned long size,
46+
struct stack_info *info);
47+
static inline bool on_sdei_stack(unsigned long sp, unsigned long size,
4748
struct stack_info *info)
4849
{
4950
if (!IS_ENABLED(CONFIG_VMAP_STACK))
5051
return false;
5152
if (!IS_ENABLED(CONFIG_ARM_SDE_INTERFACE))
5253
return false;
5354
if (in_nmi())
54-
return _on_sdei_stack(sp, info);
55+
return _on_sdei_stack(sp, size, info);
5556

5657
return false;
5758
}

arch/arm64/include/asm/stacktrace.h

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,14 @@ extern void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk,
6969

7070
DECLARE_PER_CPU(unsigned long *, irq_stack_ptr);
7171

72-
static inline bool on_stack(unsigned long sp, unsigned long low,
73-
unsigned long high, enum stack_type type,
74-
struct stack_info *info)
72+
static inline bool on_stack(unsigned long sp, unsigned long size,
73+
unsigned long low, unsigned long high,
74+
enum stack_type type, struct stack_info *info)
7575
{
7676
if (!low)
7777
return false;
7878

79-
if (sp < low || sp >= high)
79+
if (sp < low || sp + size < sp || sp + size > high)
8080
return false;
8181

8282
if (info) {
@@ -87,38 +87,38 @@ static inline bool on_stack(unsigned long sp, unsigned long low,
8787
return true;
8888
}
8989

90-
static inline bool on_irq_stack(unsigned long sp,
90+
static inline bool on_irq_stack(unsigned long sp, unsigned long size,
9191
struct stack_info *info)
9292
{
9393
unsigned long low = (unsigned long)raw_cpu_read(irq_stack_ptr);
9494
unsigned long high = low + IRQ_STACK_SIZE;
9595

96-
return on_stack(sp, low, high, STACK_TYPE_IRQ, info);
96+
return on_stack(sp, size, low, high, STACK_TYPE_IRQ, info);
9797
}
9898

9999
static inline bool on_task_stack(const struct task_struct *tsk,
100-
unsigned long sp,
100+
unsigned long sp, unsigned long size,
101101
struct stack_info *info)
102102
{
103103
unsigned long low = (unsigned long)task_stack_page(tsk);
104104
unsigned long high = low + THREAD_SIZE;
105105

106-
return on_stack(sp, low, high, STACK_TYPE_TASK, info);
106+
return on_stack(sp, size, low, high, STACK_TYPE_TASK, info);
107107
}
108108

109109
#ifdef CONFIG_VMAP_STACK
110110
DECLARE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack);
111111

112-
static inline bool on_overflow_stack(unsigned long sp,
112+
static inline bool on_overflow_stack(unsigned long sp, unsigned long size,
113113
struct stack_info *info)
114114
{
115115
unsigned long low = (unsigned long)raw_cpu_ptr(overflow_stack);
116116
unsigned long high = low + OVERFLOW_STACK_SIZE;
117117

118-
return on_stack(sp, low, high, STACK_TYPE_OVERFLOW, info);
118+
return on_stack(sp, size, low, high, STACK_TYPE_OVERFLOW, info);
119119
}
120120
#else
121-
static inline bool on_overflow_stack(unsigned long sp,
121+
static inline bool on_overflow_stack(unsigned long sp, unsigned long size,
122122
struct stack_info *info) { return false; }
123123
#endif
124124

@@ -128,21 +128,21 @@ static inline bool on_overflow_stack(unsigned long sp,
128128
* context.
129129
*/
130130
static inline bool on_accessible_stack(const struct task_struct *tsk,
131-
unsigned long sp,
131+
unsigned long sp, unsigned long size,
132132
struct stack_info *info)
133133
{
134134
if (info)
135135
info->type = STACK_TYPE_UNKNOWN;
136136

137-
if (on_task_stack(tsk, sp, info))
137+
if (on_task_stack(tsk, sp, size, info))
138138
return true;
139139
if (tsk != current || preemptible())
140140
return false;
141-
if (on_irq_stack(sp, info))
141+
if (on_irq_stack(sp, size, info))
142142
return true;
143-
if (on_overflow_stack(sp, info))
143+
if (on_overflow_stack(sp, size, info))
144144
return true;
145-
if (on_sdei_stack(sp, info))
145+
if (on_sdei_stack(sp, size, info))
146146
return true;
147147

148148
return false;

arch/arm64/kernel/ptrace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ static bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
122122
{
123123
return ((addr & ~(THREAD_SIZE - 1)) ==
124124
(kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1))) ||
125-
on_irq_stack(addr, NULL);
125+
on_irq_stack(addr, sizeof(unsigned long), NULL);
126126
}
127127

128128
/**

arch/arm64/kernel/sdei.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -162,31 +162,33 @@ static int init_sdei_scs(void)
162162
return err;
163163
}
164164

165-
static bool on_sdei_normal_stack(unsigned long sp, struct stack_info *info)
165+
static bool on_sdei_normal_stack(unsigned long sp, unsigned long size,
166+
struct stack_info *info)
166167
{
167168
unsigned long low = (unsigned long)raw_cpu_read(sdei_stack_normal_ptr);
168169
unsigned long high = low + SDEI_STACK_SIZE;
169170

170-
return on_stack(sp, low, high, STACK_TYPE_SDEI_NORMAL, info);
171+
return on_stack(sp, size, low, high, STACK_TYPE_SDEI_NORMAL, info);
171172
}
172173

173-
static bool on_sdei_critical_stack(unsigned long sp, struct stack_info *info)
174+
static bool on_sdei_critical_stack(unsigned long sp, unsigned long size,
175+
struct stack_info *info)
174176
{
175177
unsigned long low = (unsigned long)raw_cpu_read(sdei_stack_critical_ptr);
176178
unsigned long high = low + SDEI_STACK_SIZE;
177179

178-
return on_stack(sp, low, high, STACK_TYPE_SDEI_CRITICAL, info);
180+
return on_stack(sp, size, low, high, STACK_TYPE_SDEI_CRITICAL, info);
179181
}
180182

181-
bool _on_sdei_stack(unsigned long sp, struct stack_info *info)
183+
bool _on_sdei_stack(unsigned long sp, unsigned long size, struct stack_info *info)
182184
{
183185
if (!IS_ENABLED(CONFIG_VMAP_STACK))
184186
return false;
185187

186-
if (on_sdei_critical_stack(sp, info))
188+
if (on_sdei_critical_stack(sp, size, info))
187189
return true;
188190

189-
if (on_sdei_normal_stack(sp, info))
191+
if (on_sdei_normal_stack(sp, size, info))
190192
return true;
191193

192194
return false;

arch/arm64/kernel/stacktrace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
7878
if (fp & 0xf)
7979
return -EINVAL;
8080

81-
if (!on_accessible_stack(tsk, fp, &info))
81+
if (!on_accessible_stack(tsk, fp, 16, &info))
8282
return -EINVAL;
8383

8484
if (test_bit(info.type, frame->stacks_done))

0 commit comments

Comments
 (0)