Skip to content

Commit 5ed8d8b

Browse files
jpoimboeIngo Molnar
authored and
Ingo Molnar
committed
x86/unwind: Move common code into update_stack_state()
The __unwind_start() and unwind_next_frame() functions have some duplicated functionality. They both call decode_frame_pointer() and set state->regs and state->bp accordingly. Move that functionality to a common place in update_stack_state(). Signed-off-by: Josh Poimboeuf <[email protected]> Acked-by: Thomas Gleixner <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Brian Gerst <[email protected]> Cc: Daniel Borkmann <[email protected]> Cc: Dave Jones <[email protected]> Cc: Denys Vlasenko <[email protected]> Cc: H. Peter Anvin <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Peter Zijlstra <[email protected]> Link: http://lkml.kernel.org/r/a2ee4801113f6d2300d58f08f6b69f85edf4eb43.1492020577.git.jpoimboe@redhat.com Signed-off-by: Ingo Molnar <[email protected]>
1 parent b5effd3 commit 5ed8d8b

File tree

1 file changed

+55
-64
lines changed

1 file changed

+55
-64
lines changed

arch/x86/kernel/unwind_frame.c

Lines changed: 55 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -135,41 +135,72 @@ static struct pt_regs *decode_frame_pointer(unsigned long *bp)
135135
return (struct pt_regs *)(regs & ~0x1);
136136
}
137137

138-
static bool update_stack_state(struct unwind_state *state, void *addr,
139-
size_t len)
138+
static bool update_stack_state(struct unwind_state *state,
139+
unsigned long *next_bp)
140140
{
141141
struct stack_info *info = &state->stack_info;
142-
enum stack_type orig_type = info->type;
142+
enum stack_type prev_type = info->type;
143+
struct pt_regs *regs;
144+
unsigned long *frame, *prev_frame_end;
145+
size_t len;
146+
147+
if (state->regs)
148+
prev_frame_end = (void *)state->regs + regs_size(state->regs);
149+
else
150+
prev_frame_end = (void *)state->bp + FRAME_HEADER_SIZE;
151+
152+
/* Is the next frame pointer an encoded pointer to pt_regs? */
153+
regs = decode_frame_pointer(next_bp);
154+
if (regs) {
155+
frame = (unsigned long *)regs;
156+
len = regs_size(regs);
157+
} else {
158+
frame = next_bp;
159+
len = FRAME_HEADER_SIZE;
160+
}
143161

144162
/*
145-
* If addr isn't on the current stack, switch to the next one.
163+
* If the next bp isn't on the current stack, switch to the next one.
146164
*
147165
* We may have to traverse multiple stacks to deal with the possibility
148-
* that 'info->next_sp' could point to an empty stack and 'addr' could
149-
* be on a subsequent stack.
166+
* that info->next_sp could point to an empty stack and the next bp
167+
* could be on a subsequent stack.
150168
*/
151-
while (!on_stack(info, addr, len))
169+
while (!on_stack(info, frame, len))
152170
if (get_stack_info(info->next_sp, state->task, info,
153171
&state->stack_mask))
154172
return false;
155173

156-
if (!state->orig_sp || info->type != orig_type)
157-
state->orig_sp = addr;
174+
/* Make sure it only unwinds up and doesn't overlap the prev frame: */
175+
if (state->orig_sp && state->stack_info.type == prev_type &&
176+
frame < prev_frame_end)
177+
return false;
178+
179+
/* Move state to the next frame: */
180+
if (regs) {
181+
state->regs = regs;
182+
state->bp = NULL;
183+
} else {
184+
state->bp = next_bp;
185+
state->regs = NULL;
186+
}
187+
188+
/* Save the original stack pointer for unwind_dump(): */
189+
if (!state->orig_sp || info->type != prev_type)
190+
state->orig_sp = frame;
158191

159192
return true;
160193
}
161194

162195
bool unwind_next_frame(struct unwind_state *state)
163196
{
164197
struct pt_regs *regs;
165-
unsigned long *next_bp, *next_frame;
166-
size_t next_len;
167-
enum stack_type prev_type = state->stack_info.type;
198+
unsigned long *next_bp;
168199

169200
if (unwind_done(state))
170201
return false;
171202

172-
/* have we reached the end? */
203+
/* Have we reached the end? */
173204
if (state->regs && user_mode(state->regs))
174205
goto the_end;
175206

@@ -200,24 +231,14 @@ bool unwind_next_frame(struct unwind_state *state)
200231
return true;
201232
}
202233

203-
/* get the next frame pointer */
234+
/* Get the next frame pointer: */
204235
if (state->regs)
205236
next_bp = (unsigned long *)state->regs->bp;
206237
else
207-
next_bp = (unsigned long *)READ_ONCE_TASK_STACK(state->task,*state->bp);
238+
next_bp = (unsigned long *)READ_ONCE_TASK_STACK(state->task, *state->bp);
208239

209-
/* is the next frame pointer an encoded pointer to pt_regs? */
210-
regs = decode_frame_pointer(next_bp);
211-
if (regs) {
212-
next_frame = (unsigned long *)regs;
213-
next_len = sizeof(*regs);
214-
} else {
215-
next_frame = next_bp;
216-
next_len = FRAME_HEADER_SIZE;
217-
}
218-
219-
/* make sure the next frame's data is accessible */
220-
if (!update_stack_state(state, next_frame, next_len)) {
240+
/* Move to the next frame if it's safe: */
241+
if (!update_stack_state(state, next_bp)) {
221242
/*
222243
* Don't warn on bad regs->bp. An interrupt in entry code
223244
* might cause a false positive warning.
@@ -228,24 +249,6 @@ bool unwind_next_frame(struct unwind_state *state)
228249
goto bad_address;
229250
}
230251

231-
/* Make sure it only unwinds up and doesn't overlap the last frame: */
232-
if (state->stack_info.type == prev_type) {
233-
if (state->regs && (void *)next_frame < (void *)state->regs + regs_size(state->regs))
234-
goto bad_address;
235-
236-
if (state->bp && (void *)next_frame < (void *)state->bp + FRAME_HEADER_SIZE)
237-
goto bad_address;
238-
}
239-
240-
/* move to the next frame */
241-
if (regs) {
242-
state->regs = regs;
243-
state->bp = NULL;
244-
} else {
245-
state->bp = next_bp;
246-
state->regs = NULL;
247-
}
248-
249252
return true;
250253

251254
bad_address:
@@ -263,13 +266,13 @@ bool unwind_next_frame(struct unwind_state *state)
263266
printk_deferred_once(KERN_WARNING
264267
"WARNING: kernel stack regs at %p in %s:%d has bad 'bp' value %p\n",
265268
state->regs, state->task->comm,
266-
state->task->pid, next_frame);
269+
state->task->pid, next_bp);
267270
unwind_dump(state, (unsigned long *)state->regs);
268271
} else {
269272
printk_deferred_once(KERN_WARNING
270273
"WARNING: kernel stack frame pointer at %p in %s:%d has bad value %p\n",
271274
state->bp, state->task->comm,
272-
state->task->pid, next_frame);
275+
state->task->pid, next_bp);
273276
unwind_dump(state, state->bp);
274277
}
275278
the_end:
@@ -281,35 +284,23 @@ EXPORT_SYMBOL_GPL(unwind_next_frame);
281284
void __unwind_start(struct unwind_state *state, struct task_struct *task,
282285
struct pt_regs *regs, unsigned long *first_frame)
283286
{
284-
unsigned long *bp, *frame;
285-
size_t len;
287+
unsigned long *bp;
286288

287289
memset(state, 0, sizeof(*state));
288290
state->task = task;
289291

290-
/* don't even attempt to start from user mode regs */
292+
/* Don't even attempt to start from user mode regs: */
291293
if (regs && user_mode(regs)) {
292294
state->stack_info.type = STACK_TYPE_UNKNOWN;
293295
return;
294296
}
295297

296-
/* set up the starting stack frame */
297298
bp = get_frame_pointer(task, regs);
298-
regs = decode_frame_pointer(bp);
299-
if (regs) {
300-
state->regs = regs;
301-
frame = (unsigned long *)regs;
302-
len = sizeof(*regs);
303-
} else {
304-
state->bp = bp;
305-
frame = bp;
306-
len = FRAME_HEADER_SIZE;
307-
}
308299

309-
/* initialize stack info and make sure the frame data is accessible */
310-
get_stack_info(frame, state->task, &state->stack_info,
300+
/* Initialize stack info and make sure the frame data is accessible: */
301+
get_stack_info(bp, state->task, &state->stack_info,
311302
&state->stack_mask);
312-
update_stack_state(state, frame, len);
303+
update_stack_state(state, bp);
313304

314305
/*
315306
* The caller can provide the address of the first frame directly

0 commit comments

Comments
 (0)