Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
9 changes: 7 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ GOLANGCI := $(GOPATH)/bin/golangci-lint

.PHONY: analyzer
analyzer:
go build -o ./bin/analyzer ./main.go
go build -o ./bin/vm-compact ./main.go

.PHONY: get
get:
Expand All @@ -22,4 +22,9 @@ lint: get_lint
.PHONY: test
test:
@echo " > \033[32mRunning sprinter-api tests...\033[0m "
go test -v ./...
go test -v ./...

# Run e2e tests
.PHONY: e2e-test
e2e-test:
go test ./e2e_tests -tags=integration -v
7 changes: 3 additions & 4 deletions analyzer/opcode/opcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,6 @@ func (op *opcode) Analyze(path string, withTrace bool) ([]*analyzer.Issue, error
if err != nil { // non-reachable portion ignored
continue
}
if !withTrace {
source.CallStack = nil
}

issue := &analyzer.Issue{
Severity: analyzer.IssueSeverityCritical,
CallStack: source,
Expand All @@ -58,6 +54,9 @@ func (op *opcode) Analyze(path string, withTrace bool) ([]*analyzer.Issue, error
if common.ShouldIgnoreSource(source, op.profile.IgnoredFunctions) {
issue.Severity = analyzer.IssueSeverityWarning
}
if !withTrace {
source.CallStack = nil
}
issues = append(issues, issue)
}
}
Expand Down
7 changes: 3 additions & 4 deletions analyzer/syscall/asm_syscall.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,6 @@ func (a *asmSyscallAnalyser) Analyze(path string, withTrace bool) ([]*analyzer.I
if err != nil { // non-reachable portion ignored
continue
}
if !withTrace {
source.CallStack = nil
}

severity := analyzer.IssueSeverityCritical
if common.ShouldIgnoreSource(source, a.profile.IgnoredFunctions) {
Expand All @@ -80,7 +77,9 @@ func (a *asmSyscallAnalyser) Analyze(path string, withTrace bool) ([]*analyzer.I
message = fmt.Sprintf("Potential NOOP Syscall Detected: %d", syscall.Number)
severity = analyzer.IssueSeverityWarning
}

if !withTrace {
source.CallStack = nil
}
issues = append(issues, &analyzer.Issue{
Severity: severity,
Message: message,
Expand Down
4 changes: 2 additions & 2 deletions common/entrypoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ func ProgramEntrypoint(arch string) func(function string) bool {
function == "runtime.schedinit" ||
function == "runtime.newproc" ||
function == "runtime.mstart" ||
function == "main.main" || // main
strings.Contains(function, "main.main") || // main and closures or anonymous functions
strings.Contains(function, ".init.") || // all init functions
strings.HasSuffix(function, ".init") // vars
}
case "mips64":
return func(function string) bool {
return function == "runtime.rt0_go" || // start point of a go program
function == "main.main" || // main
strings.Contains(function, "main.main") || // main and closures or anonymous functions
strings.Contains(function, ".init.") || // all init functions
strings.HasSuffix(function, ".init") // vars
}
Expand Down
115 changes: 115 additions & 0 deletions e2e_tests/e2e_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//go:build integration

package e2etest

import (
"bytes"
"encoding/json"
"fmt"
"os/exec"
"path/filepath"
"testing"

"github.com/ChainSafe/vm-compat/analyzer"
"github.com/stretchr/testify/assert"
)

const testdataDir = "testdata"

type testcase struct {
path string
isPassing bool
}

func runTest(t *testing.T, vmProfile string, cases map[string]testcase) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
cmd := exec.Command("../bin/vm-compact", "analyze", "-vm-profile", vmProfile, "-format", "json", tc.path)

var out bytes.Buffer
var errOut bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &errOut
err := cmd.Run()
if err != nil {
t.Fatalf("Failed to run CLI: %v. errorOutput: %s", err, errOut.String())
}

issues := []*analyzer.Issue{}
json.Unmarshal(out.Bytes(), &issues)

if tc.isPassing {
for i := range issues {
assert.NotEqual(t, analyzer.IssueSeverityCritical, issues[i].Severity, fmt.Sprintf("Found Critical issue %v", issues[i]))
}
} else {
var criticalIssueFound bool
for i := range issues {
if issues[i].Severity == analyzer.IssueSeverityCritical {
criticalIssueFound = true
}
}

assert.True(t, criticalIssueFound, "No critical issues found")
}
})
}
}

func TestSinglethreadedMips(t *testing.T) {
cases := map[string]testcase{
"hello_world": {
path: filepath.Join(testdataDir, "hello"),
isPassing: true,
},
"sys-clockgettime": {
path: filepath.Join(testdataDir, "sys-clockgettime"),
},
"sys-getrandom": {
path: filepath.Join(testdataDir, "sys-getrandom"),
},
"sys-statx": {
path: filepath.Join(testdataDir, "sys-statx"),
isPassing: true,
},
}
runTest(t, "../profile/cannon/cannon-singlethreaded-32.yaml", cases)
}

func TestMultithreadedMips(t *testing.T) {
cases := map[string]testcase{
"hello_world": {
path: filepath.Join(testdataDir, "hello"),
isPassing: true,
},
"sys-clockgettime": {
path: filepath.Join(testdataDir, "sys-clockgettime"),
},
"sys-getrandom": {
path: filepath.Join(testdataDir, "sys-getrandom"),
},
"sys-statx": {
path: filepath.Join(testdataDir, "sys-statx"),
},
}
runTest(t, "../profile/cannon/cannon-multithreaded-32.yaml", cases)
}

func TestMultithreadedMips64(t *testing.T) {
cases := map[string]testcase{
"hello_world": {
path: filepath.Join(testdataDir, "hello"),
isPassing: true,
},
"sys-clockgettime": {
path: filepath.Join(testdataDir, "sys-clockgettime"),
},
"sys-getrandom": {
path: filepath.Join(testdataDir, "sys-getrandom"),
},
"sys-statx": {
path: filepath.Join(testdataDir, "sys-statx"),
},
}
runTest(t, "../profile/cannon/cannon-multithreaded-64.yaml", cases)
}
3 changes: 3 additions & 0 deletions e2e_tests/testdata/hello/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module hello

go 1.22.2
7 changes: 7 additions & 0 deletions e2e_tests/testdata/hello/hello.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package main

import "fmt"

func hello() {
fmt.Println("Hello World")
}
5 changes: 5 additions & 0 deletions e2e_tests/testdata/hello/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package main

func main() {
hello()
}
3 changes: 3 additions & 0 deletions e2e_tests/testdata/sys-clockgettime/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module sys-clockgettime

go 1.22.2
14 changes: 14 additions & 0 deletions e2e_tests/testdata/sys-clockgettime/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import "syscall"

const (
SYS_CLOCK_GETTIME = 228
)

func main() {
_, _, err := syscall.Syscall(SYS_CLOCK_GETTIME, 0, 0, 0)
if err != 0 {
panic(err)
}
}
3 changes: 3 additions & 0 deletions e2e_tests/testdata/sys-getrandom/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module sys-getrandom

go 1.22.2
14 changes: 14 additions & 0 deletions e2e_tests/testdata/sys-getrandom/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import "syscall"

const (
SYS_GETRANDOM = 318
)

func main() {
_, _, err := syscall.Syscall(SYS_GETRANDOM, 0, 0, 0)
if err != 0 {
panic(err)
}
}
Binary file added e2e_tests/testdata/sys-getrandom/mybinary_mips64
Binary file not shown.
3 changes: 3 additions & 0 deletions e2e_tests/testdata/sys-statx/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module sys-statx

go 1.22.2
23 changes: 23 additions & 0 deletions e2e_tests/testdata/sys-statx/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package main

import (
"fmt"
"syscall"
)

func main() {
const SYS_STATX = 4075

// Dummy arguments
dirfd := uintptr(0) // 0 is a valid dummy value
path := uintptr(0) // NULL pointer to simulate a dummy invoke
flags := uintptr(0)
mask := uintptr(0)
statxbuf := uintptr(0) // NULL pointer instead of actual struct

// Invoke the syscall with dummy values
_, _, err := syscall.RawSyscall6(SYS_STATX, dirfd, path, flags, mask, statxbuf, 0)

// Expected to fail, but still confirms the syscall was invoked
fmt.Println("Syscall 4075 (statx) invoked. Error:", err)
}
1 change: 1 addition & 0 deletions profile/cannon/cannon-multithreaded-64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ ignored_functions:
- 'syscall.setrlimit'
- 'runtime.morestack'
- 'runtime.abort'
- 'runtime.switchToCrashStack0'

allowed_opcodes:
- opcode: '0x2'
Expand Down
Loading