-
Notifications
You must be signed in to change notification settings - Fork 449
Add initial CO:RE support #759
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great!
This is something we are very much looking forward to.
Regarding the vmlinux.h file - this file is huge! Do we have to include it as part of the repo? If yes, will we need to ever change it in the future as newer kernels will be introduced?
Also, have you verified that you code works for non-core compilation in kernel 4.18?
tracee-ebpf/Makefile
Outdated
@@ -19,7 +19,7 @@ OUT_DIR ?= dist | |||
GO_SRC := $(shell find . -type f -name '*.go') | |||
OUT_BIN := $(OUT_DIR)/tracee-ebpf | |||
BPF_SRC := tracee/tracee.bpf.c | |||
OUT_BPF := $(OUT_DIR)/tracee.bpf.$(subst .,_,$(KERN_RELEASE)).$(subst .,_,$(VERSION)).o | |||
OUT_BPF := $(OUT_DIR)/tracee.bpf.o |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that we should keep this line for non CO-RE compilations. It makes sure that the compiled bpf code matches the kernel version and tracee userspace version.
For CO-RE compilation, we should probably remove the KERN_RELEASE part but keep the VERSION part.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. I will pass a compile time variable into the Go code so that it knows what name to look for. I don't think having 'VERSION' is important for the co:re object, how about some indication that it's co:re?
tracee-ebpf/tracee/missing_macros.h
Outdated
/* | ||
* The purpose of this file is to define macros | ||
* that tracee.bpf.c relies on which are defined | ||
* in linux kernel headers but not in vmlinux.h |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So from now on, every macro that we add to tracee.bpf.c should be added to here as well, right?
We should add to the pipeline CO-RE compilation so that we know that we didn't miss adding a macro to this file when needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, and good point!
tracee-ebpf/tracee/missing_macros.h
Outdated
|
||
#define VM_READ 0x00000001 /* currently active flags */ | ||
#define VM_WRITE 0x00000002 | ||
#define VM_EXEC 0x00000004 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to correct indentations in some places in this file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tabs are a scourge
#define READ_KERN(ptr) ({ typeof(ptr) _val; \ | ||
__builtin_memset(&_val, 0, sizeof(_val)); \ | ||
bpf_probe_read(&_val, sizeof(_val), &ptr); \ | ||
_val; \ | ||
}) | ||
#else | ||
// Try using READ_KERN here, just don't embed them in each other |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we previously discussed, maybe we can change this macro to get the arguments in a comma separated list (which is also supported by the BPF_CORE_READ and BPF_PROBE_READ macros given by libbpf)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, this requires a little rewiring but I can do it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we plan to do this one in this PR or do you want to finish it in a separate PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll take a crack at it for this PR
tracee-ebpf/tracee/tracee.bpf.c
Outdated
@@ -256,7 +278,7 @@ struct bpf_map_def SEC("maps") _name = { \ | |||
|
|||
/*=============================== INTERNAL STRUCTS ===========================*/ | |||
|
|||
typedef struct context { | |||
typedef struct internal_proc_context { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason for changing this name?
It is not only the proc context that is in this struct
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a name collision with the enum context
in vmlinux.h. I'll change it to 'internal_context'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So maybe "event_context"?
tracee-ebpf/tracee/tracee.bpf.c
Outdated
bpf_probe_read(&dentry, sizeof(struct dentry*), &mnt_p->mnt_mountpoint); | ||
bpf_probe_read(&mnt_p, sizeof(struct mount*), &mnt_p->mnt_parent); | ||
bpf_probe_read(&mnt_parent_p, sizeof(struct mount*), &mnt_p->mnt_parent); | ||
bpf_probe_read(&vfsmnt, sizeof(struct vfsmount*), (const void*)&mnt_p->mnt); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Weren't these changes already part of your previously commit? rebase?
tracee-ebpf/tracee/tracee.bpf.c
Outdated
struct ipv6_pinfo *np = inet6_sk_own_impl(sk, inet); | ||
|
||
struct in6_addr addr = {}; | ||
addr = get_sock_v6_rcv_saddr(sk); | ||
if (ipv6_addr_any(&addr)){ | ||
if (ipv6_any_addr(&addr)){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function, and inet_sk as well were part of the headers which are now removed for CO-RE, right?
I think that it would be better to put them in the "missing_macros" file (rename?), which should compensate for all the missing things that we had in the headers
@@ -1675,7 +1737,7 @@ int tracepoint__raw_syscalls__sys_enter(struct bpf_raw_tracepoint_args *ctx) | |||
int id = ctx->args[1]; | |||
struct task_struct *task = (struct task_struct *)bpf_get_current_task(); | |||
|
|||
#if defined(CONFIG_ARCH_HAS_SYSCALL_WRAPPER) | |||
if (CONFIG_ARCH_HAS_SYSCALL_WRAPPER) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about the case that CORE is not defined? Does it work?
For x86 arch with kernels >= 4.18 this might not be a problem as this macro is always defined, but for ARM64 this is not case (added in a later kernel version)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I can tell this causes no issue, but I don't have somewhere to test on ARM64?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was added in kernel 4.17 for x86 and 4.20 for ARM64.
As tracee only supports kernels > 4.18, this should be tested on an ARM64 platform with a 4.18/4.19 kernel.
As we don't have any ARM64 platform with these kernels installed to test on, we can keep your changes and address any potential bug that might appear in the future.
8af3ed6
to
59f4822
Compare
I'd like to have the vmlinux.h file as a backup in case the build machine doesn't have the vmlinux file. It shouldn't make a difference in terms of functionality. For example, I don't think we have access to it in our builder container. |
tracee-ebpf/Makefile
Outdated
OUT_BPF := $(OUT_DIR)/tracee.bpf.$(subst .,_,$(KERN_RELEASE)).$(subst .,_,$(VERSION)).o | ||
else | ||
OUT_BPF := $(OUT_DIR)/tracee.bpf.core.o |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be
so that we can check if the bpf code matches the running tracee binary version (this might be relevant if someone upgrades tracee, but already have tracee.bpf.o already compiled to /tmp/tracee, for example)
tracee-ebpf/main.go
Outdated
bpfObjFileName := fmt.Sprintf("tracee.bpf.%s.%s.o", strings.ReplaceAll(tracee.UnameRelease(), ".", "_"), strings.ReplaceAll(version, ".", "_")) | ||
if bpf_core != "" { | ||
bpfObjFileName = "tracee.bpf.o" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be
fmt.Sprintf("tracee.bpf.%s.o", strings.ReplaceAll(version, ".", "_"))
to match my comment in the makefile
tracee-ebpf/tracee/tracee.bpf.c
Outdated
#ifdef asm_inline | ||
#undef asm_inline | ||
#define asm_inline asm | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These lines are common for CO-RE and non-CORE compilations, we can probably remove them from here
tracee-ebpf/tracee/tracee.bpf.c
Outdated
#undef container_of | ||
//#include "bpf_core_read.h" | ||
#include "bpf_core_read.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we have brackets here as we have below?
#define READ_KERN(ptr) ({ typeof(ptr) _val; \ | ||
__builtin_memset(&_val, 0, sizeof(_val)); \ | ||
bpf_probe_read(&_val, sizeof(_val), &ptr); \ | ||
_val; \ | ||
}) | ||
#else | ||
// Try using READ_KERN here, just don't embed them in each other |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we plan to do this one in this PR or do you want to finish it in a separate PR?
@@ -1675,7 +1737,7 @@ int tracepoint__raw_syscalls__sys_enter(struct bpf_raw_tracepoint_args *ctx) | |||
int id = ctx->args[1]; | |||
struct task_struct *task = (struct task_struct *)bpf_get_current_task(); | |||
|
|||
#if defined(CONFIG_ARCH_HAS_SYSCALL_WRAPPER) | |||
if (CONFIG_ARCH_HAS_SYSCALL_WRAPPER) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was added in kernel 4.17 for x86 and 4.20 for ARM64.
As tracee only supports kernels > 4.18, this should be tested on an ARM64 platform with a 4.18/4.19 kernel.
As we don't have any ARM64 platform with these kernels installed to test on, we can keep your changes and address any potential bug that might appear in the future.
98b6863
to
7f68f24
Compare
LGTM! One of my last concerns is the missing macros file. What if some macros are changed between kernel versions? Also, what if these macros are not the same on different systems (for example PAGE_SIZE)? I'm not sure if there are things that we can do to mitigate these problems, but we should be aware of them |
@yanivagman That's a good point, certainly worth the concern. Another way we can achieve CO:RE is to apply the 'preserve_access_index' attribute to all the headers we import in non-co:re variant of tracee-ebpf. Just like how it works in vmlinux.h:
That'd let us keep the macros from the headers but has its own sets of challenges. |
I got a bpf object that was built on a 5.12 kernel running on 4.18 with no issue. I realized that we definitely should be documenting this as part of this PR. Additional things I want to make sure we make follow up issues for/document:
|
I think that we should also try to tackle #776 errors in this PR, but not by generating vmlinux.h. Instead, we should probably wrap the existing kernel version ifdefs with an outer "ifndef CORE". WDYT? Also, can you please rename vmlinux.h to vmlinux_512.h and put it in "x86" folder like done in https://github.com/iovisor/bcc/tree/master/libbpf-tools/x86 ? |
Signed-off-by: grantseltzer <grantseltzer@gmail.com>
This changes the way that tracee reads kernel data structures so that: 1) If a compile time 'CORE' flag is specified, the bpf_core_read helper is used which takes into account btf information extracted from the running kernel. 2) KERN_READ calls are not embedded in one another. This was an issue because the attribute that the BTF helper requires cannot be embedded in one another. This also adds supporting artifacts in the vmlinux.h file which contains baseline definitions of all kernel structures, and a header file which contains all macros tracee uses that aren't defined in the vmlinux.h file. Signed-off-by: grantseltzer <grantseltzer@gmail.com>
38392d0
to
c180569
Compare
RUN echo "deb http://apt.llvm.org/buster/ llvm-toolchain-buster-9 main" >> /etc/apt/sources.list && apt-key adv --keyserver hkps://keyserver.ubuntu.com --recv-keys 15CF4D18AF4F7421 && \ | ||
DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get install -y --no-install-recommends libelf-dev llvm-9 clang-9 && \ | ||
(for tool in "clang" "llc" "llvm-strip"; do path=$(which $tool-9) && ln -s $path ${path%-*}; done) | ||
RUN echo "deb http://apt.llvm.org/buster/ llvm-toolchain-buster-12 main" >> /etc/apt/sources.list && apt-key adv --keyserver hkps://keyserver.ubuntu.com --recv-keys 15CF4D18AF4F7421 && \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
update the docs to reflect that llvm 12 is now required
@@ -28,5 +28,7 @@ jobs: | |||
fi | |||
- name: Build | |||
run: make all DOCKER=1 | |||
- name: Build CO:RE | |||
run: make all DOCKER=1 CORE=y |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we make the examples/scripts use consistent config values: either 1 or y
|
||
# eBPF CO:RE Compilation | ||
|
||
Tracee also can utilize CO:RE (Compile once, run everywhere) technology enabled by libbpf. With this enabled, you can compile the tracee bpf object file on one system, and run it on any kernel with BTF (BPF type format) enabled. To check if your kernel has BTF enabled, check for the `CONFIG_DEBUG_INFO_BTF` in your kernel config. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check for the
CONFIG_DEBUG_INFO_BTF
in your kernel config.
can we write the command to do that?
can we make sure Tracee-eBPF's main does that and prints a nice error?
This changes the way that tracee reads kernel data structures
so that:
If a compile time 'CORE' flag is specified, the bpf_core_read
helper is used which takes into account btf information extracted
from the running kernel.
KERN_READ calls are not embedded in one another. This was an
issue because the attribute that the BTF helper requires cannot
be embedded in one another.
This also adds supporting artifacts in the vmlinux.h file which
contains baseline definitions of all kernel structures, and a
header file which contains all macros tracee uses that aren't
defined in the vmlinux.h file.
Note: This PR does not address how we handle packaging of a CORE enabled tracee binary, nor does it handle testing infra.
Signed-off-by: grantseltzer grantseltzer@gmail.com