-
Notifications
You must be signed in to change notification settings - Fork 0
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
Added trace, build allowlist, and enforce modes #2
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.
I suggested one change and some comments. Do answer them when you have time.
if sym.Value != 0 { | ||
Cache = append(Cache, SymbolInfo{ | ||
Name: sym.Name, | ||
Start: sym.Value, | ||
End: sym.Value + sym.Size, | ||
}) | ||
} |
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 symbols from elf file are you storing here and for what?
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.
Since goleash retrieves only the addresses of invoked functions from the stack, we need to translate these addresses into function symbols from the elf binary. Function symbols from the binary come along with package names, which is how goleash can infer the caller dependency.
note: i don't resolve symbols at runtime during enforcement; instead, I resolve and cache all the function symbols once during initialization, for performance reasons.
track_syscalls/main.go
Outdated
func runTraceMode(binaryPath string) { | ||
setupAndRun(binaryPath, func(event ebpfEvent, stackTrace []uint64, objs *ebpfObjects) { | ||
// Just log the event | ||
logEvent(event, stackTrace, objs) |
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.
We would only want to log the violation of the event, eventually right? This would log complete stacktrace based on all eBPF comments, right?
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 now, for each execution mode, I am logging everything for debugging and testing purpose. We can eventually add a debug mode flag for this.
But yes, in general, we want to log only violation events for the enforcement mode.
We will log everything, as logEvent does, for a "monitoring" mode (now called 'trace'), if we stille need this mode.
syscalls := make(map[string]map[int]bool) | ||
setupAndRun(binaryPath, func(event ebpfEvent, stackTrace []uint64, objs *ebpfObjects) { | ||
callerPackage := stackanalyzer.GetCallerPackage(stackTrace) | ||
if callerPackage != "" { |
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.
In what case callerPackage is ""
?
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 callerPackage
can be empty in cases where the package name doesn't have the prefix 'github.com'. The logic is implemented into stackanalyzer.GetCallerPackages()
In this current implementation, I was allowlisting (and also enforcing, in runEnforceMode) only third-party packages hosted on github. This implementation skips the generation and enforcement of the allowlist for packages from the Go runtime, the main package, and other local custom packages.
TODO: we should work on a more robust logic for package tracing. For example, third-party packages can be hosted elsewhere (e.g., k8s.io, google.golang.org, etc).
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.
elsewhere (e.g., k8s.io, google.golang.org, etc).
Is there an exhausitve list? Could you host packages on custom URL and download go packages from there?
log.Println("Received signal, exiting..") | ||
return | ||
func runBuildMode(binaryPath string) { | ||
syscalls := make(map[string]map[int]bool) |
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 am bit confused about what this make
function does. Could you explain? 😅
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.
make
in Go create a slice, a dynamic data structure.
We are creating a map of maps. The key of the outer map is the callerPackage
name (string). For each callerPackage
, we have an inner map, which the keys are syscall numbers (int). Each syscall number have an associated boolean value representing "allowed" or "denied". This structure allows for efficient allowlist check.
track_syscalls/main.go
Outdated
case "build": | ||
runBuildMode(*binaryPath) |
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.
Let's rename this to augment
because we take input as allowlist from capslock and we will augment it as we discussed here.
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 agree and i like this new name.
@carminecesarano I tried adding a test resource in order to test
What changes should I make to tracer to achieve this? |
@algomaster99 there is one more hard-coded parameter to set, which is target_comm in the eBPF program. This is the name of the command to trace. In your case, it should be basiccgo. We should make this configurable from the CLI. |
Still unable to get a non-empty allowlist. Let's sit on Friday to pair program. I get some output from the eBPF program but nowhere it prints the stack trace that has go function for |
The problems with test as of now:
|
I managed to solve |
Now we need CI |
f4ce2e6
to
ce01662
Compare
We have a working CI now. I will fix the functionality for building allowlist and then merge. |
Gives a good failure message:
|
@carminecesarano This is the structure of our local go package
|
…tions to get the Caller Package from the stack trace
StopTracer(tracer) | ||
|
||
var expectedCallerFunction = "Go caller function: example.com/filereader.ExecuteMaliciousCGO" | ||
var expectedCallerPackage = "Go caller package: example.com" |
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.
@carminecesarano should this not be "Go caller module: example.com"?
The package would be 'Go caller package: example.com/filreader".
Todo: