Commit c4a5de20 authored by Aleksa Sarai's avatar Aleksa Sarai Committed by Alastair Robertson

codegen: stack: allow for inter-tid stack aggregation

User-space stacks are quite special in regards to aggregation (and
comparison) between processes. To a first approximation, each pid has a
different memory mapping and thus pointers should not be compared or
aggregated between pids[*]. With ASLR this becomes even more fun, and
thus it is necessary to do usym()-style packing of the stackid for
ustack (since bpf_get_stackid will give you a hash of the pointers --
even in the ustack case).

However, the kernel address space is the same regardless of current->pid
-- and in many cases you want to aggregate between different processes
(and if not, you can always do the packing yourself with @[tid,stack]).

So, we only apply the packing when dealing with ustack. sym() already
does the right thing.

[*] This is more than slightly untrue -- really this depends on
    current->mm and ideally we would aggregate ustack on current->mm.
    Unfortunately this is not a luxury we have at the moment.
Signed-off-by: default avatarAleksa Sarai <cyphar@cyphar.com>
parent c07b54f6
...@@ -36,11 +36,19 @@ void CodegenLLVM::visit(Builtin &builtin) ...@@ -36,11 +36,19 @@ void CodegenLLVM::visit(Builtin &builtin)
expr_ = b_.CreateGetNs(); expr_ = b_.CreateGetNs();
} }
else if (builtin.ident == "stack" || builtin.ident == "ustack") else if (builtin.ident == "stack" || builtin.ident == "ustack")
{
Value *stackid = b_.CreateGetStackId(ctx_, builtin.ident == "ustack");
// Kernel stacks should not be differentiated by tid, since the kernel
// address space is the same between pids (and when aggregating you *want*
// to be able to correlate between pids in most cases). User-space stacks
// are special because of ASLR and so we do usym()-style packing.
if (builtin.ident == "ustack")
{ {
// pack uint64_t with: (uint32_t)stack_id, (uint32_t)pid // pack uint64_t with: (uint32_t)stack_id, (uint32_t)pid
Value *pidhigh = b_.CreateShl(b_.CreateGetPidTgid(), 32); Value *pidhigh = b_.CreateShl(b_.CreateGetPidTgid(), 32);
Value *stackid = b_.CreateGetStackId(ctx_, builtin.ident == "ustack"); stackid = b_.CreateOr(stackid, pidhigh);
expr_ = b_.CreateOr(stackid, pidhigh); }
expr_ = stackid;
} }
else if (builtin.ident == "pid" || builtin.ident == "tid") else if (builtin.ident == "pid" || builtin.ident == "tid")
{ {
......
...@@ -364,21 +364,18 @@ define i64 @"kprobe:f"(i8*) local_unnamed_addr section "s_kprobe:f_1" { ...@@ -364,21 +364,18 @@ define i64 @"kprobe:f"(i8*) local_unnamed_addr section "s_kprobe:f_1" {
entry: entry:
%"@x_val" = alloca i64, align 8 %"@x_val" = alloca i64, align 8
%"@x_key" = alloca i64, align 8 %"@x_key" = alloca i64, align 8
%get_pid_tgid = tail call i64 inttoptr (i64 14 to i64 ()*)()
%1 = shl i64 %get_pid_tgid, 32
%pseudo = tail call i64 @llvm.bpf.pseudo(i64 1, i64 2) %pseudo = tail call i64 @llvm.bpf.pseudo(i64 1, i64 2)
%get_stackid = tail call i64 inttoptr (i64 27 to i64 (i8*, i8*, i64)*)(i8* %0, i64 %pseudo, i64 0) %get_stackid = tail call i64 inttoptr (i64 27 to i64 (i8*, i8*, i64)*)(i8* %0, i64 %pseudo, i64 0)
%2 = or i64 %get_stackid, %1 %1 = bitcast i64* %"@x_key" to i8*
%3 = bitcast i64* %"@x_key" to i8* call void @llvm.lifetime.start.p0i8(i64 -1, i8* nonnull %1)
call void @llvm.lifetime.start.p0i8(i64 -1, i8* nonnull %3)
store i64 0, i64* %"@x_key", align 8 store i64 0, i64* %"@x_key", align 8
%4 = bitcast i64* %"@x_val" to i8* %2 = bitcast i64* %"@x_val" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* nonnull %4) call void @llvm.lifetime.start.p0i8(i64 -1, i8* nonnull %2)
store i64 %2, i64* %"@x_val", align 8 store i64 %get_stackid, i64* %"@x_val", align 8
%pseudo1 = tail call i64 @llvm.bpf.pseudo(i64 1, i64 1) %pseudo1 = tail call i64 @llvm.bpf.pseudo(i64 1, i64 1)
%update_elem = call i64 inttoptr (i64 2 to i64 (i8*, i8*, i8*, i64)*)(i64 %pseudo1, i64* nonnull %"@x_key", i64* nonnull %"@x_val", i64 0) %update_elem = call i64 inttoptr (i64 2 to i64 (i8*, i8*, i8*, i64)*)(i64 %pseudo1, i64* nonnull %"@x_key", i64* nonnull %"@x_val", i64 0)
call void @llvm.lifetime.end.p0i8(i64 -1, i8* nonnull %3) call void @llvm.lifetime.end.p0i8(i64 -1, i8* nonnull %1)
call void @llvm.lifetime.end.p0i8(i64 -1, i8* nonnull %4) call void @llvm.lifetime.end.p0i8(i64 -1, i8* nonnull %2)
ret i64 0 ret i64 0
} }
...@@ -404,11 +401,11 @@ define i64 @"kprobe:f"(i8*) local_unnamed_addr section "s_kprobe:f_1" { ...@@ -404,11 +401,11 @@ define i64 @"kprobe:f"(i8*) local_unnamed_addr section "s_kprobe:f_1" {
entry: entry:
%"@x_val" = alloca i64, align 8 %"@x_val" = alloca i64, align 8
%"@x_key" = alloca i64, align 8 %"@x_key" = alloca i64, align 8
%get_pid_tgid = tail call i64 inttoptr (i64 14 to i64 ()*)()
%1 = shl i64 %get_pid_tgid, 32
%pseudo = tail call i64 @llvm.bpf.pseudo(i64 1, i64 2) %pseudo = tail call i64 @llvm.bpf.pseudo(i64 1, i64 2)
%get_stackid = tail call i64 inttoptr (i64 27 to i64 (i8*, i8*, i64)*)(i8* %0, i64 %pseudo, i64 256) %get_stackid = tail call i64 inttoptr (i64 27 to i64 (i8*, i8*, i64)*)(i8* %0, i64 %pseudo, i64 256)
%2 = or i64 %get_stackid, %1 %get_pid_tgid = tail call i64 inttoptr (i64 14 to i64 ()*)()
%1 = shl i64 %get_pid_tgid, 32
%2 = or i64 %1, %get_stackid
%3 = bitcast i64* %"@x_key" to i8* %3 = bitcast i64* %"@x_key" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* nonnull %3) call void @llvm.lifetime.start.p0i8(i64 -1, i8* nonnull %3)
store i64 0, i64* %"@x_key", align 8 store i64 0, i64* %"@x_key", align 8
......
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