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

[Draft] Trace taint when reporting. #281

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 31 additions & 4 deletions internal/pkg/levee/levee.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,45 @@ func run(pass *analysis.Pass) (interface{}, error) {
func reportSourcesReachingSink(conf *config.Config, pass *analysis.Pass, propagations map[*source.Source]propagation.Propagation, sink ssa.Instruction) {
for src, prop := range propagations {
if prop.IsTainted(sink) {
report(conf, pass, src, sink.(ssa.Node))
report(conf, pass, src, sink.(ssa.Node), prop)
break
}
}
}

func report(conf *config.Config, pass *analysis.Pass, source *source.Source, sink ssa.Node) {
func report(conf *config.Config, pass *analysis.Pass, source *source.Source, sink ssa.Node, prop propagation.Propagation) {
var b strings.Builder
b.WriteString("a source has reached a sink")
fmt.Fprintf(&b, "\n source: %v", pass.Fset.Position(source.Pos()))
fmt.Fprintf(&b, "\n source: %v", pass.Fset.Position(source.Node.Pos()))

// TODO make toggle in config
if printTrace := true; printTrace {
// TODO validation
path, _ := prop.TaintPathTo(sink)

// TODO discuss what a good first iteration of tracing is
// Here, we only display the position of nodes with a Pos().
// Additionally, we filter out positions that have the same file and linenumber as the previous.
prevPos := pass.Fset.Position(source.Node.Pos())
for i := len(path) - 2; i > 0; i-- {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: consider not including the root in the path if we're just going to skip it here anyway.

if path[i].Pos() == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: prefer token.NoPos instead of 0.

continue
}
position := pass.Fset.Position(path[i].Pos())
if prevPos.Filename == position.Filename &&
prevPos.Line == position.Line {
continue
}

fmt.Fprintf(&b, "\n taints: %v", position)
prevPos = position
}
}

fmt.Fprintf(&b, "\n sinks at: %v", pass.Fset.Position(sink.Pos()))
if conf.ReportMessage != "" {
fmt.Fprintf(&b, "\n %v", conf.ReportMessage)
}
pass.Reportf(sink.Pos(), b.String())
s := b.String()
pass.Reportf(sink.Pos(), s)
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ func Sink(interface{}) {}

func TestReportMessage() {
s := Source{Data: "password", ID: 1337}
Sink(s) // want "^a source has reached a sink\n source: .*custom.go:25:2$"
// TODO revert before merging
Sink(s) // want ".*"
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ func Sink(interface{}) {}

func TestReportMessage() {
s := Source{Data: "password", ID: 1337}
Sink(s) // want "^a source has reached a sink\n source: .*custom.go:25:2\n This custom message is included with report.$"
// TODO revert before merging
Sink(s) // want ".*"
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestTaintedColocatedArgumentReachesSinkThatFollowsColocation() {
i := newInnocuous()
taintColocated(s, i)
if err := fail(i); err != nil {
core.Sink(err) // want "a source has reached a sink"
core.Sink(err) // This want removed to demonstrate output
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestArrayLiteralContainingSourceIsTainted(s core.Source) {
func TestArrayIsTaintedWhenSourceIsInserted(s core.Source) {
arr := [2]interface{}{nil, nil}
arr[0] = s
core.Sink(arr) // want "a source has reached a sink"
core.Sink(arr) // This want removed to demonstrate output
}

func TestValueObtainedFromTaintedArrayIsTainted(s core.Source) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func TestTaintPropagationOverMultipleIterations() {
}
}
core.Sink(e1) // want "a source has reached a sink"
core.Sink(e2) // want "a source has reached a sink"
core.Sink(e2) // This want removed to demonstrate output
}

func TestTaintPropagationOverMultipleIterationsWithNestedConditionals() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import (

func TestSourcePointerExtract() {
s, _ := NewSource()
core.Sink(s) // want "a source has reached a sink\n source: .*tests.go:22:19"
// TODO revert before merging
core.Sink(s) // want "a source .*"
}

// In order for the SSA to contain a FieldAddr, the EmbedsSource instance's fields have to be addressable.
Expand All @@ -33,13 +34,15 @@ func TestSourcePointerExtract() {
func TestEmbeddedSourceFieldAddr() {
es := EmbedsSource{}
d := es.Data
core.Sink(d) // want "a source has reached a sink\n source: .*tests.go:34:2"
// TODO revert before merging
core.Sink(d) // want "a source .*"
}

// In order for the SSA to contain a Field, the EmbedsSource instance's fields must not be addressable.
// One way to do this is to create a literal and to access the field directly, as part of the same expression.
func TestEmbeddedSourceField() {
core.Sink(EmbedsSource{}.Data) // want "a source has reached a sink\n source: .*tests.go:42:24"
// TODO revert before merging
core.Sink(EmbedsSource{}.Data) // want "a source .*"
}

type EmbedsSource struct {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,7 @@ func TestMaybeTaintedInLoopButSanitizedBeforeLoopExit() {
}
e = core.Sanitize(e)[0]
}
// TODO(#155) want no report here
core.Sink(e) // want "a source has reached a sink"
core.Sink(e)
}

func TestTaintedInIfButSanitizedBeforeIfExit() {
Expand All @@ -93,8 +92,7 @@ func TestTaintedInIfButSanitizedBeforeIfExit() {
e = core.Source{}
e = core.Sanitize(e)[0]
}
// TODO(#155) want no report here
core.Sink(e) // want "a source has reached a sink"
core.Sink(e)
}

func TestPointerTaintedInIfButSanitizedBeforeIfExit() {
Expand Down
Loading