Commit d8bb097d authored by yonghong-song's avatar yonghong-song Committed by GitHub

Merge pull request #1792 from pchaigno/refactor-ext-ptr-assignments

Refactor external pointer assignments
parents c817cfd6 44d34732
...@@ -214,11 +214,56 @@ ProbeVisitor::ProbeVisitor(ASTContext &C, Rewriter &rewriter, ...@@ -214,11 +214,56 @@ ProbeVisitor::ProbeVisitor(ASTContext &C, Rewriter &rewriter,
set<Decl *> &m, bool track_helpers) : set<Decl *> &m, bool track_helpers) :
C(C), rewriter_(rewriter), m_(m), track_helpers_(track_helpers) {} C(C), rewriter_(rewriter), m_(m), track_helpers_(track_helpers) {}
bool ProbeVisitor::assignsExtPtr(Expr *E, int *nbAddrOf) {
if (IsContextMemberExpr(E)) {
*nbAddrOf = 0;
return true;
}
ProbeChecker checker = ProbeChecker(E, ptregs_, track_helpers_,
true);
if (checker.is_transitive()) {
// The negative of the number of dereferences is the number of addrof. In
// an assignment, if we went through n addrof before getting the external
// pointer, then we'll need n dereferences on the left-hand side variable
// to get to the external pointer.
*nbAddrOf = -checker.get_nb_derefs();
return true;
}
if (E->getStmtClass() == Stmt::CallExprClass) {
CallExpr *Call = dyn_cast<CallExpr>(E);
if (MemberExpr *Memb = dyn_cast<MemberExpr>(Call->getCallee()->IgnoreImplicit())) {
StringRef memb_name = Memb->getMemberDecl()->getName();
if (DeclRefExpr *Ref = dyn_cast<DeclRefExpr>(Memb->getBase())) {
if (SectionAttr *A = Ref->getDecl()->getAttr<SectionAttr>()) {
if (!A->getName().startswith("maps"))
return false;
if (memb_name == "lookup" || memb_name == "lookup_or_init") {
if (m_.find(Ref->getDecl()) != m_.end()) {
// Retrieved an ext. pointer from a map, mark LHS as ext. pointer.
// Pointers from maps always need a single dereference to get the
// actual value. The value may be an external pointer but cannot
// be a pointer to an external pointer as the verifier prohibits
// storing known pointers (to map values, context, the stack, or
// the packet) in maps.
*nbAddrOf = 1;
return true;
}
}
}
}
}
}
return false;
}
bool ProbeVisitor::VisitVarDecl(VarDecl *D) { bool ProbeVisitor::VisitVarDecl(VarDecl *D) {
if (Expr *E = D->getInit()) { if (Expr *E = D->getInit()) {
ProbeChecker checker = ProbeChecker(E, ptregs_, track_helpers_, true); int nbAddrOf;
if (checker.is_transitive() || IsContextMemberExpr(E)) { if (assignsExtPtr(E, &nbAddrOf)) {
tuple<Decl *, int> pt = make_tuple(D, checker.get_nb_derefs()); // The negative of the number of addrof is the number of dereferences.
tuple<Decl *, int> pt = make_tuple(D, -nbAddrOf);
set_ptreg(pt); set_ptreg(pt);
} }
} }
...@@ -249,42 +294,11 @@ bool ProbeVisitor::VisitCallExpr(CallExpr *Call) { ...@@ -249,42 +294,11 @@ bool ProbeVisitor::VisitCallExpr(CallExpr *Call) {
bool ProbeVisitor::VisitBinaryOperator(BinaryOperator *E) { bool ProbeVisitor::VisitBinaryOperator(BinaryOperator *E) {
if (!E->isAssignmentOp()) if (!E->isAssignmentOp())
return true; return true;
// copy probe attribute from RHS to LHS if present
ProbeChecker checker = ProbeChecker(E->getRHS(), ptregs_, track_helpers_,
true);
if (checker.is_transitive()) {
// The negative of the number of dereferences is the number of addrof. In
// an assignment, if we went through n addrof before getting the external
// pointer, then we'll need n dereferences on the left-hand side variable
// to get to the external pointer.
ProbeSetter setter(&ptregs_, -checker.get_nb_derefs());
setter.TraverseStmt(E->getLHS());
} else if (E->getRHS()->getStmtClass() == Stmt::CallExprClass) {
CallExpr *Call = dyn_cast<CallExpr>(E->getRHS());
if (MemberExpr *Memb = dyn_cast<MemberExpr>(Call->getCallee()->IgnoreImplicit())) {
StringRef memb_name = Memb->getMemberDecl()->getName();
if (DeclRefExpr *Ref = dyn_cast<DeclRefExpr>(Memb->getBase())) {
if (SectionAttr *A = Ref->getDecl()->getAttr<SectionAttr>()) {
if (!A->getName().startswith("maps"))
return true;
if (memb_name == "lookup" || memb_name == "lookup_or_init") { // copy probe attribute from RHS to LHS if present
if (m_.find(Ref->getDecl()) != m_.end()) { int nbAddrOf;
// Retrieved an ext. pointer from a map, mark LHS as ext. pointer. if (assignsExtPtr(E->getRHS(), &nbAddrOf)) {
// Pointers from maps always need a single dereference to get the ProbeSetter setter(&ptregs_, nbAddrOf);
// actual value. The value may be an external pointer but cannot
// be a pointer to an external pointer as the verifier prohibits
// storing known pointers (to map values, context, the stack, or
// the packet) in maps.
ProbeSetter setter(&ptregs_, 1);
setter.TraverseStmt(E->getLHS());
}
}
}
}
}
} else if (IsContextMemberExpr(E->getRHS())) {
ProbeSetter setter(&ptregs_);
setter.TraverseStmt(E->getLHS()); setter.TraverseStmt(E->getLHS());
} }
return true; return true;
...@@ -355,7 +369,6 @@ bool ProbeVisitor::IsContextMemberExpr(Expr *E) { ...@@ -355,7 +369,6 @@ bool ProbeVisitor::IsContextMemberExpr(Expr *E) {
bool found = false; bool found = false;
MemberExpr *M; MemberExpr *M;
for (M = Memb; M; M = dyn_cast<MemberExpr>(M->getBase())) { for (M = Memb; M; M = dyn_cast<MemberExpr>(M->getBase())) {
memb_visited_.insert(M);
rhs_start = M->getLocEnd(); rhs_start = M->getLocEnd();
base = M->getBase(); base = M->getBase();
member = M->getMemberLoc(); member = M->getMemberLoc();
......
...@@ -99,6 +99,7 @@ class ProbeVisitor : public clang::RecursiveASTVisitor<ProbeVisitor> { ...@@ -99,6 +99,7 @@ class ProbeVisitor : public clang::RecursiveASTVisitor<ProbeVisitor> {
void set_ctx(clang::Decl *D) { ctx_ = D; } void set_ctx(clang::Decl *D) { ctx_ = D; }
std::set<std::tuple<clang::Decl *, int>> get_ptregs() { return ptregs_; } std::set<std::tuple<clang::Decl *, int>> get_ptregs() { return ptregs_; }
private: private:
bool assignsExtPtr(clang::Expr *E, int *nbAddrOf);
bool IsContextMemberExpr(clang::Expr *E); bool IsContextMemberExpr(clang::Expr *E);
clang::SourceRange expansionRange(clang::SourceRange range); clang::SourceRange expansionRange(clang::SourceRange range);
template <unsigned N> template <unsigned N>
......
...@@ -538,7 +538,7 @@ int process(struct xdp_md *ctx) { ...@@ -538,7 +538,7 @@ int process(struct xdp_md *ctx) {
t = b["act"] t = b["act"]
self.assertEqual(len(t), 32); self.assertEqual(len(t), 32);
def test_ext_ptr_maps(self): def test_ext_ptr_maps1(self):
bpf_text = """ bpf_text = """
#include <uapi/linux/ptrace.h> #include <uapi/linux/ptrace.h>
#include <net/sock.h> #include <net/sock.h>
...@@ -568,6 +568,35 @@ int trace_exit(struct pt_regs *ctx) { ...@@ -568,6 +568,35 @@ int trace_exit(struct pt_regs *ctx) {
b.load_func("trace_entry", BPF.KPROBE) b.load_func("trace_entry", BPF.KPROBE)
b.load_func("trace_exit", BPF.KPROBE) b.load_func("trace_exit", BPF.KPROBE)
def test_ext_ptr_maps2(self):
bpf_text = """
#include <uapi/linux/ptrace.h>
#include <net/sock.h>
#include <bcc/proto.h>
BPF_HASH(currsock, u32, struct sock *);
int trace_entry(struct pt_regs *ctx, struct sock *sk,
struct sockaddr *uaddr, int addr_len) {
u32 pid = bpf_get_current_pid_tgid();
currsock.update(&pid, &sk);
return 0;
};
int trace_exit(struct pt_regs *ctx) {
u32 pid = bpf_get_current_pid_tgid();
struct sock **skpp = currsock.lookup(&pid);
if (skpp) {
struct sock *skp = *skpp;
return skp->__sk_common.skc_dport;
}
return 0;
}
"""
b = BPF(text=bpf_text)
b.load_func("trace_entry", BPF.KPROBE)
b.load_func("trace_exit", BPF.KPROBE)
def test_ext_ptr_maps_reverse(self): def test_ext_ptr_maps_reverse(self):
bpf_text = """ bpf_text = """
#include <uapi/linux/ptrace.h> #include <uapi/linux/ptrace.h>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment