Blame SOURCES/rhbz1643997.0025-PR23860-additional-stack-protection-for-strings.patch

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