10000 events: improve hidden_kernel_module by OriGlassman · Pull Request #3001 · aquasecurity/tracee · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

events: improve hidden_kernel_module #3001

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

Merged
merged 1 commit into from
May 28, 2023

Conversation

OriGlassman
Copy link
Collaborator

Add improvements:

  • Run after a kernel module was loaded (in addition to periodically)
  • Address possible race condition that my cause false-positive

2. Explain how to test it

./tracee -f e=hidden_kernel_module

@CLAassistant
Copy link
CLAassistant commented Apr 16, 2023

CLA assistant check
All committers have signed the CLA.

Copy link
Collaborator
@NDStrahilevitz NDStrahilevitz left a comment

Choose a reason for hiding this comment

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

The design of channel messaging between derive and tracee.go causes direct coupling between the implementation of the derived event and tracee itself.
As in: If we wanted to separate the event out into a plugin for example, it would be difficult, if not impossible to do so.
As i've written in the first comment, I think most of the logic here should move to a new pipeline stage happening after the derive stage.
Alternatively: maybe a separate modscan package should be added with parallel module scanning logic that can be initialized by the tracee object (although this will require some future development to how tracee registers such objects).

@OriGlassman OriGlassman force-pushed the lkm_finder branch 2 times, most recently from 65e651c to cb9826b Compare April 19, 2023 13:05
@rafaeldtinoco rafaeldtinoco self-requested a review April 19, 2023 13:23
@rafaeldtinoco
Copy link
Contributor
rafaeldtinoco commented Apr 21, 2023

I also want to review this one. One thing I spotted in code already merged:

func clearMap(bpfMap *bpf.BPFMap) error {
	var err error

	var iter = bpfMap.Iterator()
	for iter.Next() {
		addr := binary.LittleEndian.Uint64(iter.Key())
		err = bpfMap.DeleteKey(unsafe.Pointer(&addr))

		if err != nil {
			logger.Errorw("err occurred DeleteKey: " + err.Error())
			return err
		}
	}

	return nil
}

There is a batch libbpf function for that, way more performatic I believe. Check:

https://github.com/aquasecurity/libbpfgo/blob/main/selftest/map-batch/main.go/#L112-L118

EDIT: The fix for this has been proposed at #3014 and i 8000 s being discussed.

@rafaeldtinoco
Copy link
Contributor
rafaeldtinoco commented Apr 21, 2023

Algo, you forgot to raise capabilities at:

https://github.com/aquasecurity/tracee/blob/main/pkg/ebpf/tracee.go/#L1455-L1459

	modsMap, err := t.bpfModule.GetMap("modules_map")
	if err != nil {
		logger.Errorw("err occurred GetMap: " + err.Error())
		return
	}

So, now that E2E tests are dropping capabilities by default, they're failing with:

[2023-04-21T03:47:51.930Z] {"level":"error","ts":1682048788.2915356,"msg":"Ignored key without a value.","ignored":"failed to update map modules_map: operation not permitted"}

EDIT: And you added (in this PR) another GetMap that also needs capabilities raising.

Copy link
Contributor
@rafaeldtinoco rafaeldtinoco left a comment

Choose a reason for hiding this comment

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

@OriGlassman its a very ingenuous work (sorry it took me sometime to read your initial PR already merged and this one improving it). With that said, I left some comments on better documenting it, a few simple changes that might be good, positional changes into new files AND some capabilities raising fixes needed.

I did not take the time to check if the execution path of probes you used, for the race windows u mentioned, between the probes and event processing, could be mitigated by other type of probes, etc.

I know its more of a "research" thing, but I was wondering if this "flag based state machine" approach could be simplified by eBPF only logic making sure there are no races.

Either way, at the end, talking is cheaper than doing.. so good job =D

@rafaeldtinoco
Copy link
Contributor

Hey @OriGlassman, we're releasing tomorrow. I'm moving this to the next milestone, ok ? Let me know if there is any real need from something here to this milestone and we can, maybe, spin off the code and have another PR with a simple change. If not, then next milestone is good I believe.

@yanivagman
Copy link
Collaborator

@OriGlassman not sure what's the status here,
both @NDStrahilevitz @rafaeldtinoco requested changes - is the PR ready for review?

@OriGlassman
Copy link
Collaborator Author

@OriGlassman not sure what's the status here, both @NDStrahilevitz @rafaeldtinoco requested changes - is the PR ready for review?

Was OOO for a couple of weeks, but I'm back now... PR should be ready in the next couple of days.

@OriGlassman OriGlassman force-pushed the lkm_finder branch 2 times, most recently from f25879f to 5290ad5 Compare May 22, 2023 16:47
@OriGlassman OriGlassman force-pushed the lkm_finder branch 2 times, most recently from 2530ca4 to ccd41ee Compare May 24, 2023 14:24
@OriGlassman
Copy link
Collaborator Author

Ready for review from my side guys.. Thanks!
@rafaeldtinoco @yanivagman @NDStrahilevitz

@@ -688,21 +743,25 @@ static __always_inline bool find_modules_from_module_kset_list(program_data_t *p
return !finished_iterating;
}

BPF_QUEUE(walk_mod_tree_queue, rb_node_t, 2048); // used to walk a rb tree
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0) || defined(CORE)
Copy link
Contributor

Choose a reason for hiding this comment

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

4,20 ? Either way, we do not support non CORE any longer. So you can remove this ifdef here.


#ifdef CORE // in non CORE builds it's already defined
Copy link
Contributor

Choose a reason for hiding this comment

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

no need (only CORE supported now)

{
reset_event_args(p);
u64 mod_addr = (u64) mod;
char *mod_name = mod->name;
const char *mod_srcversion = READ_KERN(mod->srcversion);
Copy link
Contributor

Choose a reason for hiding this comment

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

READ_KERN was dropped, should use BPF_CORE_READ (and similar) macros (directly from libbpf UAPI headers).

// Check again with the address being the start of the memory area, since
// there's a chance the module is in /proc/modules but not in /proc/kallsyms (since the
// file can be hooked).
key = (u64) READ_KERN(pos->core_layout.base);
mod_from_map = bpf_map_lookup_elem(&modules_map, &key);
mod = (u64) READ_KERN(pos->core_layout.base);
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto.


return 0;
const char *version = READ_KERN(mod->version);
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto

// get previous of original next
struct list_head *orig_next_ptr = (struct list_head *) (orig_module_data->next);
u64 orig_next_prev_addr = (u64) READ_KERN(orig_next_ptr->prev);
const char *version = READ_KERN(mod->version);
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto

}

// save strings to buf
const char *version = READ_KERN(mod->version);
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto

// If found hidden, it sends a message in the channel, which causes the address and the flags to get passed
// to the lkm submitter program (eBPF), which sends it back to userspace,
// this time with flags that will cause it to get submitted to the user as an event,
err := capabilities.GetInstance().Specific(
Copy link
Contributor

Choose a reason for hiding this comment

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

Should use the EBPF capabilities RING (it already contains the base line for all capabilities needed by picked events PLUS the ones needed for eBPF functions).

func clearMap(bpfMap *bpf.BPFMap) error {
err := capabilities.GetInstance().EBPF(
err := capabilities.GetInstance().Specific(
Copy link
Contributor

Choose a reason for hiding this comment

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

Should use the EBPF capabilities RING (it already contains the base line for all capabilities needed by picked events PLUS the ones needed for eBPF functions).

err = capabilities.GetInstance().Specific(
// FillModulesFromProcFs fills a map with modules from /proc/modules, to be checked in kernel-space for inconsistencies.
func FillModulesFromProcFs(kernelSymbols helpers.KernelSymbolTable) error {
err := capabilities.GetInstance().Specific(
Copy link
Contributor

Choose a reason for hiding this comment

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

Should use the EBPF capabilities RING (it already contains the base line for all capabilities needed by picked events PLUS the ones needed for eBPF functions).

Copy link
Contributor

Choose a reason for hiding this comment

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

IF reading /proc/modules here needs another capability, then you can either add the capability to the base line (by adding as a requirement in the events.go event) OR, if this code is not that frequent you can use Specific() her 10000 e, but with the capability event needed to read /proc/ fs only, not CAP_SYS_ADMIN).

Copy link
Contributor
@rafaeldtinoco rafaeldtinoco left a comment

Choose a reason for hiding this comment

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

I have added a few comments. The PR needs rebasing (and changing READ_KERN macro to BPF_CORE_READ). The rest, I have proposed a chore commit to your personal branch at OriGlassman#1).

I believe we're close to merge, and I really want to spin this code out of tracee.bpf.c to something more "event specific" (I'll do it as chore actions later).

Nice work! I'll rebase myself tomorrow if you're out (Friday for you), lets see if we can get this merged before freezing the tree for the release. Cheers!

@OriGlassman OriGlassman force-pushed the lkm_finder branch 2 times, most recently from 50da68f to 071b3f3 Compare May 27, 2023 16:03
- lkm_seeker: run after a kernel module was loaded (in addition to periodically)
- lkm_seeker: address possible race conditions that may cause false-positive
- lkm_seeker: add technique for newly loaded modules
- Removed logic from do_init_module event
- Added module_free event
- Added module_load event
@OriGlassman
Copy link
Collaborator Author

I have added a few comments. The PR needs rebasing (and changing READ_KERN macro to BPF_CORE_READ). The rest, I have proposed a chore commit to your personal branch at OriGlassman#1).

I believe we're close to merge, and I really want to spin this code out of tracee.bpf.c to something more "event specific" (I'll do it as chore actions later).

Nice work! I'll rebase myself tomorrow if you're out (Friday for you), lets see if we can get this merged before freezing the tree for the release. Cheers!

Done

@rafaeldtinoco rafaeldtinoco dismissed stale reviews from NDStrahilevitz and themself May 28, 2023 00:42

Rafael reviewing before freeze date.

@rafaeldtinoco rafaeldtinoco requested review from rafaeldtinoco and removed request for roikol May 28, 2023 00:47
Copy link
Contributor
@rafaeldtinoco rafaeldtinoco left a comment

Choose a reason for hiding this comment

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

LGTM

@rafaeldtinoco rafaeldtinoco merged commit b855a20 into aquasecurity:main May 28, 2023
geyslan pushed a commit to geyslan/tracee that referenced this pull request Jun 5, 2023
- lkm_seeker: run after a kernel module was loaded (in addition to periodically)
- lkm_seeker: address possible race conditions that may cause false-positive
- lkm_seeker: add technique for newly loaded modules
- removed logic from do_init_module event
- added module_free event
- added module_load event
josedonizetti added a commit to josedonizetti/tracee that referenced this pull request Jun 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants
0