diff --git a/analyzer/syscall/asm_syscall.go b/analyzer/syscall/asm_syscall.go index fb4ff5f..894d2e3 100644 --- a/analyzer/syscall/asm_syscall.go +++ b/analyzer/syscall/asm_syscall.go @@ -55,7 +55,7 @@ func (a *asmSyscallAnalyser) Analyze(path string, withTrace bool) ([]*analyzer.I } for _, syscall := range syscalls { // Categorize syscall - if slices.Contains(a.profile.AllowedSycalls, syscall.Number) { + if slices.Contains(a.profile.AllowedSyscalls, syscall.Number) { continue } sources, err := common.TraceAllAsmCaller( diff --git a/analyzer/syscall/go_syscall.go b/analyzer/syscall/go_syscall.go index 61a607a..51ccf07 100644 --- a/analyzer/syscall/go_syscall.go +++ b/analyzer/syscall/go_syscall.go @@ -51,7 +51,7 @@ func (a *goSyscallAnalyser) Analyze(path string, withTrace bool) ([]*analyzer.Is issues := make([]*analyzer.Issue, 0) for i := range syscalls { syscll := syscalls[i] - if slices.Contains(a.profile.AllowedSycalls, syscll.num) { + if slices.Contains(a.profile.AllowedSyscalls, syscll.num) { continue } stackTrace := a.edgeToCallStack(syscll.edgeStack, fset, withTrace) diff --git a/cmd/analyze.go b/cmd/analyze.go index 7a938db..107534b 100644 --- a/cmd/analyze.go +++ b/cmd/analyze.go @@ -20,9 +20,12 @@ import ( var ( VMProfileFlag = &cli.StringFlag{ - Name: "vm-profile", - Usage: "Path to the VM profile config file", - Required: true, + Name: "vm-profile", + Usage: "vm profile against which compatibity should be checked. Options: cannon-singlethreaded-32, cannon-multithreaded-32, cannon-multithreaded-64", + } + VMProfileConfigFlag = &cli.StringFlag{ + Name: "vm-profile-config", + Usage: "Path to the VM profile config file", } AnalysisTypeFlag = &cli.StringFlag{ Name: "analysis-type", @@ -67,6 +70,7 @@ func CreateAnalyzeCommand(action cli.ActionFunc) *cli.Command { Action: action, Flags: []cli.Flag{ VMProfileFlag, + VMProfileConfigFlag, AnalysisTypeFlag, DisassemblyOutputFlag, FormatFlag, @@ -80,8 +84,16 @@ func CreateAnalyzeCommand(action cli.ActionFunc) *cli.Command { var AnalyzeCommand = CreateAnalyzeCommand(AnalyzeCompatibility) func AnalyzeCompatibility(ctx *cli.Context) error { - vmProfile := ctx.Path(VMProfileFlag.Name) - prof, err := profile.LoadProfile(vmProfile) + var vmProfile *profile.VMProfile + var err error + prof := ctx.Path(VMProfileFlag.Name) + if prof != "" { + vmProfile, err = profile.LoadProfile(prof) + } else { + profPath := ctx.Path(VMProfileConfigFlag.Name) + vmProfile, err = profile.LoadProfileFromConfig(profPath) + } + if err != nil { return fmt.Errorf("error loading profile: %w", err) } @@ -94,25 +106,25 @@ func AnalyzeCompatibility(ctx *cli.Context) error { withTrace := ctx.Bool(TraceFlag.Name) baselineReport := ctx.Path(BaselineReport.Name) - disassemblyPath, err = disassemble(prof, source, disassemblyPath) + disassemblyPath, err = disassemble(vmProfile, source, disassemblyPath) if err != nil { return fmt.Errorf("error disassembling the file: %w", err) } - issues, err := analyze(prof, disassemblyPath, analysisType, withTrace) + issues, err := analyze(vmProfile, disassemblyPath, analysisType, withTrace) if err != nil { return fmt.Errorf("analysis failed: %w", err) } if baselineReport != "" { - err = compareReport(issues, format, reportOutputPath, prof, baselineReport) + err = compareReport(issues, format, reportOutputPath, vmProfile, baselineReport) if err != nil { return fmt.Errorf("error comparing reports: %w", err) } return nil } - if err := writeReport(issues, format, reportOutputPath, prof); err != nil { + if err := writeReport(issues, format, reportOutputPath, vmProfile); err != nil { return fmt.Errorf("unable to write report: %w", err) } return nil diff --git a/cmd/trace.go b/cmd/trace.go index d901646..b59aaf9 100644 --- a/cmd/trace.go +++ b/cmd/trace.go @@ -35,6 +35,7 @@ func CreateTraceCommand(action cli.ActionFunc) *cli.Command { Action: action, Flags: []cli.Flag{ VMProfileFlag, + VMProfileConfigFlag, FunctionNameFlag, SourceTypeFlag, }, @@ -44,8 +45,16 @@ func CreateTraceCommand(action cli.ActionFunc) *cli.Command { var TraceCommand = CreateTraceCommand(TraceCaller) func TraceCaller(ctx *cli.Context) error { - vmProfile := ctx.Path(VMProfileFlag.Name) - prof, err := profile.LoadProfile(vmProfile) + var vmProfile *profile.VMProfile + var err error + prof := ctx.Path(VMProfileFlag.Name) + if prof != "" { + vmProfile, err = profile.LoadProfile(prof) + } else { + profPath := ctx.Path(VMProfileConfigFlag.Name) + vmProfile, err = profile.LoadProfileFromConfig(profPath) + } + if err != nil { return fmt.Errorf("error loading profile: %w", err) } @@ -56,9 +65,9 @@ func TraceCaller(ctx *cli.Context) error { var analyzer analyzer.Analyzer if sourceType == "go" { - analyzer = syscall.NewGOSyscallAnalyser(prof) + analyzer = syscall.NewGOSyscallAnalyser(vmProfile) } else { - analyzer = syscall.NewAssemblySyscallAnalyser(prof) + analyzer = syscall.NewAssemblySyscallAnalyser(vmProfile) } callStack, err := analyzer.TraceStack(path, function) diff --git a/profile/config.go b/profile/config.go new file mode 100644 index 0000000..0587966 --- /dev/null +++ b/profile/config.go @@ -0,0 +1,237 @@ +package profile + +var vmProfileConfigs map[string]*VMProfile = map[string]*VMProfile{ + "cannon-singlethreaded-32": { + VMName: "Cannon Singlethreaded 32bit", + GOOS: "linux", + GOARCH: "mips", + IgnoredFunctions: []string{ + "syscall.setrlimit", + "runtime.morestack", + "runtime.abort", + "runtime.exitThread", + "runtime.sigaltstack", + "runtime.rtsigprocmask", + "runtime.munmap", + "runtime.exit", + "runtime.gcenable", + "runtime.init.5", + "runtime.main.func1", + "runtime.deductSweepCredit", + "runtime.(*gcControllerState).commit", + "github.com/prometheus/client_golang/prometheus.init", + "github.com/prometheus/client_golang/prometheus.init.0", + "github.com/prometheus/procfs.init", + "github.com/prometheus/common/model.init", + "github.com/prometheus/client_model/go.init", + "github.com/prometheus/client_model/go.init.0", + "github.com/prometheus/client_model/go.init.1", + "flag.init", + "runtime.check", + "runtime.sysFaultOS", + "runtime.netpollinit", + }, + AllowedOpcodes: []OpcodeInstruction{ + {Opcode: "0x2"}, + {Opcode: "0x3"}, + {Opcode: "0x4"}, + {Opcode: "0x5"}, + {Opcode: "0x6"}, + {Opcode: "0x7"}, + {Opcode: "0x1"}, + {Opcode: "0x1a"}, + {Opcode: "0x1b"}, + {Opcode: "0x0", Funct: []string{ + "0x0", "0x2", "0x3", "0x4", "0x6", "0x7", "0x8", "0x9", "0xa", "0xb", "0xc", "0xf", + "0x10", "0x11", "0x12", "0x13", "0x18", "0x19", "0x1a", "0x1b", "0x20", "0x21", "0x22", + "0x23", "0x24", "0x25", "0x26", "0x27", "0x2a", "0x2b", "0xa", "0xb", "0xc", + }}, + {Opcode: "0x8"}, + {Opcode: "0x9"}, + {Opcode: "0xa"}, + {Opcode: "0xb"}, + {Opcode: "0xc"}, + {Opcode: "0xd"}, + {Opcode: "0xe"}, + {Opcode: "0x1c", Funct: []string{"0x2", "0x20", "0x21"}}, + {Opcode: "0xf"}, + {Opcode: "0x20"}, + {Opcode: "0x21"}, + {Opcode: "0x22"}, + {Opcode: "0x23"}, + {Opcode: "0x24"}, + {Opcode: "0x25"}, + {Opcode: "0x26"}, + {Opcode: "0x28"}, + {Opcode: "0x29"}, + {Opcode: "0x2a"}, + {Opcode: "0x2b"}, + {Opcode: "0x2e"}, + {Opcode: "0x30"}, + {Opcode: "0x38"}, + }, + AllowedSyscalls: []int{4090, 4045, 4120, 4246, 4003, 4004, 4055}, + NOOPSyscalls: []int{ + 4000, 4001, 4002, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, + 4013, 4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023, 4024, 4025, 4026, + 4027, 4028, 4029, 4030, 4031, 4032, 4033, 4034, 4035, 4036, 4037, 4038, 4039, 4040, 4041, + 4042, 4043, 4044, 4046, 4047, 4048, 4049, 4050, 4051, 4052, 4053, 4054, 4056, 4057, 4058, + 4059, 4060, 4061, 4062, 4063, 4064, 4065, 4066, 4067, 4068, 4069, 4070, 4071, 4072, 4073, + 4074, 4075, 4076, 4077, 4078, 4079, 4080, 4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, + 4089, 4091, 4092, 4093, 4094, 4095, 4096, 4097, 4098, 4099, 4100, 4101, 4102, 4103, 4104, + 4105, 4106, 4107, 4108, 4109, 4110, 4111, 4112, 4113, 4114, 4115, 4116, 4117, 4118, 4119, + 4121, 4122, 4123, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4131, 4132, 4133, 4134, 4135, + 4136, 4137, 4138, 4139, 4140, 4141, 4142, 4143, 4144, 4145, 4146, 4147, 4148, 4149, 4150, + 4151, 4152, 4153, 4154, 4155, 4156, 4157, 4158, 4159, 4160, 4161, 4162, 4163, 4164, 4165, + 4166, 4167, 4168, 4169, 4170, 4171, 4172, 4173, 4174, 4175, 4176, 4177, 4178, 4179, 4180, + 4181, 4182, 4183, 4184, 4185, 4186, 4187, 4188, 4189, 4190, 4191, 4192, 4193, 4194, + 4195, 4196, 4197, 4198, 4199, 4200, 4201, 4202, 4203, 4204, 4205, 4206, 4207, 4208, + 4209, 4210, 4211, 4212, 4213, 4214, 4215, 4216, 4217, 4218, 4219, 4220, 4221, 4222, + 4223, 4224, 4225, 4226, 4227, 4228, 4229, 4230, 4231, 4232, 4233, 4234, 4235, 4236, + 4237, 4238, 4239, 4240, 4241, 4242, 4243, 4244, 4245, 4247, 4248, 4249, 4250, 4251, + 4252, 4253, 4254, 4255, 4256, 4257, 4258, 4259, 4260, 4261, 4262, 4263, 4264, 4265, + 4266, 4267, 4268, 4269, 4270, 4271, 4272, 4273, 4274, 4275, 4276, 4277, 4278, 4280, + 4281, 4282, 4283, 4284, 4285, 4286, 4287, 4288, 4289, 4290, 4291, 4292, 4293, 4294, + 4295, 4296, 4297, 4298, 4299, 4300, 4301, 4302, 4303, 4304, 4305, 4306, 4307, 4308, + 4309, 4310, 4311, 4312, 4313, 4314, 4315, 4316, 4317, 4318, 4319, 4320, 4321, 4322, + 4323, 4324, 4325, 4326, 4327, 4328, 4329, 4330, 4331, 4332, 4333, 4334, 4335, 4336, + 4337, 4338, 4339, 4340, 4341, 4342, 4343, 4344, 4345, 4346, 4346, 4346, 4305, 4310, + }, + }, + "cannon-multithreaded-32": { + VMName: "Cannon Multithreaded 32bit", + GOOS: "linux", + GOARCH: "mips", + IgnoredFunctions: []string{ + "syscall.setrlimit", + "runtime.morestack", + "runtime.abort", + "runtime.exitThread", + "runtime.sigaltstack", + "runtime.rtsigprocmask", + "runtime.munmap", + "runtime.exit", + "runtime.sysFaultOS", + "runtime.netpollinit", + }, + AllowedOpcodes: []OpcodeInstruction{ + {"0x2", []string{}}, + {"0x3", []string{}}, + {"0x4", []string{}}, + {"0x5", []string{}}, + {"0x6", []string{}}, + {"0x7", []string{}}, + {"0x1", []string{}}, + {"0x1a", []string{}}, + {"0x1b", []string{}}, + {"0x0", []string{ + "0x0", "0x2", "0x3", "0x4", "0x6", "0x7", "0x8", "0x9", + "0xa", "0xb", "0xc", "0xf", "0x10", "0x11", "0x12", "0x13", "0x18", "0x19", + "0x1a", "0x1b", "0x20", "0x21", "0x22", "0x23", "0x24", "0x25", "0x26", + "0x27", "0x2a", "0x2b", "0xa", "0xb", "0xc", + }}, + {"0x8", []string{}}, + {"0x9", []string{}}, + {"0xa", []string{}}, + {"0xb", []string{}}, + {"0xc", []string{}}, + {"0xd", []string{}}, + {"0xe", []string{}}, + {"0x1c", []string{"0x2", "0x20", "0x21"}}, + {"0xf", []string{}}, + {"0x20", []string{}}, + {"0x21", []string{}}, + {"0x22", []string{}}, + {"0x23", []string{}}, + {"0x24", []string{}}, + {"0x25", []string{}}, + {"0x26", []string{}}, + {"0x28", []string{}}, + {"0x29", []string{}}, + {"0x2a", []string{}}, + {"0x2b", []string{}}, + {"0x2e", []string{}}, + {"0x30", []string{}}, + {"0x38", []string{}}, + }, + AllowedSyscalls: []int{ + 4090, 4045, 4120, 4246, 4003, 4004, 4055, 4222, 4001, 4238, 4162, + 4166, 4005, 4263, 4020, + }, + NOOPSyscalls: []int{ + 4091, 4240, 4218, 4195, 4206, 4194, 4338, 4006, 4200, 4106, + 4108, 4288, 4085, 4298, 4054, 4326, 4328, 4249, 4313, 4353, 4122, 4024, 4047, + 4217, 4266, 4104, 4257, 4258, 4261, 4076, 4019, 4215, 4213, 4140, + }, + }, + "cannon-multithreaded-64": { + VMName: "Cannon Multithreaded 64bit", + GOOS: "linux", + GOARCH: "mips64", + IgnoredFunctions: []string{ + "syscall.setrlimit", + "runtime.morestack", + "runtime.abort", + "runtime.sysFaultOS", + "runtime.netpollinit", + }, + AllowedOpcodes: []OpcodeInstruction{ + {Opcode: "0x2", Funct: []string{}}, + {Opcode: "0x3", Funct: []string{}}, + {Opcode: "0x38", Funct: []string{}}, + {Opcode: "0x30", Funct: []string{}}, + {Opcode: "0x27", Funct: []string{}}, + {Opcode: "0x1a", Funct: []string{}}, + {Opcode: "0x1b", Funct: []string{}}, + {Opcode: "0x4", Funct: []string{}}, + {Opcode: "0x5", Funct: []string{}}, + {Opcode: "0x6", Funct: []string{}}, + {Opcode: "0x7", Funct: []string{}}, + {Opcode: "0x1", Funct: []string{}}, + {Opcode: "0x0", Funct: []string{ + "0x27", "0x20", "0x21", "0x2A", "0x2B", "0x24", "0x25", "0x26", + "0x2c", "0x2d", "0x0", "0x2", "0x3", "0x4", "0x6", "0x7", "0x8", "0x9", + "0xa", "0xb", "0xc", "0xf", "0x10", "0x11", "0x12", "0x13", "0x14", "0x18", + "0x19", "0x16", "0x17", "0x1C", "0x1D", "0x1E", "0x1F", "0x2c", "0x2d", "0x2e", + "0x2f", "0x38", "0x3A", "0x3B", "0x3C", "0x3E", "0x3F", "0x1a", "0x1b", "0xc", + }}, + {Opcode: "0x8", Funct: []string{}}, + {Opcode: "0x9", Funct: []string{}}, + {Opcode: "0xa", Funct: []string{}}, + {Opcode: "0xb", Funct: []string{}}, + {Opcode: "0xc", Funct: []string{}}, + {Opcode: "0xd", Funct: []string{}}, + {Opcode: "0xe", Funct: []string{}}, + {Opcode: "0x18", Funct: []string{}}, + {Opcode: "0x19", Funct: []string{}}, + {Opcode: "0x1c", Funct: []string{"0x2", "0x20", "0x21"}}, + {Opcode: "0xf", Funct: []string{}}, + {Opcode: "0x20", Funct: []string{}}, + {Opcode: "0x21", Funct: []string{}}, + {Opcode: "0x22", Funct: []string{}}, + {Opcode: "0x23", Funct: []string{}}, + {Opcode: "0x24", Funct: []string{}}, + {Opcode: "0x25", Funct: []string{}}, + {Opcode: "0x26", Funct: []string{}}, + {Opcode: "0x28", Funct: []string{}}, + {Opcode: "0x29", Funct: []string{}}, + {Opcode: "0x2a", Funct: []string{}}, + {Opcode: "0x2b", Funct: []string{}}, + {Opcode: "0x2e", Funct: []string{}}, + {Opcode: "0x2c", Funct: []string{}}, + {Opcode: "0x2d", Funct: []string{}}, + {Opcode: "0x37", Funct: []string{}}, + {Opcode: "0x3f", Funct: []string{}}, + {Opcode: "0x34", Funct: []string{}}, + {Opcode: "0x3c", Funct: []string{}}, + }, + AllowedSyscalls: []int{ + 5009, 5012, 5205, 5000, 5001, 5070, 5055, 5058, 5023, 5178, 5194, 5002, 5034, 5222, 5038, + }, + NOOPSyscalls: []int{ + 5011, 5196, 5027, 5014, 5129, 5013, 5297, 5003, 5016, 5004, 5005, 5247, 5087, + 5257, 5015, 5285, 5287, 5208, 5272, 5313, 5061, 5100, 5102, 5026, 5225, 5095, 5008, + 5036, 5216, 5217, 5220, + }, + }, +} diff --git a/profile/profile.go b/profile/profile.go index 9544bca..a73b680 100644 --- a/profile/profile.go +++ b/profile/profile.go @@ -20,7 +20,7 @@ type VMProfile struct { GOOS string `yaml:"goos"` GOARCH string `yaml:"goarch"` AllowedOpcodes []OpcodeInstruction `yaml:"allowed_opcodes"` - AllowedSycalls []int `yaml:"allowed_syscalls"` + AllowedSyscalls []int `yaml:"allowed_syscalls"` NOOPSyscalls []int `yaml:"noop_syscalls"` IgnoredFunctions []string `yaml:"ignored_functions"` } @@ -34,8 +34,17 @@ func (p *VMProfile) SetDefaults() { } } -// LoadProfile loads a VM profile from a JSON file. -func LoadProfile(filename string) (*VMProfile, error) { +// LoadProfile loads a VM profile for predefined profiles. +func LoadProfile(name string) (*VMProfile, error) { + vmProfile, ok := vmProfileConfigs[name] + if !ok { + return nil, fmt.Errorf("invalid profile") + } + return vmProfile, nil +} + +// LoadProfileFromConfig loads a VM profile from a yaml file. +func LoadProfileFromConfig(filename string) (*VMProfile, error) { path, err := filepath.Abs(filename) if err != nil { return nil, fmt.Errorf("failed to get absolute path of profile: %w", err) diff --git a/profile/samples/cannon.json b/profile/samples/cannon.json deleted file mode 100644 index 308be49..0000000 --- a/profile/samples/cannon.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "vm": "Cannon", - "goos": "linux", - "goarch": "mips", - "allowed_opcodes": [ - "0x08", - "0x09", - "0x0C", - "0x04" - ], - "allowed_syscalls": [ - 4090, - 4045, - 4120, - 4246, - 4003, - 4004, - 4055 - ] -} \ No newline at end of file