bcc: Use bpf_probe_read_user in tools and provide backward compatibility
s390 has overlapping address space for user and kernel. Hence separation of
bpf_probe_read_user and bpf_probe_read_kernel is essential. Commit 6ae08ae3dea2
("bpf: Add probe_read_{user, kernel} and probe_read_{user, kernel}_str
helpers") introduced these changes into the kernel. However, bcc tools does not
respect it.
As a workaround, perform the following:
1. Use bpf_probe_read_user() explicitly in the bcc tools.
2. When kernel version < 5.5, perform the checks if the
bpf_probe_read_user kernel helper is present in the backported kernel
as well. If not found, then fallback from bpf_probe_read_user to
bpf_probe_read.
Signed-off-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
diff --git a/src/cc/export/helpers.h b/src/cc/export/helpers.h
index b38b3f2..b0ffc4f 100644
--- a/src/cc/export/helpers.h
+++ b/src/cc/export/helpers.h
@@ -602,6 +602,7 @@
static int (*bpf_skb_output)(void *ctx, void *map, __u64 flags, void *data,
__u64 size) =
(void *)BPF_FUNC_skb_output;
+
static int (*bpf_probe_read_user)(void *dst, __u32 size,
const void *unsafe_ptr) =
(void *)BPF_FUNC_probe_read_user;
@@ -887,8 +888,8 @@
#if defined(__TARGET_ARCH_x86)
#define bpf_target_x86
#define bpf_target_defined
-#elif defined(__TARGET_ARCH_s930x)
-#define bpf_target_s930x
+#elif defined(__TARGET_ARCH_s390x)
+#define bpf_target_s390x
#define bpf_target_defined
#elif defined(__TARGET_ARCH_arm64)
#define bpf_target_arm64
@@ -905,7 +906,7 @@
#if defined(__x86_64__)
#define bpf_target_x86
#elif defined(__s390x__)
-#define bpf_target_s930x
+#define bpf_target_s390x
#elif defined(__aarch64__)
#define bpf_target_arm64
#elif defined(__powerpc__)
@@ -923,7 +924,7 @@
#define PT_REGS_RC(ctx) ((ctx)->gpr[3])
#define PT_REGS_IP(ctx) ((ctx)->nip)
#define PT_REGS_SP(ctx) ((ctx)->gpr[1])
-#elif defined(bpf_target_s930x)
+#elif defined(bpf_target_s390x)
#define PT_REGS_PARM1(x) ((x)->gprs[2])
#define PT_REGS_PARM2(x) ((x)->gprs[3])
#define PT_REGS_PARM3(x) ((x)->gprs[4])
diff --git a/src/cc/frontends/clang/b_frontend_action.cc b/src/cc/frontends/clang/b_frontend_action.cc
index 89511ef..6087c80 100644
--- a/src/cc/frontends/clang/b_frontend_action.cc
+++ b/src/cc/frontends/clang/b_frontend_action.cc
@@ -37,6 +37,7 @@
#include "bcc_libbpf_inc.h"
#include "libbpf.h"
+#include "bcc_syms.h"
namespace ebpf {
@@ -82,6 +83,30 @@
return ret;
}
+static std::string check_bpf_probe_read_user(llvm::StringRef probe) {
+ if (probe.str() == "bpf_probe_read_user" ||
+ probe.str() == "bpf_probe_read_user_str") {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)
+ return probe.str();
+#else
+ // Check for probe_user symbols in backported kernels before fallback
+ void *resolver = bcc_symcache_new(-1, nullptr);
+ uint64_t addr = 0;
+ bool found = bcc_symcache_resolve_name(resolver, nullptr,
+ "bpf_probe_read_user", &addr) >= 0 ? true: false;
+ if (found)
+ return probe.str();
+
+ if (probe.str() == "bpf_probe_read_user") {
+ return "bpf_probe_read";
+ } else {
+ return "bpf_probe_read_str";
+ }
+#endif
+ }
+ return "";
+}
+
using std::map;
using std::move;
using std::set;
@@ -947,6 +972,22 @@
} else if (Call->getCalleeDecl()) {
NamedDecl *Decl = dyn_cast<NamedDecl>(Call->getCalleeDecl());
if (!Decl) return true;
+
+ string text;
+
+ std::string probe = check_bpf_probe_read_user(Decl->getName());
+ if (probe != "") {
+ vector<string> probe_args;
+
+ for (auto arg : Call->arguments())
+ probe_args.push_back(
+ rewriter_.getRewrittenText(expansionRange(arg->getSourceRange())));
+
+ text = probe + "(" + probe_args[0] + ", " + probe_args[1] + ", " +
+ probe_args[2] + ")";
+ rewriter_.ReplaceText(expansionRange(Call->getSourceRange()), text);
+ }
+
if (AsmLabelAttr *A = Decl->getAttr<AsmLabelAttr>()) {
// Functions with the tag asm("llvm.bpf.extra") are implemented in the
// rewriter rather than as a macro since they may also include nested
@@ -959,10 +1000,10 @@
}
vector<string> args;
+
for (auto arg : Call->arguments())
args.push_back(rewriter_.getRewrittenText(expansionRange(arg->getSourceRange())));
- string text;
if (Decl->getName() == "incr_cksum_l3") {
text = "bpf_l3_csum_replace_(" + fn_args_[0]->getName().str() + ", (u64)";
text += args[0] + ", " + args[1] + ", " + args[2] + ", sizeof(" + args[2] + "))";
@@ -994,8 +1035,10 @@
text = "({ u64 __addr = 0x0; ";
text += "_bpf_readarg_" + current_fn_ + "_" + args[0] + "(" +
args[1] + ", &__addr, sizeof(__addr));";
- text += "bpf_probe_read(" + args[2] + ", " + args[3] +
- ", (void *)__addr);";
+
+ text += check_bpf_probe_read_user(StringRef("bpf_probe_read_user"));
+
+ text += "(" + args[2] + ", " + args[3] + ", (void *)__addr);";
text += "})";
rewriter_.ReplaceText(expansionRange(Call->getSourceRange()), text);
} else if (Decl->getName() == "bpf_usdt_readarg") {
diff --git a/tools/ttysnoop.py b/tools/ttysnoop.py
index 058dc7e..24c1180 100755
--- a/tools/ttysnoop.py
+++ b/tools/ttysnoop.py
@@ -80,7 +80,7 @@
// bpf_probe_read() can only use a fixed size, so truncate to count
// in user space:
struct data_t data = {};
- bpf_probe_read(&data.buf, BUFSIZE, (void *)buf);
+ bpf_probe_read_user(&data.buf, BUFSIZE, (void *)buf);
if (count > BUFSIZE)
data.count = BUFSIZE;
else