Skip to content

Commit

Permalink
address pr comments
Browse files Browse the repository at this point in the history
  • Loading branch information
efd6 committed Aug 15, 2023
1 parent 2797a04 commit 9afaa2f
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 2 deletions.
89 changes: 88 additions & 1 deletion auditbeat/module/file_integrity/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@ import (
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/base64"
"encoding/binary"
"encoding/hex"
"fmt"
"hash"
"io"
"math"
"os"
"os/user"
"path/filepath"
"runtime"
"strconv"
Expand Down Expand Up @@ -321,6 +324,15 @@ func buildMetricbeatEvent(e *Event, existedBefore bool) mb.Event {
if len(info.Origin) > 0 {
file["origin"] = info.Origin
}
if info.SELinux != "" {
file["selinux"] = info.SELinux
}
if info.POSIXACLAccess != "" {
a, err := aclText(info.POSIXACLAccess)
if err == nil {
file["posix_acl_access"] = a
}
}
}

if len(e.Hashes) > 0 {
Expand Down Expand Up @@ -358,6 +370,80 @@ func buildMetricbeatEvent(e *Event, existedBefore bool) mb.Event {
return out
}

func aclText(s string) ([]string, error) {
b, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(s, "0s"))
if err != nil {
return nil, err
}
if (len(b)-4)%8 != 0 {
return nil, fmt.Errorf("unexpected ACL length: %d", len(b))
}
var a []string

Check failure on line 381 in auditbeat/module/file_integrity/event.go

View workflow job for this annotation

GitHub Actions / lint (windows)

Consider pre-allocating `a` (prealloc)
b = b[4:]
for len(b) != 0 {
tag := binary.LittleEndian.Uint16(b)
perm := binary.LittleEndian.Uint16(b[2:])
qual := binary.LittleEndian.Uint32(b[4:])
a = append(a, fmt.Sprintf("%s:%s:%s", tags[tag], qualString(qual, tag), modeString(perm)))
b = b[8:]
}
return a, nil
}

var tags = map[uint16]string{
0x00: "undefined",
0x01: "user",
0x02: "user",
0x04: "group",
0x08: "group",
0x10: "mask",
0x20: "other",
}

func qualString(qual uint32, tag uint16) string {
if qual == math.MaxUint32 {
return ""
}
const (
tagUser = 0x02
tagGroup = 0x08
)
switch tag {
case tagUser:
uid := strconv.Itoa(int(qual))
u, err := user.LookupId(uid)
if err != nil {
// Fallback to the numeric ID if we can't get a name.
return uid
}
return u.Username
case tagGroup:
gid := strconv.Itoa(int(qual))
g, err := user.LookupGroupId(gid)
if err != nil {
// Fallback to the numeric ID if we can't get a name.
return gid
}
return g.Name
}
return ""
}

func modeString(perm uint16) string {
var buf [3]byte
w := 0
const rwx = "rwx"
for i, c := range rwx {
if perm&(1<<uint(len(rwx)-1-i)) != 0 {
buf[w] = byte(c)
} else {
buf[w] = '-'
}
w++
}
return string(buf[:w])
}

// diffEvents returns true if the file info differs between the old event and
// the new event. Changes to the timestamp and action are ignored. If old
// contains a superset of new's hashes then false is returned.
Expand Down Expand Up @@ -407,7 +493,8 @@ func diffEvents(old, new *Event) (Action, bool) {
if o, n := old.Info, new.Info; o != nil && n != nil {
// The owner and group names are ignored (they aren't persisted).
if o.Inode != n.Inode || o.UID != n.UID || o.GID != n.GID || o.SID != n.SID ||
o.Mode != n.Mode || o.Type != n.Type || o.SetUID != n.SetUID || o.SetGID != n.SetGID {
o.Mode != n.Mode || o.Type != n.Type || o.SetUID != n.SetUID || o.SetGID != n.SetGID ||
o.SELinux != n.SELinux || o.POSIXACLAccess != n.POSIXACLAccess {
result |= AttributesModified
}

Expand Down
39 changes: 39 additions & 0 deletions auditbeat/module/file_integrity/event_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import (
"io/ioutil"
"math"
"os"
"os/user"
"reflect"
"runtime"
"testing"
"time"
Expand Down Expand Up @@ -553,3 +555,40 @@ func assertHasKey(t testing.TB, m mapstr.M, key string) bool {
}
return true
}

func TestACLText(t *testing.T) {
// Depending on the system we are running this test on, we may or may not
// have a username associated with the user's UID in the xattr string, so
// dynamically determine the username here.
tests := []struct {
encoded string
want []string
}{
0: {
encoded: "0sAgAAAAEABgD/////AgAGAG8AAAAEAAQA/////xAABgD/////IAAEAP////8=",
want: []string{"user::rw-", "user:" + userNameOrUID("111") + ":rw-", "group::r--", "mask::rw-", "other::r--"},
},
1: { // Encoded string from https://www.bityard.org/wiki/tech/os/linux/xattrs.
encoded: "0sAgAAAAEABgD/////AgAHAHwAAAAEAAQA/////xAABwD/////IAAEAP////8=",
want: []string{"user::rw-", "user:" + userNameOrUID("124") + ":rwx", "group::r--", "mask::rwx", "other::r--"},
},
}
for i, test := range tests {
got, err := aclText(test.encoded)
if err != nil {
t.Errorf("unexpected error for test %d: %v", i, err)
continue
}
if !reflect.DeepEqual(got, test.want) {
t.Errorf("unexpected result for test %d:\ngot: %#v\nwant:%v", i, got, test.want)
}
}
}

func userNameOrUID(uid string) string {
u, err := user.LookupId(uid)
if err != nil {
return uid
}
return u.Username
}
8 changes: 7 additions & 1 deletion auditbeat/module/file_integrity/fileinfo_posix.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package file_integrity

import (
"bytes"
"fmt"
"os"
"os/user"
Expand Down Expand Up @@ -97,6 +98,11 @@ func getExtendedAttributes(path string, dst map[string]*string) {
if err != nil {
continue
}
*d = string(att)
*d = string(trimNull(att))
}
}

func trimNull(b []byte) []byte {
b, _, _ = bytes.Cut(b, []byte{0})
return b
}

0 comments on commit 9afaa2f

Please sign in to comment.