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

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