Skip to content
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

Merged
merged 1 commit into from
May 29, 2024
Merged

gadgets: Add trace_lsm #2827

merged 1 commit into from
May 29, 2024

Conversation

i-Pear
Copy link
Contributor

@i-Pear i-Pear commented May 9, 2024

gadgets: Add trace_lsm

This gadget is used as a "strace" for LSM tracepoints.

How to use

ig run --verify-image=false trace_lsm:latest --help  # list all supported LSM tracepoints
ig run --verify-image=false trace_lsm:latest --trace_inode_mkdir  # trace "inode_mkdir" tracepoint
ig run --verify-image=false trace_lsm:latest --trace_all  # trace all supported LSM tracepoints

Copy link
Member

@alban alban left a 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 Show resolved Hide resolved
gadgets/trace_lsm/program.bpf.c Show resolved Hide resolved
F(sem_semop) \
F(netlink_send) \
F(d_instantiate) \
F(getselfattr) \
Copy link
Member

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?

Copy link
Contributor Author

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.

Copy link
Contributor Author

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

Copy link
Contributor Author

@i-Pear i-Pear May 13, 2024

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&para2 in the end of section names, the ebpf collection will fail to load.

Solved.

Copy link
Contributor Author

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


#define TRACE_LSM(name) \
SEC("lsm/" #name) \
int trace_lsm_##name() \
Copy link
Member

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.

Copy link
Contributor Author

@i-Pear i-Pear May 23, 2024

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.

Copy link
Member

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 2 struct 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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

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.

Copy link
Member

@alban alban left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

gadgets/trace_lsm/program.bpf.c Show resolved Hide resolved
Copy link
Member

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.

Copy link
Contributor Author

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.

gadgets/trace_lsm/gadget.yaml Outdated Show resolved Hide resolved
gadgets/trace_lsm/gadget.yaml Outdated Show resolved Hide resolved
gadgets/trace_lsm/gadget.yaml Outdated Show resolved Hide resolved

#define TRACE_LSM(name) \
SEC("lsm/" #name) \
int trace_lsm_##name() \
Copy link
Member

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 2 struct 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.

Copy link
Member

@alban alban left a 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!

gadgets/trace_lsm/program.bpf.c Outdated Show resolved Hide resolved
gadgets/trace_lsm/program.bpf.c Outdated Show resolved Hide resolved
gadgets/trace_lsm/gadget.yaml Outdated Show resolved Hide resolved
gadgets/trace_lsm/gadget.yaml Outdated Show resolved Hide resolved
Co-authored-by: Alban Crequy <albancrequy@linux.microsoft.com>
Signed-off-by: Tianyi Liu <i.pear@outlook.com>
@alban alban merged commit fe294b1 into inspektor-gadget:main May 29, 2024
57 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants