-
Notifications
You must be signed in to change notification settings - Fork 185
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
gadgets: Add trace_lsm #2827
gadgets: Add trace_lsm #2827
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.
Thanks. I commented with some small things to change, and some ideas for future PRs.
gadgets/trace_lsm/program.bpf.c
Outdated
F(sem_semop) \ | ||
F(netlink_send) \ | ||
F(d_instantiate) \ | ||
F(getselfattr) \ |
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.
On Linux 6.6.13-100.fc38.x86_64 I get:
program trace_lsm_getselfattr: attach LSM/LSMMac: getselfattr LSM hook not supported
This LSM hook was added in Linux 6.8:
torvalds/linux@a04a119
For this PR, could you remove the hooks that were added recently, so this gadget works on most kernels?
I wonder how to make the user experience better (in another PR). What about a flag "besteffort":
SEC("lsm/getselfattr/besteffort")
And when defined, ig would ignore the error when the LSM hook is not supported in the current kernel.
In this way, the gadget author would decide if it's better to fail or not. Or maybe that should be something defined in gadget.yaml, so the ELF conventions don't diverge between libbpf, cilium/ebpf or ig. Alternatively, it could be something that the WASM module decide based on the BTF data, e.g. in union security_list_options
(cc @mauriciovasquezbernal ). What do you think?
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.
The besteffort
flag seems to be a general option. Maybe we can create a new macro SEC_BESTEFFORT
, and it will add strings [besteffort]
in the end of section names. We will identify and erase it while attaching.
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.
uprobe/libc:malloc?failstrategy=ignore&option2=foo2
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'm wrong, the cillum/ebpf
library will verify the section name while creating ebpf collections (NewCollectionWithOptions), by finding the symbols in kernel (findProgramTargetInKernel). So if we add ?para¶2
in the end of section names, the ebpf collection will fail to load.
Solved.
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.
For older kernels, the attach LSM/LSMMac: getselfattr LSM hook not supported
error message also comes from NewCollectionWithOptions
, not our attaching process. So to support the besteffort
flag, we may also need to hack cillum/ebpf
.
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.
Issue in cillium/ebpf: #https://github.com/cilium/ebpf/discussions/1470
|
||
#define TRACE_LSM(name) \ | ||
SEC("lsm/" #name) \ | ||
int trace_lsm_##name() \ |
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.
To be really useful, this gadget should access parameters.
And when it is a well-known type such as struct path *
or struct file *
, print the full path using include/gadget/filesystem.h
.
I wonder if type matches relocations can help (#2542).
But that's for another 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 wonder if type matches relocations can help (#2542).
Do you mean we can use bpf_core_type_matches
to find struct path *
types automatically?
update: seems not. we still need to write types for each argument, and manually output the interested ones.
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 was thinking of something like this:
#define TRACE_LSM(name) \
union security_list_options___##name##arg1 { \
int (* #name)(const struct path *); \
}; \
union security_list_options___##name##arg2 { \
int (* #name)(const struct path *, const struct path *); \
}; \
\
/* ignore attaching failures for compatibility */ \
SEC("lsm/" #name) \
int trace_lsm_##name(void *arg1, void *arg2, void *arg3) \
struct event *event; /*TODO: alloc event in a map */ \
char *path_str = NULL; \
struct path *path = NULL; \
if (bpf_core_type_matches(security_list_options___##name##arg1)) { \
path = (struct path *) arg1; \
} \
if (bpf_core_type_matches(security_list_options___##name##arg2)) { \
path = (struct path *) arg1; \
} \
if (path) { \
path_str = get_path_str(&fs->pwd); \
} \
if (path_str) { \
bpf_probe_read_kernel_str(event->path, MAX_STRING_SIZE, path_str); \
} \
...
But that would work only for hooks with a single struct path *
argument (for the arg1 test):
- path_truncate
- path_chroot
- inode_getattr
Or with 2struct path *
arguments: - sb_pivotroot
- move_mount
But others would be missed, so I don't know if it is worth it.
In any cases, it is not for this 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 haven't much understood the code here, are there structs like security_list_options___*
in kernel?
We can discuss about this tomorrow.
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.
Looking into this: https://lwn.net/Articles/967893/
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 finally gave up after trying for several hours, I couldn't find any CORE API that can be used to match parameter types.
2fb8377
to
b175251
Compare
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.
Thanks!
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.
It would be good to have a README.md to improve the artifacthub page.
This could be done in another 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.
Currently I don't have a k8s environment, will provide readme files for all my gadgets later.
|
||
#define TRACE_LSM(name) \ | ||
SEC("lsm/" #name) \ | ||
int trace_lsm_##name() \ |
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 was thinking of something like this:
#define TRACE_LSM(name) \
union security_list_options___##name##arg1 { \
int (* #name)(const struct path *); \
}; \
union security_list_options___##name##arg2 { \
int (* #name)(const struct path *, const struct path *); \
}; \
\
/* ignore attaching failures for compatibility */ \
SEC("lsm/" #name) \
int trace_lsm_##name(void *arg1, void *arg2, void *arg3) \
struct event *event; /*TODO: alloc event in a map */ \
char *path_str = NULL; \
struct path *path = NULL; \
if (bpf_core_type_matches(security_list_options___##name##arg1)) { \
path = (struct path *) arg1; \
} \
if (bpf_core_type_matches(security_list_options___##name##arg2)) { \
path = (struct path *) arg1; \
} \
if (path) { \
path_str = get_path_str(&fs->pwd); \
} \
if (path_str) { \
bpf_probe_read_kernel_str(event->path, MAX_STRING_SIZE, path_str); \
} \
...
But that would work only for hooks with a single struct path *
argument (for the arg1 test):
- path_truncate
- path_chroot
- inode_getattr
Or with 2struct path *
arguments: - sb_pivotroot
- move_mount
But others would be missed, so I don't know if it is worth it.
In any cases, it is not for this 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.
Some small changes remaining to do. It should be good to go after that. Thanks!
Co-authored-by: Alban Crequy <albancrequy@linux.microsoft.com> Signed-off-by: Tianyi Liu <i.pear@outlook.com>
gadgets: Add trace_lsm
This gadget is used as a "strace" for LSM tracepoints.
How to use