|
|
e4e640 |
From 06351f7f372c670a630e7595fcd77913ed05742d Mon Sep 17 00:00:00 2001
|
|
|
e4e640 |
From: Serhei Makarov <smakarov@redhat.com>
|
|
|
e4e640 |
Date: Thu, 8 Nov 2018 16:40:40 -0500
|
|
|
e4e640 |
Subject: [PATCH 25/32] PR23860: additional stack protection for strings
|
|
|
e4e640 |
|
|
|
e4e640 |
Fixes for verifier rejection of some cases requiring string copy,
|
|
|
e4e640 |
since the verifier would reject string copy code extending beyond the
|
|
|
e4e640 |
end of the string even if it was not reachable.
|
|
|
e4e640 |
|
|
|
e4e640 |
* bpf-opt.cxx (alloc_literal_str): make sure the offset for a short
|
|
|
e4e640 |
string is at least BPF_MAXSTRINGLEN.
|
|
|
e4e640 |
(zero_stack): New function.
|
|
|
e4e640 |
(program::generate): Use zero_stack() to zero temporary area and
|
|
|
e4e640 |
prevent verifier complaints.
|
|
|
e4e640 |
* testsuite/systemtap.bpf/asm_tests/pr23860.stp: New testcase.
|
|
|
e4e640 |
---
|
|
|
e4e640 |
bpf-opt.cxx | 32 ++++++++++++++++++++++++++-
|
|
|
e4e640 |
testsuite/systemtap.bpf/asm_tests/pr23860.stp | 24 ++++++++++++++++++++
|
|
|
e4e640 |
2 files changed, 55 insertions(+), 1 deletion(-)
|
|
|
e4e640 |
create mode 100644 testsuite/systemtap.bpf/asm_tests/pr23860.stp
|
|
|
e4e640 |
|
|
|
e4e640 |
diff --git a/bpf-opt.cxx b/bpf-opt.cxx
|
|
|
e4e640 |
index 8b9a6ea60..089dcde55 100644
|
|
|
e4e640 |
--- a/bpf-opt.cxx
|
|
|
e4e640 |
+++ b/bpf-opt.cxx
|
|
|
e4e640 |
@@ -36,7 +36,19 @@ alloc_literal_str(program &p, insn_inserter &ins, std::string &str)
|
|
|
e4e640 |
if (tmp_space + str_bytes > MAX_BPF_STACK)
|
|
|
e4e640 |
throw std::runtime_error("string allocation failed due to lack of room on stack");
|
|
|
e4e640 |
|
|
|
e4e640 |
- tmp_space += str_bytes; // TODO: round up for safety?
|
|
|
e4e640 |
+ tmp_space += str_bytes;
|
|
|
e4e640 |
+
|
|
|
e4e640 |
+#if 1
|
|
|
e4e640 |
+ // XXX PR23860: Passing a short (non-padded) string constant can fail
|
|
|
e4e640 |
+ // the verifier, which is not smart enough to determine that accesses
|
|
|
e4e640 |
+ // past the end of the string will never occur. To fix this, make sure
|
|
|
e4e640 |
+ // the string offset is at least -BPF_MAXSTRINGLEN.
|
|
|
e4e640 |
+ //
|
|
|
e4e640 |
+ // Not ideal because an unlucky ordering of allocations may waste space.
|
|
|
e4e640 |
+ if (tmp_space < BPF_MAXSTRINGLEN)
|
|
|
e4e640 |
+ tmp_space = BPF_MAXSTRINGLEN;
|
|
|
e4e640 |
+#endif
|
|
|
e4e640 |
+
|
|
|
e4e640 |
p.use_tmp_space(tmp_space);
|
|
|
e4e640 |
int ofs = -tmp_space;
|
|
|
e4e640 |
|
|
|
e4e640 |
@@ -932,19 +944,37 @@ post_alloc_cleanup (program &p)
|
|
|
e4e640 |
}
|
|
|
e4e640 |
}
|
|
|
e4e640 |
|
|
|
e4e640 |
+// XXX PR23860: Passing a short (non-padded) string constant can fail
|
|
|
e4e640 |
+// the verifier, which is not smart enough to determine that accesses
|
|
|
e4e640 |
+// past the end of the string will never occur. To fix this, start the
|
|
|
e4e640 |
+// program with some code to zero out the temporary stack space.
|
|
|
e4e640 |
+void
|
|
|
e4e640 |
+zero_stack(program &p)
|
|
|
e4e640 |
+{
|
|
|
e4e640 |
+ block *entry_block = p.blocks[0];
|
|
|
e4e640 |
+ insn_before_inserter ins(entry_block, entry_block->first, "zero_stack");
|
|
|
e4e640 |
+ value *frame = p.lookup_reg(BPF_REG_10);
|
|
|
e4e640 |
+ for (int32_t ofs = -(int32_t)p.max_tmp_space; ofs < 0; ofs += 4)
|
|
|
e4e640 |
+ p.mk_st(ins, BPF_W, frame, (int32_t)ofs, p.new_imm(0));
|
|
|
e4e640 |
+}
|
|
|
e4e640 |
+
|
|
|
e4e640 |
void
|
|
|
e4e640 |
program::generate()
|
|
|
e4e640 |
{
|
|
|
e4e640 |
#ifdef DEBUG_CODEGEN
|
|
|
e4e640 |
std::cerr << "DEBUG BEFORE OPT " << *this << std::endl;
|
|
|
e4e640 |
#endif
|
|
|
e4e640 |
+
|
|
|
e4e640 |
lower_str_values(*this);
|
|
|
e4e640 |
+ zero_stack(*this);
|
|
|
e4e640 |
+
|
|
|
e4e640 |
fixup_operands(*this);
|
|
|
e4e640 |
thread_jumps(*this);
|
|
|
e4e640 |
fold_jumps(*this);
|
|
|
e4e640 |
reorder_blocks(*this);
|
|
|
e4e640 |
reg_alloc(*this);
|
|
|
e4e640 |
post_alloc_cleanup(*this);
|
|
|
e4e640 |
+
|
|
|
e4e640 |
#ifdef DEBUG_CODEGEN
|
|
|
e4e640 |
std::cerr << "DEBUG AFTER OPT " << *this << std::endl;
|
|
|
e4e640 |
#endif
|
|
|
e4e640 |
diff --git a/testsuite/systemtap.bpf/asm_tests/pr23860.stp b/testsuite/systemtap.bpf/asm_tests/pr23860.stp
|
|
|
e4e640 |
new file mode 100644
|
|
|
e4e640 |
index 000000000..bd3e05f66
|
|
|
e4e640 |
--- /dev/null
|
|
|
e4e640 |
+++ b/testsuite/systemtap.bpf/asm_tests/pr23860.stp
|
|
|
e4e640 |
@@ -0,0 +1,24 @@
|
|
|
e4e640 |
+function foo:string ()
|
|
|
e4e640 |
+%{ /* bpf */ /* pure */ /* unprivileged */ /* stable */
|
|
|
e4e640 |
+ 0xbf, $$, "key", -, -; /* mov $$, "key" */
|
|
|
e4e640 |
+%}
|
|
|
e4e640 |
+
|
|
|
e4e640 |
+function bar:string ()
|
|
|
e4e640 |
+{
|
|
|
e4e640 |
+ return "kez"
|
|
|
e4e640 |
+}
|
|
|
e4e640 |
+
|
|
|
e4e640 |
+global t
|
|
|
e4e640 |
+
|
|
|
e4e640 |
+probe begin {
|
|
|
e4e640 |
+ t[foo()] = 4
|
|
|
e4e640 |
+ t[bar()] = 6
|
|
|
e4e640 |
+ printf("U t[key]=%d, t[kez]=%d should be 4,6\n", t["key"], t["kez"])
|
|
|
e4e640 |
+}
|
|
|
e4e640 |
+
|
|
|
e4e640 |
+probe kernel.function("vfs_read") {
|
|
|
e4e640 |
+ t[foo()] = 5
|
|
|
e4e640 |
+ t[bar()] = 7
|
|
|
e4e640 |
+ printf("K t[key]=%d, t[kez]=%d should be 5,7\n", t["key"], t["kez"])
|
|
|
e4e640 |
+ exit()
|
|
|
e4e640 |
+}
|
|
|
e4e640 |
--
|
|
|
e4e640 |
2.14.5
|
|
|
e4e640 |
|