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

Added xattr plugin for darwin. #3276

Merged
merged 6 commits into from
Feb 13, 2024
Merged
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
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ require (
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/ivaxer/go-xattr v1.1.1 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/klauspost/compress v1.17.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,8 @@ github.com/inconshreveable/log15 v0.0.0-20170622235902-74a0988b5f80/go.mod h1:cO
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/ivaxer/go-xattr v1.1.1 h1:ugr8VSr2Int1FOIMbbniFg4hQ1pZSYYinkvdLTURShE=
github.com/ivaxer/go-xattr v1.1.1/go.mod h1:OpHnbEWzslZVYurbd1wtW0o2Tsp5x33BZ4N0pasCNyM=
github.com/jawher/mow.cli v1.1.0/go.mod h1:aNaQlc7ozF3vw6IJ2dHjp2ZFiA4ozMIYY6PyuRJwlUg=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
Expand Down
14 changes: 14 additions & 0 deletions vql/darwin/fixtures/xattrReturnCheck.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"Case #0": null,
"Case #1": {
"vr.test": "dGVzdC52YWx1ZQ=="
},
"Case #2": {
"vr.test": "dGVzdC52YWx1ZQ==",
"vr.test2": "dGVzdC52YWx1ZQ=="
},
"Case #3": {
"vr.test": "dGVzdC52YWx1ZQ=="
},
"Case #4": {}
}
91 changes: 91 additions & 0 deletions vql/darwin/xattr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
//go:build !windows
// +build !windows

package darwin

import (
"context"

"github.com/Velocidex/ordereddict"
"github.com/ivaxer/go-xattr"
"www.velocidex.com/golang/velociraptor/accessors"
"www.velocidex.com/golang/velociraptor/acls"
vql_subsystem "www.velocidex.com/golang/velociraptor/vql"
"www.velocidex.com/golang/vfilter"
"www.velocidex.com/golang/vfilter/arg_parser"
)

type XAttrArgs struct {
Filename *accessors.OSPath `vfilter:"required,field=filename,doc=Filename to inspect."`
Attributes []string `vfilter:"optional,field=attribute,doc=Attribute to collect."`
Accessor string `vfilter:"optional,field=accessor,doc=File accessor"`
}

type XAttrFunction struct{}

func (self XAttrFunction) Call(
ctx context.Context,
scope vfilter.Scope,
args *ordereddict.Dict) vfilter.Any {
defer vql_subsystem.CheckForPanic(scope, "xattr")
arg := &XAttrArgs{}
err := arg_parser.ExtractArgsWithContext(ctx, scope, args, arg)
if err != nil {
scope.Log("xattr: Arg parser: %s", err)
return nil
}

err = vql_subsystem.CheckFilesystemAccess(scope, arg.Accessor)
if err != nil {
scope.Log("xattr: %s", err)
return nil
}

filename, err := accessors.GetUnderlyingAPIFilename(
arg.Accessor, scope, arg.Filename)
if err != nil {
scope.Log("xattr: Failed to get underlying filename for %s: %s",
arg.Filename.String(), err)
}

bmcdermott-r7 marked this conversation as resolved.
Show resolved Hide resolved
if len(arg.Attributes) > 0 {
return self.getAttributeValues(scope, arg.Attributes, filename)
} else {
attributes, err := xattr.List(filename)
if err != nil {
scope.Log("xattr: Failed to list attributes for filename %s: %s",
filename, err)
return vfilter.Null{}
}

return self.getAttributeValues(scope, attributes, filename)
}
}

func (self *XAttrFunction) getAttributeValues(
scope vfilter.Scope, Attributes []string,
Filename string) *ordereddict.Dict {
ret := ordereddict.NewDict()
for _, attr := range Attributes {
value, err := xattr.Get(Filename, attr)
if err != nil {
continue
}
ret.Set(attr, value)
}
return ret
}

func (self XAttrFunction) Info(
scope vfilter.Scope, type_map *vfilter.TypeMap) *vfilter.FunctionInfo {
return &vfilter.FunctionInfo{
Name: "xattr",
Doc: "query a file for the specified extended attribute",
ArgType: type_map.AddType(scope, &XAttrArgs{}),
Metadata: vql_subsystem.VQLMetadata().Permissions(acls.FILESYSTEM_READ).Build(),
}
}

func init() {
vql_subsystem.RegisterFunction(&XAttrFunction{})
}
104 changes: 104 additions & 0 deletions vql/darwin/xattr_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//go:build !windows
// +build !windows

package darwin

import (
"fmt"
"os"
"testing"

"github.com/Velocidex/ordereddict"
"github.com/ivaxer/go-xattr"
"github.com/sebdah/goldie"
"github.com/stretchr/testify/suite"
_ "www.velocidex.com/golang/velociraptor/accessors/file"
"www.velocidex.com/golang/velociraptor/file_store/test_utils"
"www.velocidex.com/golang/velociraptor/json"
"www.velocidex.com/golang/velociraptor/logging"
"www.velocidex.com/golang/velociraptor/services"
"www.velocidex.com/golang/velociraptor/vql/acl_managers"
"www.velocidex.com/golang/velociraptor/vtesting/assert"
)

var ()

type XattrTestSuite struct {
test_utils.TestSuite
}

func (self *XattrTestSuite) TestXAttr() {
file, err := os.CreateTemp("", "")
assert.NoError(self.T(), err, "xattr: failed to create test file")
filepath := file.Name()
file.Close()
defer os.Remove(filepath)

attr1 := "vr.test"
attr2 := "vr.test2"
value := "test.value"

testcases := []struct {
name string
bmcdermott-r7 marked this conversation as resolved.
Show resolved Hide resolved
attr []string
pass bool
}{
{
name: filepath,
attr: []string{},
pass: false,
},
{
name: filepath,
attr: []string{attr1},
pass: true,
},
{
name: filepath,
attr: []string{attr1, attr2},
pass: true,
},
{
name: filepath,
attr: []string{attr1, "invalid.test"},
pass: true,
},
{
name: filepath,
attr: []string{"invalid.test"},
pass: false,
},
}

xattr.Set(filepath, attr1, []byte(value))
xattr.Set(filepath, attr2, []byte(value))

builder := services.ScopeBuilder{
Config: self.ConfigObj,
ACLManager: acl_managers.NullACLManager{},
Logger: logging.NewPlainLogger(self.ConfigObj,
&logging.FrontendComponent),
Env: ordereddict.NewDict(),
}

manager, err := services.GetRepositoryManager(self.ConfigObj)
assert.NoError(self.T(), err)

scope := manager.BuildScope(builder)
defer scope.Close()

ret := ordereddict.NewDict()
for i, test := range testcases {
ret.Set(fmt.Sprintf("Case #%d", i), XAttrFunction{}.Call(
self.Ctx, scope,
ordereddict.NewDict().
Set("filename", test.name).
Set("attribute", test.attr)))

}
goldie.Assert(self.T(), "xattrReturnCheck", json.MustMarshalIndent(ret))
}

func TestXAttrFunction(t *testing.T) {
suite.Run(t, &XattrTestSuite{})
}
22 changes: 22 additions & 0 deletions vql_plugins/plugins_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
Velociraptor - Dig Deeper
Copyright (C) 2019-2024 Rapid7 Inc.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package plugins

import (
_ "www.velocidex.com/golang/velociraptor/vql/darwin"
)
Loading