From: Alexandre Chartre <alexandre.chartre@oracle.com>
To: x86@kernel.org
Cc: linux-kernel@vger.kernel.org, jpoimboe@redhat.com,
peterz@infradead.org, jthierry@redhat.com, tglx@linutronix.de,
alexandre.chartre@oracle.com
Subject: [PATCH V3 6/9] objtool: Report inconsistent stack changes in alternative
Date: Tue, 14 Apr 2020 12:36:15 +0200 [thread overview]
Message-ID: <20200414103618.12657-7-alexandre.chartre@oracle.com> (raw)
In-Reply-To: <20200414103618.12657-1-alexandre.chartre@oracle.com>
To allow a valid stack unwinding, an alternative should have code
where the same stack changes happens at the same places as in the
original code. Add a check in objtool to validate that stack changes
in alternative are effectively consitent with the original code.
Signed-off-by: Alexandre Chartre <alexandre.chartre@oracle.com>
---
tools/objtool/check.c | 155 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 155 insertions(+)
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 0574ce8e232d..9488a9c7be24 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -2724,6 +2724,156 @@ static int validate_reachable_instructions(struct objtool_file *file)
return 0;
}
+static int validate_alternative_state(struct objtool_file *file,
+ struct instruction *first,
+ struct instruction *prev,
+ struct instruction *current,
+ bool include_current)
+{
+ struct instruction *alt_insn, *alt_first;
+ unsigned long roff_prev, roff_curr, roff;
+ int count, err = 0, err_alt, alt_num;
+ struct alternative *alt;
+ const char *err_str;
+
+ /*
+ * Check that instructions in alternatives between the corresponding
+ * previous and current instructions, have the same stack state.
+ */
+
+ /* use relative offset to find corresponding alt instructions */
+ roff_prev = prev->offset - first->offset;
+ roff_curr = current->offset - first->offset;
+ alt_num = 0;
+
+ list_for_each_entry(alt, &first->alts, list) {
+ if (!alt->insn->alt_group)
+ continue;
+
+ alt_num++;
+ alt_first = alt->insn;
+ count = 0;
+ err_alt = 0;
+
+ for (alt_insn = alt_first;
+ alt_insn && alt_insn->alt_group == alt_first->alt_group;
+ alt_insn = next_insn_same_sec(file, alt_insn)) {
+
+ roff = alt_insn->offset - alt_first->offset;
+ if (roff < roff_prev)
+ continue;
+
+ if (roff > roff_curr ||
+ (roff == roff_curr && !include_current))
+ break;
+
+ count++;
+ /*
+ * The first instruction we check must be aligned with
+ * the corresponding "prev" instruction because stack
+ * change should happen at the same offset.
+ */
+ if (count == 1 && roff != roff_prev) {
+ err_str = "misaligned alternative state change";
+ err_alt++;
+ }
+
+ if (!err_alt && memcmp(&prev->state, &alt_insn->state,
+ sizeof(struct insn_state))) {
+ err_str = "invalid alternative state";
+ err_alt++;
+ }
+
+ /*
+ * On error, report the error and stop checking
+ * this alternative but continue checking other
+ * alternatives.
+ */
+ if (err_alt) {
+ if (!err) {
+ WARN_FUNC("error in alternative",
+ first->sec, first->offset);
+ }
+ WARN_FUNC("in alternative %d",
+ alt_first->sec, alt_first->offset,
+ alt_num);
+ WARN_FUNC("%s", alt_insn->sec, alt_insn->offset,
+ err_str);
+
+ err += err_alt;
+ break;
+ }
+ }
+ }
+
+ return err;
+}
+
+static int validate_alternative(struct objtool_file *file)
+{
+ struct instruction *first, *prev, *next, *insn;
+ bool in_alternative;
+ int err;
+
+ err = 0;
+ first = prev = NULL;
+ in_alternative = false;
+ for_each_insn(file, insn) {
+ if (insn->ignore || !insn->alt_group || insn->ignore_alts)
+ continue;
+
+ if (!in_alternative) {
+ if (list_empty(&insn->alts))
+ continue;
+
+ /*
+ * Setup variables to start the processing of a
+ * new alternative.
+ */
+ first = insn;
+ prev = insn;
+ err = 0;
+ in_alternative = true;
+
+ } else if (!err && memcmp(&prev->state, &insn->state,
+ sizeof(struct insn_state))) {
+ /*
+ * The stack state has changed and no error was
+ * reported for this alternative. Check that the
+ * stack state is the same in all alternatives
+ * between the last check and up to this instruction.
+ *
+ * Once we have an error, stop checking the
+ * alternative because once the stack state is
+ * inconsistent, it will likely be inconsistent
+ * for other instructions as well.
+ */
+ err = validate_alternative_state(file, first,
+ prev, insn, false);
+ prev = insn;
+ }
+
+ /*
+ * If the next instruction is in the same alternative then
+ * continue with processing this alternative. Otherwise
+ * that's the end of this alternative so check there is no
+ * stack state changes in remaining instructions (if no
+ * error was reported yet).
+ */
+ next = list_next_entry(insn, list);
+ if (next && !next->ignore &&
+ next->alt_group == first->alt_group)
+ continue;
+
+ if (!err)
+ err = validate_alternative_state(file, first,
+ prev, insn, true);
+ in_alternative = false;
+ }
+
+ return 0;
+}
+
static struct objtool_file file;
int check(const char *_objname, bool orc)
@@ -2769,6 +2919,11 @@ int check(const char *_objname, bool orc)
goto out;
warnings += ret;
+ ret = validate_alternative(&file);
+ if (ret < 0)
+ goto out;
+ warnings += ret;
+
if (!warnings) {
ret = validate_reachable_instructions(&file);
if (ret < 0)
--
2.18.2
next prev parent reply other threads:[~2020-04-14 10:35 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-04-14 10:36 [PATCH V3 0/9] objtool changes to check retpoline code Alexandre Chartre
2020-04-14 10:36 ` [PATCH V3 1/9] objtool: is_fentry_call() crashes if call has no destination Alexandre Chartre
2020-05-01 18:22 ` [tip: objtool/core] " tip-bot2 for Alexandre Chartre
2020-04-14 10:36 ` [PATCH V3 2/9] objtool: Allow branches within the same alternative Alexandre Chartre
2020-04-14 10:36 ` [PATCH V3 3/9] objtool: Add support for intra-function calls Alexandre Chartre
2020-04-14 12:07 ` Julien Thierry
2020-04-16 12:12 ` Miroslav Benes
2020-05-01 18:22 ` [tip: objtool/core] " tip-bot2 for Alexandre Chartre
2020-04-14 10:36 ` [PATCH V3 4/9] objtool: Handle return instruction with intra-function call Alexandre Chartre
2020-04-14 13:44 ` Julien Thierry
2020-04-14 10:36 ` [PATCH V3 5/9] objtool: Add return address unwind hints Alexandre Chartre
2020-04-14 16:16 ` Peter Zijlstra
2020-04-14 16:40 ` Alexandre Chartre
2020-04-14 17:56 ` Peter Zijlstra
2020-04-14 18:31 ` Alexandre Chartre
2020-04-14 18:42 ` Peter Zijlstra
2020-04-14 19:27 ` Alexandre Chartre
2020-04-14 19:48 ` Peter Zijlstra
2020-04-14 10:36 ` Alexandre Chartre [this message]
2020-04-14 15:35 ` [PATCH V3 6/9] objtool: Report inconsistent stack changes in alternative Julien Thierry
2020-04-14 22:41 ` kbuild test robot
2020-04-14 23:09 ` kbuild test robot
2020-04-16 14:18 ` Peter Zijlstra
2020-04-16 14:43 ` Alexandre Chartre
2020-04-14 10:36 ` [PATCH V3 7/9] x86/speculation: Change __FILL_RETURN_BUFFER to work with objtool Alexandre Chartre
2020-04-14 10:36 ` [PATCH V3 8/9] x86/speculation: Add return address unwind hints to retpoline and RSB stuffing Alexandre Chartre
2020-04-14 10:36 ` [PATCH V3 9/9] x86/speculation: Annotate intra-function calls Alexandre Chartre
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200414103618.12657-7-alexandre.chartre@oracle.com \
--to=alexandre.chartre@oracle.com \
--cc=jpoimboe@redhat.com \
--cc=jthierry@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=peterz@infradead.org \
--cc=tglx@linutronix.de \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).