forked from elastic/beats
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Socket dataset: Workaround for bogus dereference in kernel 5.x (elast…
…ic#15771) This is a tentative workaround for the problems in Auditbeat's system/socket dataset when run under 5.x kernels. On older kernels, we could rely on dereferencing a NULL or invalid pointer returning zeroed memory. However, seems that in the tested 5.x kernels is not the case. Dereferencing a NULL pointer returns bogus memory, which causes some wrong codepaths to be taken in a couple of kprobes defined by the dataset. This so far seems only to affect udp_sendmsg and udpv6_sendmsg, which caused it to attribute traffic to bogus IP addresses. In turn this caused the test-connected-udp system tests to fail.
- Loading branch information
Showing
5 changed files
with
223 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
// or more contributor license agreements. Licensed under the Elastic License; | ||
// you may not use this file except in compliance with the Elastic License. | ||
|
||
// +build linux,386 linux,amd64 | ||
|
||
package guess | ||
|
||
import ( | ||
"encoding/hex" | ||
"os" | ||
"strconv" | ||
"syscall" | ||
|
||
"github.com/elastic/beats/libbeat/common" | ||
"github.com/elastic/beats/x-pack/auditbeat/module/system/socket/helper" | ||
"github.com/elastic/beats/x-pack/auditbeat/tracing" | ||
) | ||
|
||
/* | ||
This is not an actual guess but a helper to check if the kernel kprobe | ||
subsystem returns garbage after dereferencing a null pointer. | ||
This code is run when the AUDITBEAT_SYSTEM_SOCKET_CHECK_DEREF environment | ||
variable is set to a value greater than 0. When set, it will run the given | ||
number of times, print the hexdump to the debug logs if non-zero memory is | ||
found and set the NULL_PTR_DEREF_IS_OK (bool) variable. | ||
*/ | ||
|
||
func init() { | ||
if err := Registry.AddGuess(&guessDeref{}); err != nil { | ||
panic(err) | ||
} | ||
} | ||
|
||
const ( | ||
flagName = "NULL_PTR_DEREF_IS_OK" | ||
envVar = "AUDITBEAT_SYSTEM_SOCKET_CHECK_DEREF" | ||
) | ||
|
||
type guessDeref struct { | ||
ctx Context | ||
tries int | ||
garbage bool | ||
} | ||
|
||
// Condition allows the guess to run if the environment variable is set to a | ||
// decimal value greater than zero. | ||
func (g *guessDeref) Condition(ctx Context) (run bool, err error) { | ||
v := os.Getenv(envVar) | ||
if v == "" { | ||
return false, nil | ||
} | ||
if g.tries, err = strconv.Atoi(v); err != nil || g.tries <= 0 { | ||
return false, nil | ||
} | ||
return true, nil | ||
} | ||
|
||
// Name of this guess. | ||
func (g *guessDeref) Name() string { | ||
return "guess_deref" | ||
} | ||
|
||
// Provides returns the names of discovered variables. | ||
func (g *guessDeref) Provides() []string { | ||
return []string{ | ||
flagName, | ||
} | ||
} | ||
|
||
// Requires declares the variables required to run this guess. | ||
func (g *guessDeref) Requires() []string { | ||
return []string{ | ||
"SYS_UNAME", | ||
} | ||
} | ||
|
||
// Probes returns a kprobe on uname() that dumps the first bytes | ||
// pointed to by its first parameter. | ||
func (g *guessDeref) Probes() ([]helper.ProbeDef, error) { | ||
return []helper.ProbeDef{ | ||
{ | ||
Probe: tracing.Probe{ | ||
Type: tracing.TypeKProbe, | ||
Name: "guess_null_ptr_deref", | ||
Address: "{{.SYS_UNAME}}", | ||
Fetchargs: helper.MakeMemoryDump("{{.P1}}", 0, credDumpBytes), | ||
}, | ||
Decoder: tracing.NewDumpDecoder, | ||
}, | ||
}, nil | ||
} | ||
|
||
// Prepare is a no-op. | ||
func (g *guessDeref) Prepare(ctx Context) error { | ||
g.ctx = ctx | ||
return nil | ||
} | ||
|
||
// Terminate is a no-op. | ||
func (g *guessDeref) Terminate() error { | ||
return nil | ||
} | ||
|
||
// MaxRepeats returns the configured number of repeats. | ||
func (g *guessDeref) MaxRepeats() int { | ||
return g.tries | ||
} | ||
|
||
// Extract receives the memory read through a null pointer and checks if it's | ||
// zero or garbage. | ||
func (g *guessDeref) Extract(ev interface{}) (common.MapStr, bool) { | ||
raw := ev.([]byte) | ||
if len(raw) != credDumpBytes { | ||
return nil, false | ||
} | ||
for _, val := range raw { | ||
if val != 0 { | ||
g.ctx.Log.Errorf("Found non-zero memory:\n%s", hex.Dump(raw)) | ||
g.garbage = true | ||
break | ||
} | ||
} | ||
// Repeat until completed all tries | ||
if g.tries--; g.tries > 0 { | ||
return nil, true | ||
} | ||
return common.MapStr{ | ||
flagName: !g.garbage, | ||
}, true | ||
} | ||
|
||
// Trigger invokes the uname syscall with a null parameter. | ||
func (g *guessDeref) Trigger() error { | ||
var ptr *syscall.Utsname | ||
syscall.Uname(ptr) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters