Skip to content

Commit b1e0324

Browse files
jpoimboeIngo Molnar
authored andcommitted
objtool: Detect infinite recursion
I don't _think_ dead_end_function() can get into a recursive loop, but just in case, stop the loop and print a warning. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Andy Lutomirski <luto@kernel.org> Cc: Arnaldo Carvalho de Melo <acme@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@kernel.org> Cc: Bernd Petrovitsch <bernd@petrovitsch.priv.at> Cc: Borislav Petkov <bp@alien8.de> Cc: Chris J Arges <chris.j.arges@canonical.com> Cc: Jiri Slaby <jslaby@suse.cz> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Michal Marek <mmarek@suse.cz> Cc: Namhyung Kim <namhyung@gmail.com> Cc: Pedro Alves <palves@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: live-patching@vger.kernel.org Link: http://lkml.kernel.org/r/ff489a63e6feb88abb192cfb361d81626dcf3e89.1457502970.git.jpoimboe@redhat.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
1 parent 81bfafc commit b1e0324

File tree

1 file changed

+33
-12
lines changed

1 file changed

+33
-12
lines changed

tools/objtool/builtin-check.c

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,14 @@ static bool ignore_func(struct objtool_file *file, struct symbol *func)
121121
*
122122
* For local functions, we have to detect them manually by simply looking for
123123
* the lack of a return instruction.
124+
*
125+
* Returns:
126+
* -1: error
127+
* 0: no dead end
128+
* 1: dead end
124129
*/
125-
static bool dead_end_function(struct objtool_file *file, struct symbol *func)
130+
static int __dead_end_function(struct objtool_file *file, struct symbol *func,
131+
int recursion)
126132
{
127133
int i;
128134
struct instruction *insn, *func_insn;
@@ -144,19 +150,19 @@ static bool dead_end_function(struct objtool_file *file, struct symbol *func)
144150
};
145151

146152
if (func->bind == STB_WEAK)
147-
return false;
153+
return 0;
148154

149155
if (func->bind == STB_GLOBAL)
150156
for (i = 0; i < ARRAY_SIZE(global_noreturns); i++)
151157
if (!strcmp(func->name, global_noreturns[i]))
152-
return true;
158+
return 1;
153159

154160
if (!func->sec)
155-
return false;
161+
return 0;
156162

157163
func_insn = find_instruction(file, func->sec, func->offset);
158164
if (!func_insn)
159-
return false;
165+
return 0;
160166

161167
insn = func_insn;
162168
list_for_each_entry_from(insn, &file->insns, list) {
@@ -167,11 +173,11 @@ static bool dead_end_function(struct objtool_file *file, struct symbol *func)
167173
empty = false;
168174

169175
if (insn->type == INSN_RETURN)
170-
return false;
176+
return 0;
171177
}
172178

173179
if (empty)
174-
return false;
180+
return 0;
175181

176182
/*
177183
* A function can have a sibling call instead of a return. In that
@@ -190,7 +196,7 @@ static bool dead_end_function(struct objtool_file *file, struct symbol *func)
190196

191197
if (!dest)
192198
/* sibling call to another file */
193-
return false;
199+
return 0;
194200

195201
if (dest->sec != func->sec ||
196202
dest->offset < func->offset ||
@@ -201,16 +207,28 @@ static bool dead_end_function(struct objtool_file *file, struct symbol *func)
201207
if (!dest_func)
202208
continue;
203209

204-
return dead_end_function(file, dest_func);
210+
if (recursion == 5) {
211+
WARN_FUNC("infinite recursion (objtool bug!)",
212+
dest->sec, dest->offset);
213+
return -1;
214+
}
215+
216+
return __dead_end_function(file, dest_func,
217+
recursion + 1);
205218
}
206219
}
207220

208221
if (insn->type == INSN_JUMP_DYNAMIC)
209222
/* sibling call */
210-
return false;
223+
return 0;
211224
}
212225

213-
return true;
226+
return 1;
227+
}
228+
229+
static int dead_end_function(struct objtool_file *file, struct symbol *func)
230+
{
231+
return __dead_end_function(file, func, 0);
214232
}
215233

216234
/*
@@ -809,8 +827,11 @@ static int validate_branch(struct objtool_file *file,
809827
break;
810828
}
811829

812-
if (dead_end_function(file, insn->call_dest))
830+
ret = dead_end_function(file, insn->call_dest);
831+
if (ret == 1)
813832
return warnings;
833+
if (ret == -1)
834+
warnings++;
814835

815836
/* fallthrough */
816837
case INSN_CALL_DYNAMIC:

0 commit comments

Comments
 (0)