diff --git a/vendor/github.com/lunixbochs/struc/.travis.yml b/vendor/github.com/lunixbochs/struc/.travis.yml new file mode 100644 index 00000000..8316e895 --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/.travis.yml @@ -0,0 +1,10 @@ +language: go +sudo: false + +script: go test -v + +go: + - 1.2 + - 1.3 + - 1.4 + - tip diff --git a/vendor/github.com/lunixbochs/struc/LICENSE b/vendor/github.com/lunixbochs/struc/LICENSE new file mode 100644 index 00000000..42e82633 --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015 Ryan Hileman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/lunixbochs/struc/README.md b/vendor/github.com/lunixbochs/struc/README.md new file mode 100644 index 00000000..c8134971 --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/README.md @@ -0,0 +1,103 @@ +[![Build Status](https://travis-ci.org/lunixbochs/struc.svg?branch=master)](https://travis-ci.org/lunixbochs/struc) + +struc +==== + +Struc exists to pack and unpack C-style structures from bytes, which is useful for binary files and network protocols. It could be considered an alternative to `encoding/binary`, which requires massive boilerplate for some similar operations. + +Take a look at an [example comparing `struc` and `encoding/binary`](https://bochs.info/p/cxvm9) + +Struc considers usability first. That said, it does cache reflection data and aims to be competitive with `encoding/binary` struct packing in every way, including performance. + +Example struct +---- + +```Go +type Example struct { + Var int `struc:"int32,sizeof=Str"` + Str string + Weird []byte `struc:"[8]int64"` + Var []int `struc:"[]int32,little"` +} +``` + +Struct tag format +---- + + - ```Var []int `struc:"[]int32,little,sizeof=StringField"` ``` will pack Var as a slice of little-endian int32, and link it as the size of `StringField`. + - `sizeof=`: Indicates this field is a number used to track the length of a another field. `sizeof` fields are automatically updated on `Pack()` based on the current length of the tracked field, and are used to size the target field during `Unpack()`. + - Bare values will be parsed as type and endianness. + +Endian formats +---- + + - `big` (default) + - `little` + +Recognized types +---- + + - `pad` - this type ignores field contents and is backed by a `[length]byte` containing nulls + - `bool` + - `byte` + - `int8`, `uint8` + - `int16`, `uint16` + - `int32`, `uint32` + - `int64`, `uint64` + - `float32` + - `float64` + +Types can be indicated as arrays/slices using `[]` syntax. Example: `[]int64`, `[8]int32`. + +Bare slice types (those with no `[size]`) must have a linked `Sizeof` field. + +Private fields are ignored when packing and unpacking. + +Example code +---- + +```Go +package main + +import ( + "bytes" + "github.com/lunixbochs/struc" +) + +type Example struct { + A int `struc:"big"` + + // B will be encoded/decoded as a 16-bit int (a "short") + // but is stored as a native int in the struct + B int `struc:"int16"` + + // the sizeof key links a buffer's size to any int field + Size int `struc:"int8,little,sizeof=Str"` + Str string + + // you can get freaky if you want + Str2 string `struc:"[5]int64"` +} + +func main() { + var buf bytes.Buffer + t := &Example{1, 2, 0, "test", "test2"} + err := struc.Pack(&buf, t) + o := &Example{} + err = struc.Unpack(&buf, o) +} +``` + +Benchmark +---- + +`BenchmarkEncode` uses struc. `Stdlib` benchmarks use equivalent `encoding/binary` code. `Manual` encodes without any reflection, and should be considered an upper bound on performance (which generated code based on struc definitions should be able to achieve). + +``` +BenchmarkEncode 1000000 1265 ns/op +BenchmarkStdlibEncode 1000000 1855 ns/op +BenchmarkManualEncode 5000000 284 ns/op +BenchmarkDecode 1000000 1259 ns/op +BenchmarkStdlibDecode 1000000 1656 ns/op +BenchmarkManualDecode 20000000 89.0 ns/op +``` diff --git a/vendor/github.com/lunixbochs/struc/bench_test.go b/vendor/github.com/lunixbochs/struc/bench_test.go new file mode 100644 index 00000000..d73c110f --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/bench_test.go @@ -0,0 +1,165 @@ +package struc + +import ( + "bytes" + "encoding/binary" + "testing" +) + +type BenchExample struct { + Test [5]byte + A int32 + B, C, D int16 + Test2 [4]byte + Length int32 +} + +type BenchStrucExample struct { + Test [5]byte `struc:"[5]byte"` + A int `struc:"int32"` + B, C, D int `struc:"int16"` + Test2 [4]byte `struc:"[4]byte"` + Length int `struc:"int32,sizeof=Data"` + Data []byte +} + +var benchRef = &BenchExample{ + [5]byte{1, 2, 3, 4, 5}, + 1, 2, 3, 4, + [4]byte{1, 2, 3, 4}, + 8, +} + +var eightBytes = []byte("8bytestr") + +var benchStrucRef = &BenchStrucExample{ + [5]byte{1, 2, 3, 4, 5}, + 1, 2, 3, 4, + [4]byte{1, 2, 3, 4}, + 8, eightBytes, +} + +func BenchmarkEncode(b *testing.B) { + for i := 0; i < b.N; i++ { + var buf bytes.Buffer + err := Pack(&buf, benchStrucRef) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkStdlibEncode(b *testing.B) { + for i := 0; i < b.N; i++ { + var buf bytes.Buffer + err := binary.Write(&buf, binary.BigEndian, benchRef) + if err != nil { + b.Fatal(err) + } + _, err = buf.Write(eightBytes) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkManualEncode(b *testing.B) { + order := binary.BigEndian + s := benchStrucRef + for i := 0; i < b.N; i++ { + var buf bytes.Buffer + tmp := make([]byte, 29) + copy(tmp[0:5], s.Test[:]) + order.PutUint32(tmp[5:9], uint32(s.A)) + order.PutUint16(tmp[9:11], uint16(s.B)) + order.PutUint16(tmp[11:13], uint16(s.C)) + order.PutUint16(tmp[13:15], uint16(s.D)) + copy(tmp[15:19], s.Test2[:]) + order.PutUint32(tmp[19:23], uint32(s.Length)) + copy(tmp[23:], s.Data) + _, err := buf.Write(tmp) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkDecode(b *testing.B) { + var out BenchStrucExample + var buf bytes.Buffer + if err := Pack(&buf, benchStrucRef); err != nil { + b.Fatal(err) + } + bufBytes := buf.Bytes() + for i := 0; i < b.N; i++ { + buf := bytes.NewReader(bufBytes) + err := Unpack(buf, &out) + if err != nil { + b.Fatal(err) + } + out.Data = nil + } +} + +func BenchmarkStdlibDecode(b *testing.B) { + var out BenchExample + var buf bytes.Buffer + binary.Write(&buf, binary.BigEndian, *benchRef) + _, err := buf.Write(eightBytes) + if err != nil { + b.Fatal(err) + } + bufBytes := buf.Bytes() + for i := 0; i < b.N; i++ { + buf := bytes.NewReader(bufBytes) + err := binary.Read(buf, binary.BigEndian, &out) + if err != nil { + b.Fatal(err) + } + tmp := make([]byte, out.Length) + _, err = buf.Read(tmp) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkManualDecode(b *testing.B) { + var o BenchStrucExample + var buf bytes.Buffer + if err := Pack(&buf, benchStrucRef); err != nil { + b.Fatal(err) + } + tmp := buf.Bytes() + order := binary.BigEndian + for i := 0; i < b.N; i++ { + copy(o.Test[:], tmp[0:5]) + o.A = int(order.Uint32(tmp[5:9])) + o.B = int(order.Uint16(tmp[9:11])) + o.C = int(order.Uint16(tmp[11:13])) + o.D = int(order.Uint16(tmp[13:15])) + copy(o.Test2[:], tmp[15:19]) + o.Length = int(order.Uint32(tmp[19:23])) + o.Data = make([]byte, o.Length) + copy(o.Data, tmp[23:]) + } +} + +func BenchmarkFullEncode(b *testing.B) { + for i := 0; i < b.N; i++ { + var buf bytes.Buffer + if err := Pack(&buf, reference); err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkFullDecode(b *testing.B) { + var out Example + for i := 0; i < b.N; i++ { + buf := bytes.NewBuffer(referenceBytes) + if err := Unpack(buf, &out); err != nil { + b.Fatal(err) + } + } +} diff --git a/vendor/github.com/lunixbochs/struc/binary.go b/vendor/github.com/lunixbochs/struc/binary.go new file mode 100644 index 00000000..4899d08f --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/binary.go @@ -0,0 +1,52 @@ +package struc + +import ( + "encoding/binary" + "io" + "reflect" +) + +type byteWriter struct { + buf []byte + pos int +} + +func (b byteWriter) Write(p []byte) (int, error) { + capacity := len(b.buf) - b.pos + if capacity < len(p) { + p = p[:capacity] + } + if len(p) > 0 { + copy(b.buf[b.pos:], p) + b.pos += len(p) + } + return len(p), nil +} + +type binaryFallback reflect.Value + +func (b binaryFallback) String() string { + return b.String() +} + +func (b binaryFallback) Sizeof(val reflect.Value, options *Options) int { + return binary.Size(val.Interface()) +} + +func (b binaryFallback) Pack(buf []byte, val reflect.Value, options *Options) (int, error) { + tmp := byteWriter{buf: buf} + var order binary.ByteOrder = binary.BigEndian + if options.Order != nil { + order = options.Order + } + err := binary.Write(tmp, order, val.Interface()) + return tmp.pos, err +} + +func (b binaryFallback) Unpack(r io.Reader, val reflect.Value, options *Options) error { + var order binary.ByteOrder = binary.BigEndian + if options.Order != nil { + order = options.Order + } + return binary.Read(r, order, val.Interface()) +} diff --git a/vendor/github.com/lunixbochs/struc/custom.go b/vendor/github.com/lunixbochs/struc/custom.go new file mode 100644 index 00000000..c468dce5 --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/custom.go @@ -0,0 +1,33 @@ +package struc + +import ( + "io" + "reflect" +) + +type Custom interface { + Pack(p []byte, opt *Options) (int, error) + Unpack(r io.Reader, length int, opt *Options) error + Size(opt *Options) int + String() string +} + +type customFallback struct { + custom Custom +} + +func (c customFallback) Pack(p []byte, val reflect.Value, opt *Options) (int, error) { + return c.custom.Pack(p, opt) +} + +func (c customFallback) Unpack(r io.Reader, val reflect.Value, opt *Options) error { + return c.custom.Unpack(r, 1, opt) +} + +func (c customFallback) Sizeof(val reflect.Value, opt *Options) int { + return c.custom.Size(opt) +} + +func (c customFallback) String() string { + return c.custom.String() +} diff --git a/vendor/github.com/lunixbochs/struc/custom_float16.go b/vendor/github.com/lunixbochs/struc/custom_float16.go new file mode 100644 index 00000000..722be765 --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/custom_float16.go @@ -0,0 +1,78 @@ +package struc + +import ( + "encoding/binary" + "io" + "math" + "strconv" +) + +type Float16 float64 + +func (f *Float16) Pack(p []byte, opt *Options) (int, error) { + order := opt.Order + if order == nil { + order = binary.BigEndian + } + sign := uint16(0) + if *f < 0 { + sign = 1 + } + var frac, exp uint16 + if math.IsInf(float64(*f), 0) { + exp = 0x1f + frac = 0 + } else if math.IsNaN(float64(*f)) { + exp = 0x1f + frac = 1 + } else { + bits := math.Float64bits(float64(*f)) + exp64 := (bits >> 52) & 0x7ff + if exp64 != 0 { + exp = uint16((exp64 - 1023 + 15) & 0x1f) + } + frac = uint16((bits >> 42) & 0x3ff) + } + var out uint16 + out |= sign << 15 + out |= exp << 10 + out |= frac & 0x3ff + order.PutUint16(p, out) + return 2, nil +} +func (f *Float16) Unpack(r io.Reader, length int, opt *Options) error { + order := opt.Order + if order == nil { + order = binary.BigEndian + } + var tmp [2]byte + if _, err := r.Read(tmp[:]); err != nil { + return err + } + val := order.Uint16(tmp[:2]) + sign := (val >> 15) & 1 + exp := int16((val >> 10) & 0x1f) + frac := val & 0x3ff + if exp == 0x1f { + if frac != 0 { + *f = Float16(math.NaN()) + } else { + *f = Float16(math.Inf(int(sign)*-2 + 1)) + } + } else { + var bits uint64 + bits |= uint64(sign) << 63 + bits |= uint64(frac) << 42 + if exp > 0 { + bits |= uint64(exp-15+1023) << 52 + } + *f = Float16(math.Float64frombits(bits)) + } + return nil +} +func (f *Float16) Size(opt *Options) int { + return 2 +} +func (f *Float16) String() string { + return strconv.FormatFloat(float64(*f), 'g', -1, 32) +} diff --git a/vendor/github.com/lunixbochs/struc/custom_float16_test.go b/vendor/github.com/lunixbochs/struc/custom_float16_test.go new file mode 100644 index 00000000..11f73cbc --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/custom_float16_test.go @@ -0,0 +1,56 @@ +package struc + +import ( + "bytes" + "encoding/binary" + "fmt" + "math" + "strconv" + "strings" + "testing" +) + +func TestFloat16(t *testing.T) { + // test cases from https://en.wikipedia.org/wiki/Half-precision_floating-point_format#Half_precision_examples + tests := []struct { + B string + F float64 + }{ + //s expnt significand + {"0 01111 0000000000", 1}, + {"0 01111 0000000001", 1.0009765625}, + {"1 10000 0000000000", -2}, + {"0 11110 1111111111", 65504}, + // {"0 00001 0000000000", 0.0000610352}, + // {"0 00000 1111111111", 0.0000609756}, + // {"0 00000 0000000001", 0.0000000596046}, + {"0 00000 0000000000", 0}, + // {"1 00000 0000000000", -0}, + {"0 11111 0000000000", math.Inf(1)}, + {"1 11111 0000000000", math.Inf(-1)}, + {"0 01101 0101010101", 0.333251953125}, + } + for _, test := range tests { + var buf bytes.Buffer + f := Float16(test.F) + if err := Pack(&buf, &f); err != nil { + t.Error("pack failed:", err) + continue + } + bitval, _ := strconv.ParseUint(strings.Replace(test.B, " ", "", -1), 2, 16) + tmp := binary.BigEndian.Uint16(buf.Bytes()) + if tmp != uint16(bitval) { + t.Errorf("incorrect pack: %s != %016b (%f)", test.B, tmp, test.F) + continue + } + var f2 Float16 + if err := Unpack(&buf, &f2); err != nil { + t.Error("unpack failed:", err) + continue + } + // let sprintf deal with (im)precision for me here + if fmt.Sprintf("%f", f) != fmt.Sprintf("%f", f2) { + t.Errorf("incorrect unpack: %016b %f != %f", bitval, f, f2) + } + } +} diff --git a/vendor/github.com/lunixbochs/struc/custom_test.go b/vendor/github.com/lunixbochs/struc/custom_test.go new file mode 100644 index 00000000..e601166d --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/custom_test.go @@ -0,0 +1,97 @@ +package struc + +import ( + "bytes" + "encoding/binary" + "io" + "strconv" + "testing" +) + +type Int3 uint32 + +func (i *Int3) Pack(p []byte, opt *Options) (int, error) { + var tmp [4]byte + binary.BigEndian.PutUint32(tmp[:], uint32(*i)) + copy(p, tmp[1:]) + return 3, nil +} +func (i *Int3) Unpack(r io.Reader, length int, opt *Options) error { + var tmp [4]byte + if _, err := r.Read(tmp[1:]); err != nil { + return err + } + *i = Int3(binary.BigEndian.Uint32(tmp[:])) + return nil +} +func (i *Int3) Size(opt *Options) int { + return 3 +} +func (i *Int3) String() string { + return strconv.FormatUint(uint64(*i), 10) +} + +func TestCustom(t *testing.T) { + var buf bytes.Buffer + var i Int3 = 3 + if err := Pack(&buf, &i); err != nil { + t.Fatal(err) + } + if !bytes.Equal(buf.Bytes(), []byte{0, 0, 3}) { + t.Fatal("error packing custom int") + } + var i2 Int3 + if err := Unpack(&buf, &i2); err != nil { + t.Fatal(err) + } + if i2 != 3 { + t.Fatal("error unpacking custom int") + } +} + +type Int3Struct struct { + I Int3 +} + +func TestCustomStruct(t *testing.T) { + var buf bytes.Buffer + i := Int3Struct{3} + if err := Pack(&buf, &i); err != nil { + t.Fatal(err) + } + if !bytes.Equal(buf.Bytes(), []byte{0, 0, 3}) { + t.Fatal("error packing custom int struct") + } + var i2 Int3Struct + if err := Unpack(&buf, &i2); err != nil { + t.Fatal(err) + } + if i2.I != 3 { + t.Fatal("error unpacking custom int struct") + } +} + +// TODO: slices of custom types don't work yet +/* +type Int3SliceStruct struct { + I [2]Int3 +} + +func TestCustomSliceStruct(t *testing.T) { + var buf bytes.Buffer + i := Int3SliceStruct{[2]Int3{3, 4}} + if err := Pack(&buf, &i); err != nil { + t.Fatal(err) + } + if !bytes.Equal(buf.Bytes(), []byte{0, 0, 3}) { + t.Fatal("error packing custom int struct") + } + var i2 Int3SliceStruct + if err := Unpack(&buf, &i2); err != nil { + t.Fatal(err) + } + if i2.I[0] != 3 && i2.I[1] != 4 { + t.Fatal("error unpacking custom int struct") + } +} +*/ diff --git a/vendor/github.com/lunixbochs/struc/field.go b/vendor/github.com/lunixbochs/struc/field.go new file mode 100644 index 00000000..5ab7da61 --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/field.go @@ -0,0 +1,280 @@ +package struc + +import ( + "bytes" + "encoding/binary" + "fmt" + "math" + "reflect" +) + +type Field struct { + Name string + Ptr bool + Index int + Type Type + defType Type + Array bool + Slice bool + Len int + Order binary.ByteOrder + Sizeof []int + Sizefrom []int + Fields Fields + kind reflect.Kind +} + +func (f *Field) String() string { + var out string + if f.Type == Pad { + return fmt.Sprintf("{type: Pad, len: %d}", f.Len) + } else { + out = fmt.Sprintf("type: %s, order: %v", f.Type.String(), f.Order) + } + if f.Sizefrom != nil { + out += fmt.Sprintf(", sizefrom: %v", f.Sizefrom) + } else if f.Len > 0 { + out += fmt.Sprintf(", len: %d", f.Len) + } + if f.Sizeof != nil { + out += fmt.Sprintf(", sizeof: %v", f.Sizeof) + } + return "{" + out + "}" +} + +func (f *Field) Size(val reflect.Value, options *Options) int { + typ := f.Type.Resolve(options) + size := 0 + if typ == Struct { + vals := []reflect.Value{val} + if f.Slice { + vals = make([]reflect.Value, val.Len()) + for i := 0; i < val.Len(); i++ { + vals[i] = val.Index(i) + } + } + for _, val := range vals { + size += f.Fields.Sizeof(val, options) + } + } else if typ == Pad { + size = f.Len + } else if f.Slice || f.kind == reflect.String { + length := val.Len() + if f.Len > 1 { + length = f.Len + } + size = length * typ.Size() + } else if typ == CustomType { + return val.Addr().Interface().(Custom).Size(options) + } else { + size = typ.Size() + } + align := options.ByteAlign + if align > 0 && size < align { + size = align + } + return size +} + +func (f *Field) packVal(buf []byte, val reflect.Value, length int, options *Options) (size int, err error) { + order := f.Order + if options.Order != nil { + order = options.Order + } + if f.Ptr { + val = val.Elem() + } + typ := f.Type.Resolve(options) + switch typ { + case Struct: + return f.Fields.Pack(buf, val, options) + case Bool, Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64: + size = typ.Size() + var n uint64 + switch f.kind { + case reflect.Bool: + if val.Bool() { + n = 1 + } else { + n = 0 + } + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n = uint64(val.Int()) + default: + n = val.Uint() + } + switch typ { + case Bool: + if n != 0 { + buf[0] = 1 + } else { + buf[0] = 0 + } + case Int8, Uint8: + buf[0] = byte(n) + case Int16, Uint16: + order.PutUint16(buf, uint16(n)) + case Int32, Uint32: + order.PutUint32(buf, uint32(n)) + case Int64, Uint64: + order.PutUint64(buf, uint64(n)) + } + case Float32, Float64: + size = typ.Size() + n := val.Float() + switch typ { + case Float32: + order.PutUint32(buf, math.Float32bits(float32(n))) + case Float64: + order.PutUint64(buf, math.Float64bits(n)) + } + case String: + switch f.kind { + case reflect.String: + size = val.Len() + copy(buf, []byte(val.String())) + default: + // TODO: handle kind != bytes here + size = val.Len() + copy(buf, val.Bytes()) + } + case CustomType: + return val.Addr().Interface().(Custom).Pack(buf, options) + default: + panic(fmt.Sprintf("no pack handler for type: %s", typ)) + } + return +} + +func (f *Field) Pack(buf []byte, val reflect.Value, length int, options *Options) (int, error) { + typ := f.Type.Resolve(options) + if typ == Pad { + for i := 0; i < length; i++ { + buf[i] = 0 + } + return length, nil + } + if f.Slice { + // special case strings and byte slices for performance + end := val.Len() + if !f.Array && typ == Uint8 && (f.defType == Uint8 || f.kind == reflect.String) { + var tmp []byte + if f.kind == reflect.String { + tmp = []byte(val.String()) + } else { + tmp = val.Bytes() + } + copy(buf, tmp) + if end < length { + // TODO: allow configuring pad byte? + rep := bytes.Repeat([]byte{0}, length-end) + copy(buf[end:], rep) + return length, nil + } + return val.Len(), nil + } + pos := 0 + var zero reflect.Value + if end < length { + zero = reflect.Zero(val.Type().Elem()) + } + for i := 0; i < length; i++ { + cur := zero + if i < end { + cur = val.Index(i) + } + if n, err := f.packVal(buf[pos:], cur, 1, options); err != nil { + return pos, err + } else { + pos += n + } + } + return pos, nil + } else { + return f.packVal(buf, val, length, options) + } +} + +func (f *Field) unpackVal(buf []byte, val reflect.Value, length int, options *Options) error { + order := f.Order + if options.Order != nil { + order = options.Order + } + if f.Ptr { + val = val.Elem() + } + typ := f.Type.Resolve(options) + switch typ { + case Float32, Float64: + var n float64 + switch typ { + case Float32: + n = float64(math.Float32frombits(order.Uint32(buf))) + case Float64: + n = math.Float64frombits(order.Uint64(buf)) + } + switch f.kind { + case reflect.Float32, reflect.Float64: + val.SetFloat(n) + default: + return fmt.Errorf("struc: refusing to unpack float into field %s of type %s", f.Name, f.kind.String()) + } + case Bool, Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64: + var n uint64 + switch typ { + case Bool, Int8, Uint8: + n = uint64(buf[0]) + case Int16, Uint16: + n = uint64(order.Uint16(buf)) + case Int32, Uint32: + n = uint64(order.Uint32(buf)) + case Int64, Uint64: + n = uint64(order.Uint64(buf)) + } + switch f.kind { + case reflect.Bool: + val.SetBool(n != 0) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + val.SetInt(int64(n)) + default: + val.SetUint(n) + } + default: + panic(fmt.Sprintf("no unpack handler for type: %s", typ)) + } + return nil +} + +func (f *Field) Unpack(buf []byte, val reflect.Value, length int, options *Options) error { + typ := f.Type.Resolve(options) + if typ == Pad || f.kind == reflect.String { + if typ == Pad { + return nil + } else { + val.SetString(string(buf)) + return nil + } + } else if f.Slice { + if val.Cap() < length { + val.Set(reflect.MakeSlice(val.Type(), length, length)) + } else if val.Len() < length { + val.Set(val.Slice(0, length)) + } + // special case byte slices for performance + if !f.Array && typ == Uint8 && f.defType == Uint8 { + copy(val.Bytes(), buf[:length]) + return nil + } + pos := 0 + size := typ.Size() + for i := 0; i < length; i++ { + if err := f.unpackVal(buf[pos:pos+size], val.Index(i), 1, options); err != nil { + return err + } + pos += size + } + return nil + } else { + return f.unpackVal(buf, val, length, options) + } +} diff --git a/vendor/github.com/lunixbochs/struc/field_test.go b/vendor/github.com/lunixbochs/struc/field_test.go new file mode 100644 index 00000000..45a07b21 --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/field_test.go @@ -0,0 +1,77 @@ +package struc + +import ( + "bytes" + "testing" +) + +type badFloat struct { + BadFloat int `struc:"float64"` +} + +func TestBadFloatField(t *testing.T) { + buf := bytes.NewReader([]byte("00000000")) + err := Unpack(buf, &badFloat{}) + if err == nil { + t.Fatal("failed to error on bad float unpack") + } +} + +type emptyLengthField struct { + Strlen int `struc:"sizeof=Str"` + Str []byte +} + +func TestEmptyLengthField(t *testing.T) { + var buf bytes.Buffer + s := &emptyLengthField{0, []byte("test")} + o := &emptyLengthField{} + if err := Pack(&buf, s); err != nil { + t.Fatal(err) + } + if err := Unpack(&buf, o); err != nil { + t.Fatal(err) + } + if !bytes.Equal(s.Str, o.Str) { + t.Fatal("empty length field encode failed") + } +} + +type fixedSlicePad struct { + Field []byte `struc:"[4]byte"` +} + +func TestFixedSlicePad(t *testing.T) { + var buf bytes.Buffer + ref := []byte{0, 0, 0, 0} + s := &fixedSlicePad{} + if err := Pack(&buf, s); err != nil { + t.Fatal(err) + } + if !bytes.Equal(buf.Bytes(), ref) { + t.Fatal("implicit fixed slice pack failed") + } + if err := Unpack(&buf, s); err != nil { + t.Fatal(err) + } + if !bytes.Equal(s.Field, ref) { + t.Fatal("implicit fixed slice unpack failed") + } +} + +type sliceCap struct { + Len int `struc:"sizeof=Field"` + Field []byte +} + +func TestSliceCap(t *testing.T) { + var buf bytes.Buffer + tmp := &sliceCap{0, []byte("1234")} + if err := Pack(&buf, tmp); err != nil { + t.Fatal(err) + } + tmp.Field = make([]byte, 0, 4) + if err := Unpack(&buf, tmp); err != nil { + t.Fatal(err) + } +} diff --git a/vendor/github.com/lunixbochs/struc/fields.go b/vendor/github.com/lunixbochs/struc/fields.go new file mode 100644 index 00000000..5d591bf0 --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/fields.go @@ -0,0 +1,172 @@ +package struc + +import ( + "encoding/binary" + "fmt" + "io" + "reflect" + "strings" +) + +type Fields []*Field + +func (f Fields) SetByteOrder(order binary.ByteOrder) { + for _, field := range f { + if field != nil { + field.Order = order + } + } +} + +func (f Fields) String() string { + fields := make([]string, len(f)) + for i, field := range f { + if field != nil { + fields[i] = field.String() + } + } + return "{" + strings.Join(fields, ", ") + "}" +} + +func (f Fields) Sizeof(val reflect.Value, options *Options) int { + for val.Kind() == reflect.Ptr { + val = val.Elem() + } + size := 0 + for i, field := range f { + if field != nil { + size += field.Size(val.Field(i), options) + } + } + return size +} + +func (f Fields) sizefrom(val reflect.Value, index []int) int { + field := val.FieldByIndex(index) + switch field.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return int(field.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + n := int(field.Uint()) + // all the builtin array length types are native int + // so this guards against weird truncation + if n < 0 { + return 0 + } + return n + default: + name := val.Type().FieldByIndex(index).Name + panic(fmt.Sprintf("sizeof field %T.%s not an integer type", val.Interface(), name)) + } +} + +func (f Fields) Pack(buf []byte, val reflect.Value, options *Options) (int, error) { + for val.Kind() == reflect.Ptr { + val = val.Elem() + } + pos := 0 + for i, field := range f { + if field == nil { + continue + } + v := val.Field(i) + length := field.Len + if field.Sizefrom != nil { + length = f.sizefrom(val, field.Sizefrom) + } + if length <= 0 && field.Slice { + length = v.Len() + } + if field.Sizeof != nil { + length := val.FieldByIndex(field.Sizeof).Len() + switch field.kind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + // allocating a new int here has fewer side effects (doesn't update the original struct) + // but it's a wasteful allocation + // the old method might work if we just cast the temporary int/uint to the target type + v = reflect.New(v.Type()).Elem() + v.SetInt(int64(length)) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + v = reflect.New(v.Type()).Elem() + v.SetUint(uint64(length)) + default: + panic(fmt.Sprintf("sizeof field is not int or uint type: %s, %s", field.Name, v.Type())) + } + } + if n, err := field.Pack(buf[pos:], v, length, options); err != nil { + return n, err + } else { + pos += n + } + } + return pos, nil +} + +func (f Fields) Unpack(r io.Reader, val reflect.Value, options *Options) error { + for val.Kind() == reflect.Ptr { + val = val.Elem() + } + var tmp [8]byte + var buf []byte + for i, field := range f { + if field == nil { + continue + } + v := val.Field(i) + length := field.Len + if field.Sizefrom != nil { + length = f.sizefrom(val, field.Sizefrom) + } + if v.Kind() == reflect.Ptr && !v.Elem().IsValid() { + v.Set(reflect.New(v.Type().Elem())) + } + if field.Type == Struct { + if field.Slice { + vals := reflect.MakeSlice(v.Type(), length, length) + for i := 0; i < length; i++ { + v := vals.Index(i) + fields, err := parseFields(v) + if err != nil { + return err + } + if err := fields.Unpack(r, v, options); err != nil { + return err + } + } + v.Set(vals) + } else { + // TODO: DRY (we repeat the inner loop above) + fields, err := parseFields(v) + if err != nil { + return err + } + if err := fields.Unpack(r, v, options); err != nil { + return err + } + } + continue + } else { + typ := field.Type.Resolve(options) + if typ == CustomType { + if err := v.Addr().Interface().(Custom).Unpack(r, length, options); err != nil { + return err + } + } else { + size := length * field.Type.Resolve(options).Size() + if size < 8 { + buf = tmp[:size] + } else { + buf = make([]byte, size) + } + if _, err := io.ReadFull(r, buf); err != nil { + return err + } + err := field.Unpack(buf[:size], v, length, options) + if err != nil { + return err + } + } + } + } + return nil +} diff --git a/vendor/github.com/lunixbochs/struc/fields_test.go b/vendor/github.com/lunixbochs/struc/fields_test.go new file mode 100644 index 00000000..850e3775 --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/fields_test.go @@ -0,0 +1,59 @@ +package struc + +import ( + "bytes" + "reflect" + "testing" +) + +var refVal = reflect.ValueOf(reference) + +func TestFieldsParse(t *testing.T) { + if _, err := parseFields(refVal); err != nil { + t.Fatal(err) + } +} + +func TestFieldsString(t *testing.T) { + fields, _ := parseFields(refVal) + fields.String() +} + +type sizefromStruct struct { + Size1 uint `struc:"sizeof=Var1"` + Var1 []byte + Size2 int `struc:"sizeof=Var2"` + Var2 []byte +} + +func TestFieldsSizefrom(t *testing.T) { + var test = sizefromStruct{ + Var1: []byte{1, 2, 3}, + Var2: []byte{4, 5, 6}, + } + var buf bytes.Buffer + err := Pack(&buf, &test) + if err != nil { + t.Fatal(err) + } + err = Unpack(&buf, &test) + if err != nil { + t.Fatal(err) + } +} + +type sizefromStructBad struct { + Size1 string `struc:"sizeof=Var1"` + Var1 []byte +} + +func TestFieldsSizefromBad(t *testing.T) { + var test = &sizefromStructBad{Var1: []byte{1, 2, 3}} + var buf bytes.Buffer + defer func() { + if err := recover(); err == nil { + t.Fatal("failed to panic on bad sizeof type") + } + }() + Pack(&buf, &test) +} diff --git a/vendor/github.com/lunixbochs/struc/legacy.go b/vendor/github.com/lunixbochs/struc/legacy.go new file mode 100644 index 00000000..5baf70d9 --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/legacy.go @@ -0,0 +1,16 @@ +package struc + +import ( + "encoding/binary" + "io" +) + +// Deprecated. Use PackWithOptions. +func PackWithOrder(w io.Writer, data interface{}, order binary.ByteOrder) error { + return PackWithOptions(w, data, &Options{Order: order}) +} + +// Deprecated. Use UnpackWithOptions. +func UnpackWithOrder(r io.Reader, data interface{}, order binary.ByteOrder) error { + return UnpackWithOptions(r, data, &Options{Order: order}) +} diff --git a/vendor/github.com/lunixbochs/struc/packable_test.go b/vendor/github.com/lunixbochs/struc/packable_test.go new file mode 100644 index 00000000..ec2bed9b --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/packable_test.go @@ -0,0 +1,123 @@ +package struc + +import ( + "bytes" + "fmt" + "testing" +) + +var packableReference = []byte{ + 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 5, 0, 6, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, +} + +func TestPackable(t *testing.T) { + var ( + buf bytes.Buffer + + i8 int8 = 1 + i16 int16 = 2 + i32 int32 = 3 + i64 int64 = 4 + u8 uint8 = 5 + u16 uint16 = 6 + u32 uint32 = 7 + u64 uint64 = 8 + + u8a = [8]uint8{9, 10, 11, 12, 13, 14, 15, 16} + u16a = [8]uint16{17, 18, 19, 20, 21, 22, 23, 24} + ) + // pack tests + if err := Pack(&buf, i8); err != nil { + t.Fatal(err) + } + if err := Pack(&buf, i16); err != nil { + t.Fatal(err) + } + if err := Pack(&buf, i32); err != nil { + t.Fatal(err) + } + if err := Pack(&buf, i64); err != nil { + t.Fatal(err) + } + if err := Pack(&buf, u8); err != nil { + t.Fatal(err) + } + if err := Pack(&buf, u16); err != nil { + t.Fatal(err) + } + if err := Pack(&buf, u32); err != nil { + t.Fatal(err) + } + if err := Pack(&buf, u64); err != nil { + t.Fatal(err) + } + if err := Pack(&buf, u8a[:]); err != nil { + t.Fatal(err) + } + if err := Pack(&buf, u16a[:]); err != nil { + t.Fatal(err) + } + if !bytes.Equal(buf.Bytes(), packableReference) { + fmt.Println(buf.Bytes()) + fmt.Println(packableReference) + t.Fatal("Packable Pack() did not match reference.") + } + // unpack tests + i8 = 0 + i16 = 0 + i32 = 0 + i64 = 0 + u8 = 0 + u16 = 0 + u32 = 0 + u64 = 0 + if err := Unpack(&buf, &i8); err != nil { + t.Fatal(err) + } + if err := Unpack(&buf, &i16); err != nil { + t.Fatal(err) + } + if err := Unpack(&buf, &i32); err != nil { + t.Fatal(err) + } + if err := Unpack(&buf, &i64); err != nil { + t.Fatal(err) + } + if err := Unpack(&buf, &u8); err != nil { + t.Fatal(err) + } + if err := Unpack(&buf, &u16); err != nil { + t.Fatal(err) + } + if err := Unpack(&buf, &u32); err != nil { + t.Fatal(err) + } + if err := Unpack(&buf, &u64); err != nil { + t.Fatal(err) + } + if err := Unpack(&buf, u8a[:]); err != nil { + t.Fatal(err) + } + if err := Unpack(&buf, u16a[:]); err != nil { + t.Fatal(err) + } + // unpack checks + if i8 != 1 || i16 != 2 || i32 != 3 || i64 != 4 { + t.Fatal("Signed integer unpack failed.") + } + if u8 != 5 || u16 != 6 || u32 != 7 || u64 != 8 { + t.Fatal("Unsigned integer unpack failed.") + } + for i := 0; i < 8; i++ { + if u8a[i] != uint8(i+9) { + t.Fatal("uint8 array unpack failed.") + } + } + for i := 0; i < 8; i++ { + if u16a[i] != uint16(i+17) { + t.Fatal("uint16 array unpack failed.") + } + } +} diff --git a/vendor/github.com/lunixbochs/struc/packer.go b/vendor/github.com/lunixbochs/struc/packer.go new file mode 100644 index 00000000..a3a91a22 --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/packer.go @@ -0,0 +1,13 @@ +package struc + +import ( + "io" + "reflect" +) + +type Packer interface { + Pack(buf []byte, val reflect.Value, options *Options) (int, error) + Unpack(r io.Reader, val reflect.Value, options *Options) error + Sizeof(val reflect.Value, options *Options) int + String() string +} diff --git a/vendor/github.com/lunixbochs/struc/parse.go b/vendor/github.com/lunixbochs/struc/parse.go new file mode 100644 index 00000000..060f43d3 --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/parse.go @@ -0,0 +1,219 @@ +package struc + +import ( + "encoding/binary" + "errors" + "fmt" + "reflect" + "regexp" + "strconv" + "strings" + "sync" +) + +// struc:"int32,big,sizeof=Data" + +type strucTag struct { + Type string + Order binary.ByteOrder + Sizeof string + Skip bool +} + +func parseStrucTag(tag reflect.StructTag) *strucTag { + t := &strucTag{ + Order: binary.BigEndian, + } + tagStr := tag.Get("struc") + if tagStr == "" { + // someone's going to typo this (I already did once) + // sorry if you made a module actually using this tag + // and you're mad at me now + tagStr = tag.Get("struct") + } + for _, s := range strings.Split(tagStr, ",") { + if strings.HasPrefix(s, "sizeof=") { + tmp := strings.SplitN(s, "=", 2) + t.Sizeof = tmp[1] + } else if s == "big" { + t.Order = binary.BigEndian + } else if s == "little" { + t.Order = binary.LittleEndian + } else if s == "skip" { + t.Skip = true + } else { + t.Type = s + } + } + return t +} + +var typeLenRe = regexp.MustCompile(`^\[(\d*)\]`) + +func parseField(f reflect.StructField) (fd *Field, tag *strucTag, err error) { + tag = parseStrucTag(f.Tag) + var ok bool + fd = &Field{ + Name: f.Name, + Len: 1, + Order: tag.Order, + Slice: false, + kind: f.Type.Kind(), + } + switch fd.kind { + case reflect.Array: + fd.Slice = true + fd.Array = true + fd.Len = f.Type.Len() + fd.kind = f.Type.Elem().Kind() + case reflect.Slice: + fd.Slice = true + fd.Len = -1 + fd.kind = f.Type.Elem().Kind() + case reflect.Ptr: + fd.Ptr = true + fd.kind = f.Type.Elem().Kind() + } + // check for custom types + tmp := reflect.New(f.Type) + if _, ok := tmp.Interface().(Custom); ok { + fd.Type = CustomType + return + } + var defTypeOk bool + fd.defType, defTypeOk = reflectTypeMap[fd.kind] + // find a type in the struct tag + pureType := typeLenRe.ReplaceAllLiteralString(tag.Type, "") + if fd.Type, ok = typeLookup[pureType]; ok { + fd.Len = 1 + match := typeLenRe.FindAllStringSubmatch(tag.Type, -1) + if len(match) > 0 && len(match[0]) > 1 { + fd.Slice = true + first := match[0][1] + // Field.Len = -1 indicates a []slice + if first == "" { + fd.Len = -1 + } else { + fd.Len, err = strconv.Atoi(first) + } + } + return + } + // the user didn't specify a type + switch f.Type { + case reflect.TypeOf(Size_t(0)): + fd.Type = SizeType + case reflect.TypeOf(Off_t(0)): + fd.Type = OffType + default: + if defTypeOk { + fd.Type = fd.defType + } else { + err = errors.New("struc: Could not find field type.") + } + } + return +} + +func parseFieldsLocked(v reflect.Value) (Fields, error) { + // we need to repeat this logic because parseFields() below can't be recursively called due to locking + for v.Kind() == reflect.Ptr { + v = v.Elem() + } + t := v.Type() + if v.NumField() < 1 { + return nil, errors.New("struc: Struct has no fields.") + } + sizeofMap := make(map[string][]int) + fields := make(Fields, v.NumField()) + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + f, tag, err := parseField(field) + if tag.Skip { + continue + } + if err != nil { + return nil, err + } + if !v.Field(i).CanSet() { + continue + } + f.Index = i + if tag.Sizeof != "" { + target, ok := t.FieldByName(tag.Sizeof) + if !ok { + return nil, fmt.Errorf("struc: `sizeof=%s` field does not exist", tag.Sizeof) + } + f.Sizeof = target.Index + sizeofMap[tag.Sizeof] = field.Index + } + if sizefrom, ok := sizeofMap[field.Name]; ok { + f.Sizefrom = sizefrom + } + if f.Len == -1 && f.Sizefrom == nil { + return nil, fmt.Errorf("struc: field `%s` is a slice with no length or sizeof field", field.Name) + } + // recurse into nested structs + // TODO: handle loops (probably by indirecting the []Field and putting pointer in cache) + if f.Type == Struct { + typ := field.Type + if f.Ptr { + typ = typ.Elem() + } + if f.Slice { + typ = typ.Elem() + } + f.Fields, err = parseFieldsLocked(reflect.New(typ)) + if err != nil { + return nil, err + } + } + fields[i] = f + } + return fields, nil +} + +var fieldCache = make(map[reflect.Type]Fields) +var fieldCacheLock sync.RWMutex +var parseLock sync.Mutex + +func fieldCacheLookup(t reflect.Type) Fields { + fieldCacheLock.RLock() + defer fieldCacheLock.RUnlock() + if cached, ok := fieldCache[t]; ok { + return cached + } + return nil +} + +func parseFields(v reflect.Value) (Fields, error) { + for v.Kind() == reflect.Ptr { + v = v.Elem() + } + t := v.Type() + + // fast path: hopefully the field parsing is already cached + if cached := fieldCacheLookup(t); cached != nil { + return cached, nil + } + + // hold a global lock so multiple goroutines can't parse (the same) fields at once + parseLock.Lock() + defer parseLock.Unlock() + + // check cache a second time, in case parseLock was just released by + // another thread who filled the cache for us + if cached := fieldCacheLookup(t); cached != nil { + return cached, nil + } + + // no luck, time to parse and fill the cache ourselves + fields, err := parseFieldsLocked(v) + if err != nil { + return nil, err + } + fieldCacheLock.Lock() + fieldCache[t] = fields + fieldCacheLock.Unlock() + return fields, nil +} diff --git a/vendor/github.com/lunixbochs/struc/parse_test.go b/vendor/github.com/lunixbochs/struc/parse_test.go new file mode 100644 index 00000000..861fdd19 --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/parse_test.go @@ -0,0 +1,62 @@ +package struc + +import ( + "bytes" + "reflect" + "testing" +) + +func parseTest(data interface{}) error { + _, err := parseFields(reflect.ValueOf(data)) + return err +} + +type empty struct{} + +func TestEmptyStruc(t *testing.T) { + if err := parseTest(&empty{}); err == nil { + t.Fatal("failed to error on empty struct") + } +} + +type chanStruct struct { + Test chan int +} + +func TestChanError(t *testing.T) { + if err := parseTest(&chanStruct{}); err == nil { + // TODO: should probably ignore channel fields + t.Fatal("failed to error on struct containing channel") + } +} + +type badSizeof struct { + Size int `struc:"sizeof=Bad"` +} + +func TestBadSizeof(t *testing.T) { + if err := parseTest(&badSizeof{}); err == nil { + t.Fatal("failed to error on missing Sizeof target") + } +} + +type missingSize struct { + Test []byte +} + +func TestMissingSize(t *testing.T) { + if err := parseTest(&missingSize{}); err == nil { + t.Fatal("failed to error on missing field size") + } +} + +type badNested struct { + Empty empty +} + +func TestNestedParseError(t *testing.T) { + var buf bytes.Buffer + if err := Pack(&buf, &badNested{}); err == nil { + t.Fatal("failed to error on bad nested struct") + } +} diff --git a/vendor/github.com/lunixbochs/struc/struc.go b/vendor/github.com/lunixbochs/struc/struc.go new file mode 100644 index 00000000..3d85fe32 --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/struc.go @@ -0,0 +1,117 @@ +package struc + +import ( + "encoding/binary" + "fmt" + "io" + "reflect" +) + +type Options struct { + ByteAlign int + PtrSize int + Order binary.ByteOrder +} + +func (o *Options) Validate() error { + if o.PtrSize == 0 { + o.PtrSize = 32 + } else { + switch o.PtrSize { + case 8, 16, 32, 64: + default: + return fmt.Errorf("Invalid Options.PtrSize: %d. Must be in (8, 16, 32, 64)", o.PtrSize) + } + } + return nil +} + +var emptyOptions = &Options{} + +func prep(data interface{}) (reflect.Value, Packer, error) { + value := reflect.ValueOf(data) + for value.Kind() == reflect.Ptr { + next := value.Elem().Kind() + if next == reflect.Struct || next == reflect.Ptr { + value = value.Elem() + } else { + break + } + } + switch value.Kind() { + case reflect.Struct: + fields, err := parseFields(value) + return value, fields, err + default: + if !value.IsValid() { + return reflect.Value{}, nil, fmt.Errorf("Invalid reflect.Value for %+v", data) + } + if c, ok := data.(Custom); ok { + return value, customFallback{c}, nil + } + return value, binaryFallback(value), nil + } +} + +func Pack(w io.Writer, data interface{}) error { + return PackWithOptions(w, data, nil) +} + +func PackWithOptions(w io.Writer, data interface{}, options *Options) error { + if options == nil { + options = emptyOptions + } + if err := options.Validate(); err != nil { + return err + } + val, packer, err := prep(data) + if err != nil { + return err + } + if val.Type().Kind() == reflect.String { + val = val.Convert(reflect.TypeOf([]byte{})) + } + size := packer.Sizeof(val, options) + buf := make([]byte, size) + if _, err := packer.Pack(buf, val, options); err != nil { + return err + } + _, err = w.Write(buf) + return err +} + +func Unpack(r io.Reader, data interface{}) error { + return UnpackWithOptions(r, data, nil) +} + +func UnpackWithOptions(r io.Reader, data interface{}, options *Options) error { + if options == nil { + options = emptyOptions + } + if err := options.Validate(); err != nil { + return err + } + val, packer, err := prep(data) + if err != nil { + return err + } + return packer.Unpack(r, val, options) +} + +func Sizeof(data interface{}) (int, error) { + return SizeofWithOptions(data, nil) +} + +func SizeofWithOptions(data interface{}, options *Options) (int, error) { + if options == nil { + options = emptyOptions + } + if err := options.Validate(); err != nil { + return 0, err + } + val, packer, err := prep(data) + if err != nil { + return 0, err + } + return packer.Sizeof(val, options), nil +} diff --git a/vendor/github.com/lunixbochs/struc/struc_test.go b/vendor/github.com/lunixbochs/struc/struc_test.go new file mode 100644 index 00000000..4b50707e --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/struc_test.go @@ -0,0 +1,200 @@ +package struc + +import ( + "bytes" + "encoding/binary" + "reflect" + "testing" +) + +type Nested struct { + Test2 int `struc:"int8"` +} + +type Example struct { + Pad []byte `struc:"[5]pad"` // 00 00 00 00 00 + I8f int `struc:"int8"` // 01 + I16f int `struc:"int16"` // 00 02 + I32f int `struc:"int32"` // 00 00 00 03 + I64f int `struc:"int64"` // 00 00 00 00 00 00 00 04 + U8f int `struc:"uint8,little"` // 05 + U16f int `struc:"uint16,little"` // 06 00 + U32f int `struc:"uint32,little"` // 07 00 00 00 + U64f int `struc:"uint64,little"` // 08 00 00 00 00 00 00 00 + Boolf int `struc:"bool"` // 01 + Byte4f []byte `struc:"[4]byte"` // "abcd" + + I8 int8 // 09 + I16 int16 // 00 0a + I32 int32 // 00 00 00 0b + I64 int64 // 00 00 00 00 00 00 00 0c + U8 uint8 `struc:"little"` // 0d + U16 uint16 `struc:"little"` // 0e 00 + U32 uint32 `struc:"little"` // 0f 00 00 00 + U64 uint64 `struc:"little"` // 10 00 00 00 00 00 00 00 + BoolT bool // 01 + BoolF bool // 00 + Byte4 [4]byte // "efgh" + Float1 float32 // 41 a0 00 00 + Float2 float64 // 41 35 00 00 00 00 00 00 + + Size int `struc:"sizeof=Str,little"` // 0a 00 00 00 + Str string `struc:"[]byte"` // "ijklmnopqr" + Strb string `struc:"[4]byte"` // "stuv" + + Size2 int `struc:"uint8,sizeof=Str2"` // 04 + Str2 string // "1234" + + Size3 int `struc:"uint8,sizeof=Bstr"` // 04 + Bstr []byte // "5678" + + Nested Nested // 00 00 00 01 + NestedP *Nested // 00 00 00 02 + TestP64 *int `struc:"int64"` // 00 00 00 05 + + NestedSize int `struc:"sizeof=NestedA"` // 00 00 00 02 + NestedA []Nested // [00 00 00 03, 00 00 00 04] + + Skip int `struc:"skip"` + + CustomTypeSize Int3 `struc:"sizeof=CustomTypeSizeArr"` // 00 00 00 04 + CustomTypeSizeArr []byte // "ABCD" +} + +var five = 5 + +var reference = &Example{ + nil, + 1, 2, 3, 4, 5, 6, 7, 8, 0, []byte{'a', 'b', 'c', 'd'}, + 9, 10, 11, 12, 13, 14, 15, 16, true, false, [4]byte{'e', 'f', 'g', 'h'}, + 20, 21, + 10, "ijklmnopqr", "stuv", + 4, "1234", + 4, []byte("5678"), + Nested{1}, &Nested{2}, &five, + 6, []Nested{{3}, {4}, {5}, {6}, {7}, {8}}, + 0, + Int3(4), []byte("ABCD"), +} + +var referenceBytes = []byte{ + 0, 0, 0, 0, 0, // pad(5) + 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, // fake int8-int64(1-4) + 5, 6, 0, 7, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, // fake little-endian uint8-uint64(5-8) + 0, // fake bool(0) + 'a', 'b', 'c', 'd', // fake [4]byte + + 9, 0, 10, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 12, // real int8-int64(9-12) + 13, 14, 0, 15, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, // real little-endian uint8-uint64(13-16) + 1, 0, // real bool(1), bool(0) + 'e', 'f', 'g', 'h', // real [4]byte + 65, 160, 0, 0, // real float32(20) + 64, 53, 0, 0, 0, 0, 0, 0, // real float64(21) + + 10, 0, 0, 0, // little-endian int32(10) sizeof=Str + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', // Str + 's', 't', 'u', 'v', // fake string([4]byte) + 04, '1', '2', '3', '4', // real string + 04, '5', '6', '7', '8', // fake []byte(string) + + 1, 2, // Nested{1}, Nested{2} + 0, 0, 0, 0, 0, 0, 0, 5, // &five + + 0, 0, 0, 6, // int32(6) + 3, 4, 5, 6, 7, 8, // [Nested{3}, ...Nested{8}] + + 0, 0, 4, 'A', 'B', 'C', 'D', // Int3(4), []byte("ABCD") +} + +func TestCodec(t *testing.T) { + var buf bytes.Buffer + if err := Pack(&buf, reference); err != nil { + t.Fatal(err) + } + out := &Example{} + if err := Unpack(&buf, out); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(reference, out) { + t.Fatal("encode/decode failed") + } +} + +func TestEncode(t *testing.T) { + var buf bytes.Buffer + if err := Pack(&buf, reference); err != nil { + t.Fatal(err) + } + if !bytes.Equal(buf.Bytes(), referenceBytes) { + t.Fatal("encode failed") + } +} + +func TestDecode(t *testing.T) { + buf := bytes.NewReader(referenceBytes) + out := &Example{} + if err := Unpack(buf, out); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(reference, out) { + t.Fatal("decode failed") + } +} + +func TestSizeof(t *testing.T) { + size, err := Sizeof(reference) + if err != nil { + t.Fatal(err) + } + if size != len(referenceBytes) { + t.Fatal("sizeof failed") + } +} + +type ExampleEndian struct { + T int `struc:"int16,big"` +} + +func TestEndianSwap(t *testing.T) { + var buf bytes.Buffer + big := &ExampleEndian{1} + if err := PackWithOrder(&buf, big, binary.BigEndian); err != nil { + t.Fatal(err) + } + little := &ExampleEndian{} + if err := UnpackWithOrder(&buf, little, binary.LittleEndian); err != nil { + t.Fatal(err) + } + if little.T != 256 { + t.Fatal("big -> little conversion failed") + } +} + +func TestNilValue(t *testing.T) { + var buf bytes.Buffer + if err := Pack(&buf, nil); err == nil { + t.Fatal("failed throw error for bad struct value") + } + if err := Unpack(&buf, nil); err == nil { + t.Fatal("failed throw error for bad struct value") + } + if _, err := Sizeof(nil); err == nil { + t.Fatal("failed to throw error for bad struct value") + } +} + +type sliceUnderrun struct { + Str string `struc:"[10]byte"` + Arr []uint16 `struc:"[10]uint16"` +} + +func TestSliceUnderrun(t *testing.T) { + var buf bytes.Buffer + v := sliceUnderrun{ + Str: "foo", + Arr: []uint16{1, 2, 3}, + } + if err := Pack(&buf, &v); err != nil { + t.Fatal(err) + } +} diff --git a/vendor/github.com/lunixbochs/struc/types.go b/vendor/github.com/lunixbochs/struc/types.go new file mode 100644 index 00000000..6ca97f48 --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/types.go @@ -0,0 +1,136 @@ +package struc + +import ( + "fmt" + "reflect" +) + +type Type int + +const ( + Invalid Type = iota + Pad + Bool + Int + Int8 + Uint8 + Int16 + Uint16 + Int32 + Uint32 + Int64 + Uint64 + Float32 + Float64 + String + Struct + Ptr + + SizeType + OffType + CustomType +) + +func (t Type) Resolve(options *Options) Type { + switch t { + case OffType: + switch options.PtrSize { + case 8: + return Int8 + case 16: + return Int16 + case 32: + return Int32 + case 64: + return Int64 + default: + panic(fmt.Sprintf("unsupported ptr bits: %d", options.PtrSize)) + } + case SizeType: + switch options.PtrSize { + case 8: + return Uint8 + case 16: + return Uint16 + case 32: + return Uint32 + case 64: + return Uint64 + default: + panic(fmt.Sprintf("unsupported ptr bits: %d", options.PtrSize)) + } + } + return t +} + +func (t Type) String() string { + return typeNames[t] +} + +func (t Type) Size() int { + switch t { + case SizeType, OffType: + panic("Size_t/Off_t types must be converted to another type using options.PtrSize") + case Pad, String, Int8, Uint8, Bool: + return 1 + case Int16, Uint16: + return 2 + case Int32, Uint32, Float32: + return 4 + case Int64, Uint64, Float64: + return 8 + default: + panic("Cannot resolve size of type:" + t.String()) + } +} + +var typeLookup = map[string]Type{ + "pad": Pad, + "bool": Bool, + "byte": Uint8, + "int8": Int8, + "uint8": Uint8, + "int16": Int16, + "uint16": Uint16, + "int32": Int32, + "uint32": Uint32, + "int64": Int64, + "uint64": Uint64, + "float32": Float32, + "float64": Float64, + + "size_t": SizeType, + "off_t": OffType, +} + +var typeNames = map[Type]string{ + CustomType: "Custom", +} + +func init() { + for name, enum := range typeLookup { + typeNames[enum] = name + } +} + +type Size_t uint64 +type Off_t int64 + +var reflectTypeMap = map[reflect.Kind]Type{ + reflect.Bool: Bool, + reflect.Int8: Int8, + reflect.Int16: Int16, + reflect.Int: Int32, + reflect.Int32: Int32, + reflect.Int64: Int64, + reflect.Uint8: Uint8, + reflect.Uint16: Uint16, + reflect.Uint: Uint32, + reflect.Uint32: Uint32, + reflect.Uint64: Uint64, + reflect.Float32: Float32, + reflect.Float64: Float64, + reflect.String: String, + reflect.Struct: Struct, + reflect.Ptr: Ptr, +} diff --git a/vendor/github.com/lunixbochs/struc/types_test.go b/vendor/github.com/lunixbochs/struc/types_test.go new file mode 100644 index 00000000..3b33e8f5 --- /dev/null +++ b/vendor/github.com/lunixbochs/struc/types_test.go @@ -0,0 +1,53 @@ +package struc + +import ( + "bytes" + "testing" +) + +func TestBadType(t *testing.T) { + defer func() { recover() }() + Type(-1).Size() + t.Fatal("failed to panic for invalid Type.Size()") +} + +func TestTypeString(t *testing.T) { + if Pad.String() != "pad" { + t.Fatal("type string representation failed") + } +} + +type sizeOffTest struct { + Size Size_t + Off Off_t +} + +func TestSizeOffTypes(t *testing.T) { + bits := []int{8, 16, 32, 64} + var buf bytes.Buffer + test := &sizeOffTest{1, 2} + for _, b := range bits { + if err := PackWithOptions(&buf, test, &Options{PtrSize: b}); err != nil { + t.Fatal(err) + } + } + reference := []byte{ + 1, 2, + 0, 1, 0, 2, + 0, 0, 0, 1, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, + } + if !bytes.Equal(reference, buf.Bytes()) { + t.Errorf("reference != bytes: %v", reference, buf.Bytes()) + } + reader := bytes.NewReader(buf.Bytes()) + for _, b := range bits { + out := &sizeOffTest{} + if err := UnpackWithOptions(reader, out, &Options{PtrSize: b}); err != nil { + t.Fatal(err) + } + if out.Size != 1 || out.Off != 2 { + t.Errorf("Size_t/Off_t mismatch: {%d, %d}\n%v", out.Size, out.Off, buf.Bytes()) + } + } +} diff --git a/vendor/github.com/mozilla/libaudit-go/.travis.yml b/vendor/github.com/mozilla/libaudit-go/.travis.yml new file mode 100644 index 00000000..f1950cd8 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/.travis.yml @@ -0,0 +1,13 @@ +language: go +dist: trusty +sudo: required +notifications: + email: false +go: + - 1.8 +before_install: + - sudo apt-get -qq update + - sudo apt-get install -y auditd +script: + - sudo service auditd stop + - make test diff --git a/vendor/github.com/mozilla/libaudit-go/LICENSE b/vendor/github.com/mozilla/libaudit-go/LICENSE new file mode 100644 index 00000000..e87a115e --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/LICENSE @@ -0,0 +1,363 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. + diff --git a/vendor/github.com/mozilla/libaudit-go/Makefile b/vendor/github.com/mozilla/libaudit-go/Makefile new file mode 100644 index 00000000..43d48477 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/Makefile @@ -0,0 +1,16 @@ +GOBIN := $(shell which go) +GO := GO15VENDOREXPERIMENT=1 $(GOBIN) +BUILDPRE := auditconstant_string.go + +test: $(BUILDPRE) + sudo $(GO) test -v -bench=. -covermode=count -coverprofile=coverage.out + +profile: $(BUILDPRE) + sudo $(GO) test -v -cpuprofile cpu.prof -memprofile mem.prof -bench=. + +auditconstant_string.go: audit_constant.go + $(GO) get golang.org/x/tools/cmd/stringer + $(GO) generate + +clean: + rm -f $(BUILDPRE) diff --git a/vendor/github.com/mozilla/libaudit-go/README.md b/vendor/github.com/mozilla/libaudit-go/README.md new file mode 100755 index 00000000..06663a17 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/README.md @@ -0,0 +1,108 @@ +# libaudit in Go + +libaudit-go is a go package for interfacing with Linux audit. + +[![Build Status](https://travis-ci.org/mozilla/libaudit-go.svg?branch=master)](https://travis-ci.org/mozilla/libaudit-go) +[![Go Report Card](https://goreportcard.com/badge/mozilla/libaudit-go "Go Report Card")](https://goreportcard.com/report/mozilla/libaudit-go) + +libaudit-go is a pure Go client library for interfacing with the Linux auditing framework. It provides functions +to interact with the auditing subsystems over Netlink, including controlling the rule set and obtaining/interpreting +incoming audit events. + +libaudit-go can be used to build go applications which perform tasks similar to the standard Linux auditing daemon +`auditd`. + +To get started see package documentation at [godoc](https://godoc.org/github.com/mozilla/libaudit-go). + +For a simple example of usage, see the [auditprint](./auditprint/) tool included in this repository. + +```bash +sudo service stop auditd +go get -u github.com/mozilla/libaudit-go +cd $GOPATH/src/github.com/mozilla/libaudit-go +go install github.com/mozilla/libaudit-go/auditprint +sudo $GOPATH/bin/auditprint testdata/rules.json +``` + +Some key functions are discussed in the overview section below. + +## Overview + +### General + +##### NewNetlinkConnection + +To use libaudit-go programs will need to initialize a new Netlink connection. `NewNetlinkConnection` can be used +to allocate a new `NetlinkConnection` type which can then be passed to other functions in the library. + +```go +s, err := libaudit.NewNetlinkConnection() +if err != nil { + fmt.Printf("NewNetlinkConnection: %v\n", err) +} +defer s.Close() +``` + +`NetlinkConnection` provides a `Send` and `Receive` method to send and receive Netlink messages to the kernel, +however generally applications will use the various other functions included in libaudit-go and do not need to +call these functions directly. + +##### GetAuditEvents + +GetAuditEvents starts an audit event monitor in a go-routine and returns. Programs can call this function and +specify a callback function as an argument. When the audit event monitor receives a new event, this callback +function will be called with the parsed `AuditEvent` as an argument. + +```go + +func myCallback(msg *libaudit.AuditEvent, err error) { + if err != nil { + // An error occurred getting or parsing the audit event + return + } + // Print the fields + fmt.Println(msg.Data) + // Print the raw event + fmt.Println(msg.Raw) +} + +libaudit.GetAuditEvents(s, myCallback) +``` + +##### GetRawAuditEvents + +`GetRawAuditEvents` behaves in a similar manner to `GetAuditEvents`, however programs can use this function +to instead just retrieve raw audit events from the kernel as a string, instead of having libaudit-go parse +these audit events into an `AuditEvent` type. + +### Audit Rules + +Audit rules can be loaded into the kernel using libaudit-go, however the format differs from the common rule +set used by userspace tools such as auditctl/auditd. + +libaudit-go rulesets are defined as a JSON document. See [rules.json](./testdata/rules.json) as an example. +The libaudit-go type which stores the rule set is `AuditRules`. + +##### SetRules + +`SetRules` can be used to load an audit rule set into the kernel. The function takes a marshalled `AuditRules` +type as an argument (slice of bytes), and converts the JSON based rule set into a set of audit rules suitable +for submission to the kernel. + +The function then makes the required Netlink calls to clear the existing rule set and load the new rules. + +```go +// Load all rules from a file +content, err := ioutil.ReadFile("audit.rules.json") +if err != nil { + fmt.Printf("error: %v\n", err) + os.Exit(1) +} + +// Set audit rules +err = libaudit.SetRules(s, content) +if err != nil { + fmt.Printf("error: %v\n", err) + os.Exit(1) +} +``` diff --git a/vendor/github.com/mozilla/libaudit-go/audit_constant.go b/vendor/github.com/mozilla/libaudit-go/audit_constant.go new file mode 100644 index 00000000..279d4aa4 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/audit_constant.go @@ -0,0 +1,474 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package libaudit + +// audit_constants.go contains constants used within libaudit, sourced from linux/audit.h +// (from the Linux kernel) and from libaudit.h in the audit userspace source code. + +// Code generated using various audit headers, DO NOT EDIT. + +const ( + AUDIT_STATUS_SIZE = 40 // Size of auditStatus +) + +const ( + MAX_AUDIT_MESSAGE_LENGTH = 8970 + AUDIT_MAX_FIELDS = 64 + AUDIT_BITMASK_SIZE = 64 + //Rule Flags + AUDIT_FILTER_USER = 0x00 /* Apply rule to user-generated messages */ + AUDIT_FILTER_TASK = 0x01 /* Apply rule at task creation (not syscall) */ + AUDIT_FILTER_ENTRY = 0x02 /* Apply rule at syscall entry */ + AUDIT_FILTER_WATCH = 0x03 /* Apply rule to file system watches */ + AUDIT_FILTER_EXIT = 0x04 /* Apply rule at syscall exit */ + AUDIT_FILTER_TYPE = 0x05 /* Apply rule at audit_log_start */ + /* These are used in filter control */ + AUDIT_FILTER_MASK = 0x07 /* Mask to get actual filter */ + AUDIT_FILTER_UNSET = 0x80 /* This value means filter is unset */ + + /* Rule actions */ + AUDIT_NEVER = 0 /* Do not build context if rule matches */ + AUDIT_POSSIBLE = 1 /* Build context if rule matches */ + AUDIT_ALWAYS = 2 /* Generate audit record if rule matches */ + + /* Rule fields */ + /* These are useful when checking the + * task structure at task creation time + * (AUDIT_PER_TASK). */ + AUDIT_PID = 0 + AUDIT_UID = 1 + AUDIT_EUID = 2 + AUDIT_SUID = 3 + AUDIT_FSUID = 4 + AUDIT_GID = 5 + AUDIT_EGID = 6 + AUDIT_SGID = 7 + AUDIT_FSGID = 8 + AUDIT_LOGINUID = 9 + AUDIT_OBJ_GID = 110 + AUDIT_OBJ_UID = 109 + AUDIT_EXIT = 103 + AUDIT_PERS = 10 + AUDIT_FILTER_EXCLUDE = 0x05 + AUDIT_ARCH = 11 + PATH_MAX = 4096 + AUDIT_MSGTYPE = 12 + AUDIT_MAX_KEY_LEN = 256 + AUDIT_PERM = 106 + AUDIT_FILTERKEY = 210 + AUDIT_SUBJ_USER = 13 /* security label user */ + AUDIT_SUBJ_ROLE = 14 /* security label role */ + AUDIT_SUBJ_TYPE = 15 /* security label type */ + AUDIT_SUBJ_SEN = 16 /* security label sensitivity label */ + AUDIT_SUBJ_CLR = 17 /* security label clearance label */ + AUDIT_PPID = 18 + AUDIT_OBJ_USER = 19 + AUDIT_OBJ_ROLE = 20 + AUDIT_OBJ_TYPE = 21 + AUDIT_WATCH = 105 + AUDIT_DIR = 107 + AUDIT_OBJ_LEV_LOW = 22 + AUDIT_OBJ_LEV_HIGH = 23 + AUDIT_LOGINUID_SET = 24 + AUDIT_DEVMAJOR = 100 + AUDIT_DEVMINOR = 101 + AUDIT_INODE = 102 + AUDIT_SUCCESS = 104 + AUDIT_FIELD_COMPARE = 111 + AUDIT_EXE = 112 + AUDIT_PERM_EXEC = 1 + AUDIT_PERM_WRITE = 2 + AUDIT_PERM_READ = 4 + AUDIT_PERM_ATTR = 8 + AUDIT_FILETYPE = 108 + AUDIT_ARG0 = 200 + AUDIT_ARG1 = (AUDIT_ARG0 + 1) + AUDIT_ARG2 = (AUDIT_ARG0 + 2) + AUDIT_ARG3 = (AUDIT_ARG0 + 3) + AUDIT_BIT_MASK = 0x08000000 + AUDIT_LESS_THAN = 0x10000000 + AUDIT_GREATER_THAN = 0x20000000 + AUDIT_NOT_EQUAL = 0x30000000 + AUDIT_EQUAL = 0x40000000 + AUDIT_BIT_TEST = (AUDIT_BIT_MASK | AUDIT_EQUAL) + AUDIT_LESS_THAN_OR_EQUAL = (AUDIT_LESS_THAN | AUDIT_EQUAL) + AUDIT_GREATER_THAN_OR_EQUAL = (AUDIT_GREATER_THAN | AUDIT_EQUAL) + AUDIT_OPERATORS = (AUDIT_EQUAL | AUDIT_NOT_EQUAL | AUDIT_BIT_MASK) + /* Status symbols */ + /* Mask values */ + AUDIT_STATUS_ENABLED = 0x0001 + AUDIT_STATUS_FAILURE = 0x0002 + AUDIT_STATUS_PID = 0x0004 + AUDIT_STATUS_RATE_LIMIT = 0x0008 + AUDIT_STATUS_BACKLOG_LIMIT = 0x0010 + /* Failure-to-log actions */ + AUDIT_FAIL_SILENT = 0 + AUDIT_FAIL_PRINTK = 1 + AUDIT_FAIL_PANIC = 2 + + /* distinguish syscall tables */ + __AUDIT_ARCH_64BIT = 0x80000000 + __AUDIT_ARCH_LE = 0x40000000 + AUDIT_ARCH_ALPHA = (EM_ALPHA | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE) + AUDIT_ARCH_ARM = (EM_ARM | __AUDIT_ARCH_LE) + AUDIT_ARCH_ARMEB = (EM_ARM) + AUDIT_ARCH_CRIS = (EM_CRIS | __AUDIT_ARCH_LE) + AUDIT_ARCH_FRV = (EM_FRV) + AUDIT_ARCH_I386 = (EM_386 | __AUDIT_ARCH_LE) + AUDIT_ARCH_IA64 = (EM_IA_64 | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE) + AUDIT_ARCH_M32R = (EM_M32R) + AUDIT_ARCH_M68K = (EM_68K) + AUDIT_ARCH_MIPS = (EM_MIPS) + AUDIT_ARCH_MIPSEL = (EM_MIPS | __AUDIT_ARCH_LE) + AUDIT_ARCH_MIPS64 = (EM_MIPS | __AUDIT_ARCH_64BIT) + AUDIT_ARCH_MIPSEL64 = (EM_MIPS | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE) + // AUDIT_ARCH_OPENRISC = (EM_OPENRISC) + // AUDIT_ARCH_PARISC = (EM_PARISC) + // AUDIT_ARCH_PARISC64 = (EM_PARISC | __AUDIT_ARCH_64BIT) + AUDIT_ARCH_PPC = (EM_PPC) + AUDIT_ARCH_PPC64 = (EM_PPC64 | __AUDIT_ARCH_64BIT) + AUDIT_ARCH_S390 = (EM_S390) + AUDIT_ARCH_S390X = (EM_S390 | __AUDIT_ARCH_64BIT) + AUDIT_ARCH_SH = (EM_SH) + AUDIT_ARCH_SHEL = (EM_SH | __AUDIT_ARCH_LE) + AUDIT_ARCH_SH64 = (EM_SH | __AUDIT_ARCH_64BIT) + AUDIT_ARCH_SHEL64 = (EM_SH | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE) + AUDIT_ARCH_SPARC = (EM_SPARC) + AUDIT_ARCH_SPARC64 = (EM_SPARCV9 | __AUDIT_ARCH_64BIT) + AUDIT_ARCH_X86_64 = (EM_X86_64 | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE) + ///Temporary Solution need to add linux/elf-em.h + EM_NONE = 0 + EM_M32 = 1 + EM_SPARC = 2 + EM_386 = 3 + EM_68K = 4 + EM_88K = 5 + EM_486 = 6 /* Perhaps disused */ + EM_860 = 7 + EM_MIPS = 8 /* MIPS R3000 (officially, big-endian only) */ + /* Next two are historical and binaries and + modules of these types will be rejected by + Linux. */ + EM_MIPS_RS3_LE = 10 /* MIPS R3000 little-endian */ + EM_MIPS_RS4_BE = 10 /* MIPS R4000 big-endian */ + + EM_PARISC = 15 /* HPPA */ + EM_SPARC32PLUS = 18 /* Sun's "v8plus" */ + EM_PPC = 20 /* PowerPC */ + EM_PPC64 = 21 /* PowerPC64 */ + EM_SPU = 23 /* Cell BE SPU */ + EM_ARM = 40 /* ARM 32 bit */ + EM_SH = 42 /* SuperH */ + EM_SPARCV9 = 43 /* SPARC v9 64-bit */ + EM_IA_64 = 50 /* HP/Intel IA-64 */ + EM_X86_64 = 62 /* AMD x86-64 */ + EM_S390 = 22 /* IBM S/390 */ + EM_CRIS = 76 /* Axis Communications 32-bit embedded processor */ + EM_V850 = 87 /* NEC v850 */ + EM_M32R = 88 /* Renesas M32R */ + EM_MN10300 = 89 /* Panasonic/MEI MN10300, AM33 */ + EM_BLACKFIN = 106 /* ADI Blackfin Processor */ + EM_TI_C6000 = 140 /* TI C6X DSPs */ + EM_AARCH64 = 183 /* ARM 64 bit */ + EM_FRV = 0x5441 /* Fujitsu FR-V */ + EM_AVR32 = 0x18ad /* Atmel AVR32 */ + + /* + * This is an interim value that we will use until the committee comes + * up with a final number. + */ + EM_ALPHA = 0x9026 + + /* Bogus old v850 magic number, used by old tools. */ + EM_CYGNUS_V850 = 0x9080 + /* Bogus old m32r magic number, used by old tools. */ + EM_CYGNUS_M32R = 0x9041 + /* This is the old interim value for S/390 architecture */ + EM_S390_OLD = 0xA390 + /* Also Panasonic/MEI MN10300, AM33 */ + EM_CYGNUS_MN10300 = 0xbeef + //AUDIT_ARCH determination purpose + _UTSNAME_LENGTH = 65 + _UTSNAME_DOMAIN_LENGTH = _UTSNAME_LENGTH + _UTSNAME_NODENAME_LENGTH = _UTSNAME_DOMAIN_LENGTH +) + +/* Audit message types as of 2.6.29 kernel: + * 1000 - 1099 are for commanding the audit system + * 1100 - 1199 user space trusted application messages + * 1200 - 1299 messages internal to the audit daemon + * 1300 - 1399 audit event messages + * 1400 - 1499 kernel SE Linux use + * 1500 - 1599 AppArmor events + * 1600 - 1699 kernel crypto events + * 1700 - 1799 kernel anomaly records + * 1800 - 1899 kernel integrity labels and related events + * 1800 - 1999 future kernel use + * 2001 - 2099 unused (kernel) + * 2100 - 2199 user space anomaly records + * 2200 - 2299 user space actions taken in response to anomalies + * 2300 - 2399 user space generated LSPP events + * 2400 - 2499 user space crypto events + * 2500 - 2599 user space virtualization management events + * 2600 - 2999 future user space (maybe integrity labels and related events) + */ + +//go:generate stringer -type=auditConstant audit_constant.go +type auditConstant uint16 + +const ( + AUDIT_GET auditConstant = 1000 /* Get status */ + AUDIT_SET auditConstant = 1001 /* Set status (enable/disable/auditd) */ + AUDIT_LIST auditConstant = 1002 /* List syscall rules -- deprecated */ + AUDIT_ADD auditConstant = 1003 /* Add syscall rule -- deprecated */ + AUDIT_DEL auditConstant = 1004 /* Delete syscall rule -- deprecated */ + AUDIT_USER auditConstant = 1005 /* Message from userspace -- deprecated */ + AUDIT_LOGIN auditConstant = 1006 /* Define the login id and information */ + AUDIT_WATCH_INS auditConstant = 1007 /* Insert file/dir watch entry */ + AUDIT_WATCH_REM auditConstant = 1008 /* Remove file/dir watch entry */ + AUDIT_WATCH_LIST auditConstant = 1009 /* List all file/dir watches */ + AUDIT_SIGNAL_INFO auditConstant = 1010 /* Get info about sender of signal to auditd */ + AUDIT_ADD_RULE auditConstant = 1011 /* Add syscall filtering rule */ + AUDIT_DEL_RULE auditConstant = 1012 /* Delete syscall filtering rule */ + AUDIT_LIST_RULES auditConstant = 1013 /* List syscall filtering rules */ + AUDIT_TRIM auditConstant = 1014 /* Trim junk from watched tree */ + AUDIT_MAKE_EQUIV auditConstant = 1015 /* Append to watched tree */ + AUDIT_TTY_GET auditConstant = 1016 /* Get TTY auditing status */ + AUDIT_TTY_SET auditConstant = 1017 /* Set TTY auditing status */ + AUDIT_SET_FEATURE auditConstant = 1018 /* Turn an audit feature on or off */ + AUDIT_GET_FEATURE auditConstant = 1019 /* Get which features are enabled */ + + AUDIT_FIRST_USER_MSG auditConstant = 1100 /* First user space message */ + AUDIT_LAST_USER_MSG auditConstant = 1199 /* Last user space message */ + AUDIT_USER_AUTH auditConstant = 1100 /* User space authentication */ + AUDIT_USER_ACCT auditConstant = 1101 /* User space acct change */ + AUDIT_USER_MGMT auditConstant = 1102 /* User space acct management */ + AUDIT_CRED_ACQ auditConstant = 1103 /* User space credential acquired */ + AUDIT_CRED_DISP auditConstant = 1104 /* User space credential disposed */ + AUDIT_USER_START auditConstant = 1105 /* User space session start */ + AUDIT_USER_END auditConstant = 1106 /* User space session end */ + AUDIT_USER_AVC auditConstant = 1107 /* User space avc message */ + AUDIT_USER_CHAUTHTOK auditConstant = 1108 /* User space acct attr changed */ + AUDIT_USER_ERR auditConstant = 1109 /* User space acct state err */ + AUDIT_CRED_REFR auditConstant = 1110 /* User space credential refreshed */ + AUDIT_USYS_CONFIG auditConstant = 1111 /* User space system config change */ + AUDIT_USER_LOGIN auditConstant = 1112 /* User space user has logged in */ + AUDIT_USER_LOGOUT auditConstant = 1113 /* User space user has logged out */ + AUDIT_ADD_USER auditConstant = 1114 /* User space user account added */ + AUDIT_DEL_USER auditConstant = 1115 /* User space user account deleted */ + AUDIT_ADD_GROUP auditConstant = 1116 /* User space group added */ + AUDIT_DEL_GROUP auditConstant = 1117 /* User space group deleted */ + AUDIT_DAC_CHECK auditConstant = 1118 /* User space DAC check results */ + AUDIT_CHGRP_ID auditConstant = 1119 /* User space group ID changed */ + AUDIT_TEST auditConstant = 1120 /* Used for test success messages */ + AUDIT_TRUSTED_APP auditConstant = 1121 /* Trusted app msg - freestyle text */ + AUDIT_USER_SELINUX_ERR auditConstant = 1122 /* SE Linux user space error */ + AUDIT_USER_CMD auditConstant = 1123 /* User shell command and args */ + AUDIT_USER_TTY auditConstant = 1124 /* Non-ICANON TTY input meaning */ + AUDIT_CHUSER_ID auditConstant = 1125 /* Changed user ID supplemental data */ + AUDIT_GRP_AUTH auditConstant = 1126 /* Authentication for group password */ + AUDIT_SYSTEM_BOOT auditConstant = 1127 /* System boot */ + AUDIT_SYSTEM_SHUTDOWN auditConstant = 1128 /* System shutdown */ + AUDIT_SYSTEM_RUNLEVEL auditConstant = 1129 /* System runlevel change */ + AUDIT_SERVICE_START auditConstant = 1130 /* Service (daemon) start */ + AUDIT_SERVICE_STOP auditConstant = 1131 /* Service (daemon) stop */ + AUDIT_GRP_MGMT auditConstant = 1132 /* Group account attr was modified */ + AUDIT_GRP_CHAUTHTOK auditConstant = 1133 /* Group acct password or pin changed */ + AUDIT_MAC_CHECK auditConstant = 1134 /* User space MAC decision results */ + AUDIT_ACCT_LOCK auditConstant = 1135 /* User's account locked by admin */ + AUDIT_ACCT_UNLOCK auditConstant = 1136 /* User's account unlocked by admin */ + + AUDIT_FIRST_DAEMON auditConstant = 1200 + AUDIT_LAST_DAEMON auditConstant = 1299 + AUDIT_DAEMON_CONFIG auditConstant = 1203 /* Daemon config change */ + AUDIT_DAEMON_RECONFIG auditConstant = 1204 /* Auditd should reconfigure */ + AUDIT_DAEMON_ROTATE auditConstant = 1205 /* Auditd should rotate logs */ + AUDIT_DAEMON_RESUME auditConstant = 1206 /* Auditd should resume logging */ + AUDIT_DAEMON_ACCEPT auditConstant = 1207 /* Auditd accepted remote connection */ + AUDIT_DAEMON_CLOSE auditConstant = 1208 /* Auditd closed remote connection */ + + AUDIT_SYSCALL auditConstant = 1300 /* Syscall event */ + /* AUDIT_FS_WATCH auditConstant = 1301 * Deprecated */ + AUDIT_PATH auditConstant = 1302 /* Filename path information */ + AUDIT_IPC auditConstant = 1303 /* IPC record */ + AUDIT_SOCKETCALL auditConstant = 1304 /* sys_socketcall arguments */ + AUDIT_CONFIG_CHANGE auditConstant = 1305 /* Audit system configuration change */ + AUDIT_SOCKADDR auditConstant = 1306 /* sockaddr copied as syscall arg */ + AUDIT_CWD auditConstant = 1307 /* Current working directory */ + AUDIT_EXECVE auditConstant = 1309 /* execve arguments */ + AUDIT_IPC_SET_PERM auditConstant = 1311 /* IPC new permissions record type */ + AUDIT_MQ_OPEN auditConstant = 1312 /* POSIX MQ open record type */ + AUDIT_MQ_SENDRECV auditConstant = 1313 /* POSIX MQ send/receive record type */ + AUDIT_MQ_NOTIFY auditConstant = 1314 /* POSIX MQ notify record type */ + AUDIT_MQ_GETSETATTR auditConstant = 1315 /* POSIX MQ get/set attribute record type */ + AUDIT_KERNEL_OTHER auditConstant = 1316 /* For use by 3rd party modules */ + AUDIT_FD_PAIR auditConstant = 1317 /* audit record for pipe/socketpair */ + AUDIT_OBJ_PID auditConstant = 1318 /* ptrace target */ + AUDIT_TTY auditConstant = 1319 /* Input on an administrative TTY */ + AUDIT_EOE auditConstant = 1320 /* End of multi-record event */ + AUDIT_BPRM_FCAPS auditConstant = 1321 /* Information about fcaps increasing perms */ + AUDIT_CAPSET auditConstant = 1322 /* Record showing argument to sys_capset */ + AUDIT_MMAP auditConstant = 1323 /* Record showing descriptor and flags in mmap */ + AUDIT_NETFILTER_PKT auditConstant = 1324 /* Packets traversing netfilter chains */ + AUDIT_NETFILTER_CFG auditConstant = 1325 /* Netfilter chain modifications */ + AUDIT_SECCOMP auditConstant = 1326 /* Secure Computing event */ + AUDIT_PROCTITLE auditConstant = 1327 /* Proctitle emit event */ + AUDIT_FEATURE_CHANGE auditConstant = 1328 /* audit log listing feature changes */ + + /* AUDIT_FIRST_EVENT 1300 */ //TODO: libaudit define this as AUDIT_FIRST_EVENT but audit.h differently. + AUDIT_LAST_EVENT auditConstant = 1399 + + /* AUDIT_FIRST_SELINUX 1400 */ // TODO: libaudit define this as AUDIT_FIRST_SELINUX but audit.h as AUDIT_AVC + AUDIT_AVC auditConstant = 1400 /* SE Linux avc denial or grant */ + AUDIT_SELINUX_ERR auditConstant = 1401 /* internal SE Linux Errors */ + AUDIT_AVC_PATH auditConstant = 1402 /* dentry, vfsmount pair from avc */ + AUDIT_MAC_POLICY_LOAD auditConstant = 1403 /* Policy file load */ + AUDIT_MAC_STATUS auditConstant = 1404 /* Changed enforcing,permissive,off */ + AUDIT_MAC_CONFIG_CHANGE auditConstant = 1405 /* Changes to booleans */ + AUDIT_MAC_UNLBL_ALLOW auditConstant = 1406 /* NetLabel: allow unlabeled traffic */ + AUDIT_MAC_CIPSOV4_ADD auditConstant = 1407 /* NetLabel: add CIPSOv4 DOI entry */ + AUDIT_MAC_CIPSOV4_DEL auditConstant = 1408 /* NetLabel: del CIPSOv4 DOI entry */ + AUDIT_MAC_MAP_ADD auditConstant = 1409 /* NetLabel: add LSM domain mapping */ + AUDIT_MAC_MAP_DEL auditConstant = 1410 /* NetLabel: del LSM domain mapping */ + AUDIT_MAC_IPSEC_ADDSA auditConstant = 1411 /* Not used */ + AUDIT_MAC_IPSEC_DELSA auditConstant = 1412 /* Not used */ + AUDIT_MAC_IPSEC_ADDSPD auditConstant = 1413 /* Not used */ + AUDIT_MAC_IPSEC_DELSPD auditConstant = 1414 /* Not used */ + AUDIT_MAC_IPSEC_EVENT auditConstant = 1415 /* Audit an IPSec event */ + AUDIT_MAC_UNLBL_STCADD auditConstant = 1416 /* NetLabel: add a static label */ + AUDIT_MAC_UNLBL_STCDEL auditConstant = 1417 /* NetLabel: del a static label */ + AUDIT_LAST_SELINUX auditConstant = 1499 + + AUDIT_FIRST_APPARMOR auditConstant = 1500 + AUDIT_LAST_APPARMOR auditConstant = 1599 + + AUDIT_AA auditConstant = 1500 /* Not upstream yet*/ + AUDIT_APPARMOR_AUDIT auditConstant = 1501 + AUDIT_APPARMOR_ALLOWED auditConstant = 1502 + AUDIT_APPARMOR_DENIED auditConstant = 1503 + AUDIT_APPARMOR_HT auditConstant = 1504 + AUDIT_APPARMOR_STATUS auditConstant = 1505 + AUDIT_APPARMOR_ERROR auditConstant = 1506 + + AUDIT_FIRST_KERN_CRYPTO_MSG auditConstant = 1600 + AUDIT_LAST_KERN_CRYPTO_MSG auditConstant = 1699 + + // AUDIT_FIRST_KERN_ANOM_MSG auditConstant = 1700 + AUDIT_LAST_KERN_ANOM_MSG auditConstant = 1799 + AUDIT_ANOM_PROMISCUOUS auditConstant = 1700 /* Device changed promiscuous mode */ + AUDIT_ANOM_ABEND auditConstant = 1701 /* Process ended abnormally */ + AUDIT_ANOM_LINK auditConstant = 1702 /* Suspicious use of file links */ + + AUDIT_INTEGRITY_FIRST_MSG auditConstant = 1800 + AUDIT_TINTEGRITY_LAST_MSG auditConstant = 1899 + + AUDIT_INTEGRITY_DATA auditConstant = 1800 /* Data integrity verification */ + AUDIT_INTEGRITY_METADATA auditConstant = 1801 // Metadata integrity verification + AUDIT_INTEGRITY_STATUS auditConstant = 1802 /* integrity enable status */ + AUDIT_INTEGRITY_HASH auditConstant = 1803 /* integrity HASH type */ + AUDIT_INTEGRITY_PCR auditConstant = 1804 /* PCR invalidation msgs */ + AUDIT_INTEGRITY_RULE auditConstant = 1805 /* Policy rule */ + AUDIT_KERNEL auditConstant = 2000 /* Asynchronous audit record. NOT A REQUEST. */ + + AUDIT_FIRST_ANOM_MSG auditConstant = 2100 + AUDIT_LAST_ANOM_MSG auditConstant = 2199 + AUDIT_ANOM_LOGIN_FAILURES auditConstant = 2100 // Failed login limit reached + AUDIT_ANOM_LOGIN_TIME auditConstant = 2101 // Login attempted at bad time + AUDIT_ANOM_LOGIN_SESSIONS auditConstant = 2102 // Max concurrent sessions reached + AUDIT_ANOM_LOGIN_ACCT auditConstant = 2103 // Login attempted to watched acct + AUDIT_ANOM_LOGIN_LOCATION auditConstant = 2104 // Login from forbidden location + AUDIT_ANOM_MAX_DAC auditConstant = 2105 // Max DAC failures reached + AUDIT_ANOM_MAX_MAC auditConstant = 2106 // Max MAC failures reached + AUDIT_ANOM_AMTU_FAIL auditConstant = 2107 // AMTU failure + AUDIT_ANOM_RBAC_FAIL auditConstant = 2108 // RBAC self test failure + AUDIT_ANOM_RBAC_INTEGRITY_FAIL auditConstant = 2109 // RBAC file Tegrity failure + AUDIT_ANOM_CRYPTO_FAIL auditConstant = 2110 // Crypto system test failure + AUDIT_ANOM_ACCESS_FS auditConstant = 2111 // Access of file or dir + AUDIT_ANOM_EXEC auditConstant = 2112 // Execution of file + AUDIT_ANOM_MK_EXEC auditConstant = 2113 // Make an executable + AUDIT_ANOM_ADD_ACCT auditConstant = 2114 // Adding an acct + AUDIT_ANOM_DEL_ACCT auditConstant = 2115 // Deleting an acct + AUDIT_ANOM_MOD_ACCT auditConstant = 2116 // Changing an acct + AUDIT_ANOM_ROOT_TRANS auditConstant = 2117 // User became root + + AUDIT_FIRST_ANOM_RESP auditConstant = 2200 + AUDIT_LAST_ANOM_RESP auditConstant = 2299 + AUDIT_RESP_ANOMALY auditConstant = 2200 /* Anomaly not reacted to */ + AUDIT_RESP_ALERT auditConstant = 2201 /* Alert email was sent */ + AUDIT_RESP_KILL_PROC auditConstant = 2202 /* Kill program */ + AUDIT_RESP_TERM_ACCESS auditConstant = 2203 /* Terminate session */ + AUDIT_RESP_ACCT_REMOTE auditConstant = 2204 /* Acct locked from remote access*/ + AUDIT_RESP_ACCT_LOCK_TIMED auditConstant = 2205 /* User acct locked for time */ + AUDIT_RESP_ACCT_UNLOCK_TIMED auditConstant = 2206 /* User acct unlocked from time */ + AUDIT_RESP_ACCT_LOCK auditConstant = 2207 /* User acct was locked */ + AUDIT_RESP_TERM_LOCK auditConstant = 2208 /* Terminal was locked */ + AUDIT_RESP_SEBOOL auditConstant = 2209 /* Set an SE Linux boolean */ + AUDIT_RESP_EXEC auditConstant = 2210 /* Execute a script */ + AUDIT_RESP_SINGLE auditConstant = 2211 /* Go to single user mode */ + AUDIT_RESP_HALT auditConstant = 2212 /* take the system down */ + + AUDIT_FIRST_USER_LSPP_MSG auditConstant = 2300 + AUDIT_LAST_USER_LSPP_MSG auditConstant = 2399 + AUDIT_USER_ROLE_CHANGE auditConstant = 2300 /* User changed to a new role */ + AUDIT_ROLE_ASSIGN auditConstant = 2301 /* Admin assigned user to role */ + AUDIT_ROLE_REMOVE auditConstant = 2302 /* Admin removed user from role */ + AUDIT_LABEL_OVERRIDE auditConstant = 2303 /* Admin is overriding a label */ + AUDIT_LABEL_LEVEL_CHANGE auditConstant = 2304 /* Object's level was changed */ + AUDIT_USER_LABELED_EXPORT auditConstant = 2305 /* Object exported with label */ + AUDIT_USER_UNLABELED_EXPORT auditConstant = 2306 /* Object exported without label */ + AUDIT_DEV_ALLOC auditConstant = 2307 /* Device was allocated */ + AUDIT_DEV_DEALLOC auditConstant = 2308 /* Device was deallocated */ + AUDIT_FS_RELABEL auditConstant = 2309 /* Filesystem relabeled */ + AUDIT_USER_MAC_POLICY_LOAD auditConstant = 2310 /* Userspc daemon loaded policy */ + AUDIT_ROLE_MODIFY auditConstant = 2311 /* Admin modified a role */ + AUDIT_USER_MAC_CONFIG_CHANGE auditConstant = 2312 /* Change made to MAC policy */ + + AUDIT_FIRST_CRYPTO_MSG auditConstant = 2400 + AUDIT_CRYPTO_TEST_USER auditConstant = 2400 /* Crypto test results */ + AUDIT_CRYPTO_PARAM_CHANGE_USER auditConstant = 2401 /* Crypto attribute change */ + AUDIT_CRYPTO_LOGIN auditConstant = 2402 /* Logged in as crypto officer */ + AUDIT_CRYPTO_LOGOUT auditConstant = 2403 /* Logged out from crypto */ + AUDIT_CRYPTO_KEY_USER auditConstant = 2404 /* Create,delete,negotiate */ + AUDIT_CRYPTO_FAILURE_USER auditConstant = 2405 /* Fail decrypt,encrypt,randomiz */ + AUDIT_CRYPTO_REPLAY_USER auditConstant = 2406 /* Crypto replay detected */ + AUDIT_CRYPTO_SESSION auditConstant = 2407 /* Record parameters set during TLS session establishment */ + AUDIT_CRYPTO_IKE_SA auditConstant = 2408 /* Record parameters related to IKE SA */ + AUDIT_CRYPTO_IPSEC_SA auditConstant = 2409 /* Record parameters related to IPSEC SA */ + + AUDIT_LAST_CRYPTO_MSG auditConstant = 2499 + + AUDIT_FIRST_VIRT_MSG auditConstant = 2500 + AUDIT_VIRT_CONTROL auditConstant = 2500 /* Start, Pause, Stop VM */ + AUDIT_VIRT_RESOURCE auditConstant = 2501 /* Resource assignment */ + AUDIT_VIRT_MACHINE_ID auditConstant = 2502 /* Binding of label to VM */ + AUDIT_LAST_VIRT_MSG auditConstant = 2599 + AUDIT_LAST_USER_MSG2 auditConstant = 2999 + // Field Comparing Constants + AUDIT_COMPARE_UID_TO_OBJ_UID auditConstant = 1 + AUDIT_COMPARE_GID_TO_OBJ_GID auditConstant = 2 + AUDIT_COMPARE_EUID_TO_OBJ_UID auditConstant = 3 + AUDIT_COMPARE_EGID_TO_OBJ_GID auditConstant = 4 + AUDIT_COMPARE_AUID_TO_OBJ_UID auditConstant = 5 + AUDIT_COMPARE_SUID_TO_OBJ_UID auditConstant = 6 + AUDIT_COMPARE_SGID_TO_OBJ_GID auditConstant = 7 + AUDIT_COMPARE_FSUID_TO_OBJ_UID auditConstant = 8 + AUDIT_COMPARE_FSGID_TO_OBJ_GID auditConstant = 9 + AUDIT_COMPARE_UID_TO_AUID auditConstant = 10 + AUDIT_COMPARE_UID_TO_EUID auditConstant = 11 + AUDIT_COMPARE_UID_TO_FSUID auditConstant = 12 + AUDIT_COMPARE_UID_TO_SUID auditConstant = 13 + AUDIT_COMPARE_AUID_TO_FSUID auditConstant = 14 + AUDIT_COMPARE_AUID_TO_SUID auditConstant = 15 + AUDIT_COMPARE_AUID_TO_EUID auditConstant = 16 + AUDIT_COMPARE_EUID_TO_SUID auditConstant = 17 + AUDIT_COMPARE_EUID_TO_FSUID auditConstant = 18 + AUDIT_COMPARE_SUID_TO_FSUID auditConstant = 19 + AUDIT_COMPARE_GID_TO_EGID auditConstant = 20 + AUDIT_COMPARE_GID_TO_FSGID auditConstant = 21 + AUDIT_COMPARE_GID_TO_SGID auditConstant = 22 + AUDIT_COMPARE_EGID_TO_FSGID auditConstant = 23 + AUDIT_COMPARE_EGID_TO_SGID auditConstant = 24 + AUDIT_COMPARE_SGID_TO_FSGID auditConstant = 25 +) diff --git a/vendor/github.com/mozilla/libaudit-go/audit_events.go b/vendor/github.com/mozilla/libaudit-go/audit_events.go new file mode 100644 index 00000000..3ce8e43c --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/audit_events.go @@ -0,0 +1,164 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package libaudit + +import ( + "errors" + "fmt" + "strconv" + "syscall" +) + +// EventCallback is the function definition for any function that wants to receive an AuditEvent as soon as +// it is received from the kernel. Error will be set to indicate any error that occurs while receiving +// messages. +type EventCallback func(*AuditEvent, error) + +// RawEventCallback is similar to EventCallback but the difference is that the function will receive only +// the message string which contains the audit event and not the parsed AuditEvent struct. +type RawEventCallback func(string, error) + +// AuditEvent is a parsed audit message. +type AuditEvent struct { + Serial string // Message serial + Timestamp string // Timestamp + Type string // Audit event type + Data map[string]string // Map of field values in the audit message + Raw string // Raw audit message from kernel +} + +// NewAuditEvent takes a NetlinkMessage passed from the netlink connection and parses the data +// from the message header to return an AuditEvent type. +// +// Note that it is possible here that we don't have a full event to return. In some cases, a +// single audit event may be represented by multiple audit events from the kernel. This function +// looks after buffering partial fragments of a full event, and may only return the complete event +// once an AUDIT_EOE record has been recieved for the audit event. +// +// See https://www.redhat.com/archives/linux-audit/2016-January/msg00019.html for additional information +// on the behavior of this function. +func NewAuditEvent(msg NetlinkMessage) (*AuditEvent, error) { + x, err := ParseAuditEvent(string(msg.Data[:]), auditConstant(msg.Header.Type), true) + if err != nil { + return nil, err + } + if (*x).Type == "auditConstant("+strconv.Itoa(int(msg.Header.Type))+")" { + return nil, fmt.Errorf("unknown message type %d", msg.Header.Type) + } + + // Determine if the event type is one which the kernel is expected to send only a single + // packet for; in these cases we don't need to look into buffering it and can return the + // event immediately. + if auditConstant(msg.Header.Type) < AUDIT_SYSCALL || + auditConstant(msg.Header.Type) >= AUDIT_FIRST_ANOM_MSG { + return x, nil + } + + // If this is an EOE message, get the entire processed message and return it. + if auditConstant(msg.Header.Type) == AUDIT_EOE { + return bufferGet(x), nil + } + + // Otherwise we need to buffer this message. + bufferEvent(x) + + return nil, nil +} + +// GetAuditEvents receives audit messages from the kernel and parses them into an AuditEvent. +// It passes them along the callback function and if any error occurs while receiving the message, +// the same will be passed in the callback as well. +// +// This function executes a go-routine (which does not return) and the function itself returns +// immediately. +func GetAuditEvents(s Netlink, cb EventCallback) { + go func() { + for { + select { + default: + msgs, _ := s.Receive(false) + for _, msg := range msgs { + if msg.Header.Type == syscall.NLMSG_ERROR { + err := int32(hostEndian.Uint32(msg.Data[0:4])) + if err != 0 { + cb(nil, fmt.Errorf("audit error %d", err)) + } + } else { + nae, err := NewAuditEvent(msg) + if nae == nil { + continue + } + cb(nae, err) + } + } + } + } + }() +} + +// GetRawAuditEvents is similar to GetAuditEvents, however it returns raw messages and does not parse +// incoming audit data. +func GetRawAuditEvents(s Netlink, cb RawEventCallback) { + go func() { + for { + select { + default: + msgs, _ := s.Receive(false) + for _, msg := range msgs { + var ( + m string + err error + ) + if msg.Header.Type == syscall.NLMSG_ERROR { + v := int32(hostEndian.Uint32(msg.Data[0:4])) + if v != 0 { + cb(m, fmt.Errorf("audit error %d", v)) + } + } else { + Type := auditConstant(msg.Header.Type) + if Type.String() == "auditConstant("+strconv.Itoa(int(msg.Header.Type))+")" { + err = errors.New("Unknown Type: " + string(msg.Header.Type)) + } else { + m = "type=" + Type.String()[6:] + + " msg=" + string(msg.Data[:]) + "\n" + } + } + cb(m, err) + } + } + } + }() +} + +// GetAuditMessages is a blocking function (runs in forever for loop) that receives audit messages +// from the kernel and parses them to AuditEvent. It passes them along the callback function and if +// any error occurs while receiving the message, the same will be passed in the callback as well. +// +// It will return when a signal is received on the done channel. +func GetAuditMessages(s Netlink, cb EventCallback, done *chan bool) { + for { + select { + case <-*done: + return + default: + msgs, _ := s.Receive(false) + for _, msg := range msgs { + if msg.Header.Type == syscall.NLMSG_ERROR { + v := int32(hostEndian.Uint32(msg.Data[0:4])) + if v != 0 { + cb(nil, fmt.Errorf("audit error %d", v)) + } + } else { + nae, err := NewAuditEvent(msg) + if nae == nil { + continue + } + cb(nae, err) + } + } + } + } + +} diff --git a/vendor/github.com/mozilla/libaudit-go/auditconstant_string.go b/vendor/github.com/mozilla/libaudit-go/auditconstant_string.go new file mode 100644 index 00000000..3a9a488c --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/auditconstant_string.go @@ -0,0 +1,239 @@ +// Code generated by "stringer -type=auditConstant audit_constant.go"; DO NOT EDIT. + +package libaudit + +import "fmt" + +const _auditConstant_name = "AUDIT_COMPARE_UID_TO_OBJ_UIDAUDIT_COMPARE_GID_TO_OBJ_GIDAUDIT_COMPARE_EUID_TO_OBJ_UIDAUDIT_COMPARE_EGID_TO_OBJ_GIDAUDIT_COMPARE_AUID_TO_OBJ_UIDAUDIT_COMPARE_SUID_TO_OBJ_UIDAUDIT_COMPARE_SGID_TO_OBJ_GIDAUDIT_COMPARE_FSUID_TO_OBJ_UIDAUDIT_COMPARE_FSGID_TO_OBJ_GIDAUDIT_COMPARE_UID_TO_AUIDAUDIT_COMPARE_UID_TO_EUIDAUDIT_COMPARE_UID_TO_FSUIDAUDIT_COMPARE_UID_TO_SUIDAUDIT_COMPARE_AUID_TO_FSUIDAUDIT_COMPARE_AUID_TO_SUIDAUDIT_COMPARE_AUID_TO_EUIDAUDIT_COMPARE_EUID_TO_SUIDAUDIT_COMPARE_EUID_TO_FSUIDAUDIT_COMPARE_SUID_TO_FSUIDAUDIT_COMPARE_GID_TO_EGIDAUDIT_COMPARE_GID_TO_FSGIDAUDIT_COMPARE_GID_TO_SGIDAUDIT_COMPARE_EGID_TO_FSGIDAUDIT_COMPARE_EGID_TO_SGIDAUDIT_COMPARE_SGID_TO_FSGIDAUDIT_GETAUDIT_SETAUDIT_LISTAUDIT_ADDAUDIT_DELAUDIT_USERAUDIT_LOGINAUDIT_WATCH_INSAUDIT_WATCH_REMAUDIT_WATCH_LISTAUDIT_SIGNAL_INFOAUDIT_ADD_RULEAUDIT_DEL_RULEAUDIT_LIST_RULESAUDIT_TRIMAUDIT_MAKE_EQUIVAUDIT_TTY_GETAUDIT_TTY_SETAUDIT_SET_FEATUREAUDIT_GET_FEATUREAUDIT_FIRST_USER_MSGAUDIT_USER_ACCTAUDIT_USER_MGMTAUDIT_CRED_ACQAUDIT_CRED_DISPAUDIT_USER_STARTAUDIT_USER_ENDAUDIT_USER_AVCAUDIT_USER_CHAUTHTOKAUDIT_USER_ERRAUDIT_CRED_REFRAUDIT_USYS_CONFIGAUDIT_USER_LOGINAUDIT_USER_LOGOUTAUDIT_ADD_USERAUDIT_DEL_USERAUDIT_ADD_GROUPAUDIT_DEL_GROUPAUDIT_DAC_CHECKAUDIT_CHGRP_IDAUDIT_TESTAUDIT_TRUSTED_APPAUDIT_USER_SELINUX_ERRAUDIT_USER_CMDAUDIT_USER_TTYAUDIT_CHUSER_IDAUDIT_GRP_AUTHAUDIT_SYSTEM_BOOTAUDIT_SYSTEM_SHUTDOWNAUDIT_SYSTEM_RUNLEVELAUDIT_SERVICE_STARTAUDIT_SERVICE_STOPAUDIT_GRP_MGMTAUDIT_GRP_CHAUTHTOKAUDIT_MAC_CHECKAUDIT_ACCT_LOCKAUDIT_ACCT_UNLOCKAUDIT_LAST_USER_MSGAUDIT_FIRST_DAEMONAUDIT_DAEMON_CONFIGAUDIT_DAEMON_RECONFIGAUDIT_DAEMON_ROTATEAUDIT_DAEMON_RESUMEAUDIT_DAEMON_ACCEPTAUDIT_DAEMON_CLOSEAUDIT_LAST_DAEMONAUDIT_SYSCALLAUDIT_PATHAUDIT_IPCAUDIT_SOCKETCALLAUDIT_CONFIG_CHANGEAUDIT_SOCKADDRAUDIT_CWDAUDIT_EXECVEAUDIT_IPC_SET_PERMAUDIT_MQ_OPENAUDIT_MQ_SENDRECVAUDIT_MQ_NOTIFYAUDIT_MQ_GETSETATTRAUDIT_KERNEL_OTHERAUDIT_FD_PAIRAUDIT_OBJ_PIDAUDIT_TTYAUDIT_EOEAUDIT_BPRM_FCAPSAUDIT_CAPSETAUDIT_MMAPAUDIT_NETFILTER_PKTAUDIT_NETFILTER_CFGAUDIT_SECCOMPAUDIT_PROCTITLEAUDIT_FEATURE_CHANGEAUDIT_LAST_EVENTAUDIT_AVCAUDIT_SELINUX_ERRAUDIT_AVC_PATHAUDIT_MAC_POLICY_LOADAUDIT_MAC_STATUSAUDIT_MAC_CONFIG_CHANGEAUDIT_MAC_UNLBL_ALLOWAUDIT_MAC_CIPSOV4_ADDAUDIT_MAC_CIPSOV4_DELAUDIT_MAC_MAP_ADDAUDIT_MAC_MAP_DELAUDIT_MAC_IPSEC_ADDSAAUDIT_MAC_IPSEC_DELSAAUDIT_MAC_IPSEC_ADDSPDAUDIT_MAC_IPSEC_DELSPDAUDIT_MAC_IPSEC_EVENTAUDIT_MAC_UNLBL_STCADDAUDIT_MAC_UNLBL_STCDELAUDIT_LAST_SELINUXAUDIT_FIRST_APPARMORAUDIT_APPARMOR_AUDITAUDIT_APPARMOR_ALLOWEDAUDIT_APPARMOR_DENIEDAUDIT_APPARMOR_HTAUDIT_APPARMOR_STATUSAUDIT_APPARMOR_ERRORAUDIT_LAST_APPARMORAUDIT_FIRST_KERN_CRYPTO_MSGAUDIT_LAST_KERN_CRYPTO_MSGAUDIT_ANOM_PROMISCUOUSAUDIT_ANOM_ABENDAUDIT_ANOM_LINKAUDIT_LAST_KERN_ANOM_MSGAUDIT_INTEGRITY_FIRST_MSGAUDIT_INTEGRITY_METADATAAUDIT_INTEGRITY_STATUSAUDIT_INTEGRITY_HASHAUDIT_INTEGRITY_PCRAUDIT_INTEGRITY_RULEAUDIT_TINTEGRITY_LAST_MSGAUDIT_KERNELAUDIT_FIRST_ANOM_MSGAUDIT_ANOM_LOGIN_TIMEAUDIT_ANOM_LOGIN_SESSIONSAUDIT_ANOM_LOGIN_ACCTAUDIT_ANOM_LOGIN_LOCATIONAUDIT_ANOM_MAX_DACAUDIT_ANOM_MAX_MACAUDIT_ANOM_AMTU_FAILAUDIT_ANOM_RBAC_FAILAUDIT_ANOM_RBAC_INTEGRITY_FAILAUDIT_ANOM_CRYPTO_FAILAUDIT_ANOM_ACCESS_FSAUDIT_ANOM_EXECAUDIT_ANOM_MK_EXECAUDIT_ANOM_ADD_ACCTAUDIT_ANOM_DEL_ACCTAUDIT_ANOM_MOD_ACCTAUDIT_ANOM_ROOT_TRANSAUDIT_LAST_ANOM_MSGAUDIT_FIRST_ANOM_RESPAUDIT_RESP_ALERTAUDIT_RESP_KILL_PROCAUDIT_RESP_TERM_ACCESSAUDIT_RESP_ACCT_REMOTEAUDIT_RESP_ACCT_LOCK_TIMEDAUDIT_RESP_ACCT_UNLOCK_TIMEDAUDIT_RESP_ACCT_LOCKAUDIT_RESP_TERM_LOCKAUDIT_RESP_SEBOOLAUDIT_RESP_EXECAUDIT_RESP_SINGLEAUDIT_RESP_HALTAUDIT_LAST_ANOM_RESPAUDIT_FIRST_USER_LSPP_MSGAUDIT_ROLE_ASSIGNAUDIT_ROLE_REMOVEAUDIT_LABEL_OVERRIDEAUDIT_LABEL_LEVEL_CHANGEAUDIT_USER_LABELED_EXPORTAUDIT_USER_UNLABELED_EXPORTAUDIT_DEV_ALLOCAUDIT_DEV_DEALLOCAUDIT_FS_RELABELAUDIT_USER_MAC_POLICY_LOADAUDIT_ROLE_MODIFYAUDIT_USER_MAC_CONFIG_CHANGEAUDIT_LAST_USER_LSPP_MSGAUDIT_FIRST_CRYPTO_MSGAUDIT_CRYPTO_PARAM_CHANGE_USERAUDIT_CRYPTO_LOGINAUDIT_CRYPTO_LOGOUTAUDIT_CRYPTO_KEY_USERAUDIT_CRYPTO_FAILURE_USERAUDIT_CRYPTO_REPLAY_USERAUDIT_CRYPTO_SESSIONAUDIT_CRYPTO_IKE_SAAUDIT_CRYPTO_IPSEC_SAAUDIT_LAST_CRYPTO_MSGAUDIT_FIRST_VIRT_MSGAUDIT_VIRT_RESOURCEAUDIT_VIRT_MACHINE_IDAUDIT_LAST_VIRT_MSGAUDIT_LAST_USER_MSG2" + +var _auditConstant_map = map[auditConstant]string{ + 1: _auditConstant_name[0:28], + 2: _auditConstant_name[28:56], + 3: _auditConstant_name[56:85], + 4: _auditConstant_name[85:114], + 5: _auditConstant_name[114:143], + 6: _auditConstant_name[143:172], + 7: _auditConstant_name[172:201], + 8: _auditConstant_name[201:231], + 9: _auditConstant_name[231:261], + 10: _auditConstant_name[261:286], + 11: _auditConstant_name[286:311], + 12: _auditConstant_name[311:337], + 13: _auditConstant_name[337:362], + 14: _auditConstant_name[362:389], + 15: _auditConstant_name[389:415], + 16: _auditConstant_name[415:441], + 17: _auditConstant_name[441:467], + 18: _auditConstant_name[467:494], + 19: _auditConstant_name[494:521], + 20: _auditConstant_name[521:546], + 21: _auditConstant_name[546:572], + 22: _auditConstant_name[572:597], + 23: _auditConstant_name[597:624], + 24: _auditConstant_name[624:650], + 25: _auditConstant_name[650:677], + 1000: _auditConstant_name[677:686], + 1001: _auditConstant_name[686:695], + 1002: _auditConstant_name[695:705], + 1003: _auditConstant_name[705:714], + 1004: _auditConstant_name[714:723], + 1005: _auditConstant_name[723:733], + 1006: _auditConstant_name[733:744], + 1007: _auditConstant_name[744:759], + 1008: _auditConstant_name[759:774], + 1009: _auditConstant_name[774:790], + 1010: _auditConstant_name[790:807], + 1011: _auditConstant_name[807:821], + 1012: _auditConstant_name[821:835], + 1013: _auditConstant_name[835:851], + 1014: _auditConstant_name[851:861], + 1015: _auditConstant_name[861:877], + 1016: _auditConstant_name[877:890], + 1017: _auditConstant_name[890:903], + 1018: _auditConstant_name[903:920], + 1019: _auditConstant_name[920:937], + 1100: _auditConstant_name[937:957], + 1101: _auditConstant_name[957:972], + 1102: _auditConstant_name[972:987], + 1103: _auditConstant_name[987:1001], + 1104: _auditConstant_name[1001:1016], + 1105: _auditConstant_name[1016:1032], + 1106: _auditConstant_name[1032:1046], + 1107: _auditConstant_name[1046:1060], + 1108: _auditConstant_name[1060:1080], + 1109: _auditConstant_name[1080:1094], + 1110: _auditConstant_name[1094:1109], + 1111: _auditConstant_name[1109:1126], + 1112: _auditConstant_name[1126:1142], + 1113: _auditConstant_name[1142:1159], + 1114: _auditConstant_name[1159:1173], + 1115: _auditConstant_name[1173:1187], + 1116: _auditConstant_name[1187:1202], + 1117: _auditConstant_name[1202:1217], + 1118: _auditConstant_name[1217:1232], + 1119: _auditConstant_name[1232:1246], + 1120: _auditConstant_name[1246:1256], + 1121: _auditConstant_name[1256:1273], + 1122: _auditConstant_name[1273:1295], + 1123: _auditConstant_name[1295:1309], + 1124: _auditConstant_name[1309:1323], + 1125: _auditConstant_name[1323:1338], + 1126: _auditConstant_name[1338:1352], + 1127: _auditConstant_name[1352:1369], + 1128: _auditConstant_name[1369:1390], + 1129: _auditConstant_name[1390:1411], + 1130: _auditConstant_name[1411:1430], + 1131: _auditConstant_name[1430:1448], + 1132: _auditConstant_name[1448:1462], + 1133: _auditConstant_name[1462:1481], + 1134: _auditConstant_name[1481:1496], + 1135: _auditConstant_name[1496:1511], + 1136: _auditConstant_name[1511:1528], + 1199: _auditConstant_name[1528:1547], + 1200: _auditConstant_name[1547:1565], + 1203: _auditConstant_name[1565:1584], + 1204: _auditConstant_name[1584:1605], + 1205: _auditConstant_name[1605:1624], + 1206: _auditConstant_name[1624:1643], + 1207: _auditConstant_name[1643:1662], + 1208: _auditConstant_name[1662:1680], + 1299: _auditConstant_name[1680:1697], + 1300: _auditConstant_name[1697:1710], + 1302: _auditConstant_name[1710:1720], + 1303: _auditConstant_name[1720:1729], + 1304: _auditConstant_name[1729:1745], + 1305: _auditConstant_name[1745:1764], + 1306: _auditConstant_name[1764:1778], + 1307: _auditConstant_name[1778:1787], + 1309: _auditConstant_name[1787:1799], + 1311: _auditConstant_name[1799:1817], + 1312: _auditConstant_name[1817:1830], + 1313: _auditConstant_name[1830:1847], + 1314: _auditConstant_name[1847:1862], + 1315: _auditConstant_name[1862:1881], + 1316: _auditConstant_name[1881:1899], + 1317: _auditConstant_name[1899:1912], + 1318: _auditConstant_name[1912:1925], + 1319: _auditConstant_name[1925:1934], + 1320: _auditConstant_name[1934:1943], + 1321: _auditConstant_name[1943:1959], + 1322: _auditConstant_name[1959:1971], + 1323: _auditConstant_name[1971:1981], + 1324: _auditConstant_name[1981:2000], + 1325: _auditConstant_name[2000:2019], + 1326: _auditConstant_name[2019:2032], + 1327: _auditConstant_name[2032:2047], + 1328: _auditConstant_name[2047:2067], + 1399: _auditConstant_name[2067:2083], + 1400: _auditConstant_name[2083:2092], + 1401: _auditConstant_name[2092:2109], + 1402: _auditConstant_name[2109:2123], + 1403: _auditConstant_name[2123:2144], + 1404: _auditConstant_name[2144:2160], + 1405: _auditConstant_name[2160:2183], + 1406: _auditConstant_name[2183:2204], + 1407: _auditConstant_name[2204:2225], + 1408: _auditConstant_name[2225:2246], + 1409: _auditConstant_name[2246:2263], + 1410: _auditConstant_name[2263:2280], + 1411: _auditConstant_name[2280:2301], + 1412: _auditConstant_name[2301:2322], + 1413: _auditConstant_name[2322:2344], + 1414: _auditConstant_name[2344:2366], + 1415: _auditConstant_name[2366:2387], + 1416: _auditConstant_name[2387:2409], + 1417: _auditConstant_name[2409:2431], + 1499: _auditConstant_name[2431:2449], + 1500: _auditConstant_name[2449:2469], + 1501: _auditConstant_name[2469:2489], + 1502: _auditConstant_name[2489:2511], + 1503: _auditConstant_name[2511:2532], + 1504: _auditConstant_name[2532:2549], + 1505: _auditConstant_name[2549:2570], + 1506: _auditConstant_name[2570:2590], + 1599: _auditConstant_name[2590:2609], + 1600: _auditConstant_name[2609:2636], + 1699: _auditConstant_name[2636:2662], + 1700: _auditConstant_name[2662:2684], + 1701: _auditConstant_name[2684:2700], + 1702: _auditConstant_name[2700:2715], + 1799: _auditConstant_name[2715:2739], + 1800: _auditConstant_name[2739:2764], + 1801: _auditConstant_name[2764:2788], + 1802: _auditConstant_name[2788:2810], + 1803: _auditConstant_name[2810:2830], + 1804: _auditConstant_name[2830:2849], + 1805: _auditConstant_name[2849:2869], + 1899: _auditConstant_name[2869:2894], + 2000: _auditConstant_name[2894:2906], + 2100: _auditConstant_name[2906:2926], + 2101: _auditConstant_name[2926:2947], + 2102: _auditConstant_name[2947:2972], + 2103: _auditConstant_name[2972:2993], + 2104: _auditConstant_name[2993:3018], + 2105: _auditConstant_name[3018:3036], + 2106: _auditConstant_name[3036:3054], + 2107: _auditConstant_name[3054:3074], + 2108: _auditConstant_name[3074:3094], + 2109: _auditConstant_name[3094:3124], + 2110: _auditConstant_name[3124:3146], + 2111: _auditConstant_name[3146:3166], + 2112: _auditConstant_name[3166:3181], + 2113: _auditConstant_name[3181:3199], + 2114: _auditConstant_name[3199:3218], + 2115: _auditConstant_name[3218:3237], + 2116: _auditConstant_name[3237:3256], + 2117: _auditConstant_name[3256:3277], + 2199: _auditConstant_name[3277:3296], + 2200: _auditConstant_name[3296:3317], + 2201: _auditConstant_name[3317:3333], + 2202: _auditConstant_name[3333:3353], + 2203: _auditConstant_name[3353:3375], + 2204: _auditConstant_name[3375:3397], + 2205: _auditConstant_name[3397:3423], + 2206: _auditConstant_name[3423:3451], + 2207: _auditConstant_name[3451:3471], + 2208: _auditConstant_name[3471:3491], + 2209: _auditConstant_name[3491:3508], + 2210: _auditConstant_name[3508:3523], + 2211: _auditConstant_name[3523:3540], + 2212: _auditConstant_name[3540:3555], + 2299: _auditConstant_name[3555:3575], + 2300: _auditConstant_name[3575:3600], + 2301: _auditConstant_name[3600:3617], + 2302: _auditConstant_name[3617:3634], + 2303: _auditConstant_name[3634:3654], + 2304: _auditConstant_name[3654:3678], + 2305: _auditConstant_name[3678:3703], + 2306: _auditConstant_name[3703:3730], + 2307: _auditConstant_name[3730:3745], + 2308: _auditConstant_name[3745:3762], + 2309: _auditConstant_name[3762:3778], + 2310: _auditConstant_name[3778:3804], + 2311: _auditConstant_name[3804:3821], + 2312: _auditConstant_name[3821:3849], + 2399: _auditConstant_name[3849:3873], + 2400: _auditConstant_name[3873:3895], + 2401: _auditConstant_name[3895:3925], + 2402: _auditConstant_name[3925:3943], + 2403: _auditConstant_name[3943:3962], + 2404: _auditConstant_name[3962:3983], + 2405: _auditConstant_name[3983:4008], + 2406: _auditConstant_name[4008:4032], + 2407: _auditConstant_name[4032:4052], + 2408: _auditConstant_name[4052:4071], + 2409: _auditConstant_name[4071:4092], + 2499: _auditConstant_name[4092:4113], + 2500: _auditConstant_name[4113:4133], + 2501: _auditConstant_name[4133:4152], + 2502: _auditConstant_name[4152:4173], + 2599: _auditConstant_name[4173:4192], + 2999: _auditConstant_name[4192:4212], +} + +func (i auditConstant) String() string { + if str, ok := _auditConstant_map[i]; ok { + return str + } + return fmt.Sprintf("auditConstant(%d)", i) +} diff --git a/vendor/github.com/mozilla/libaudit-go/auditprint/auditprint.go b/vendor/github.com/mozilla/libaudit-go/auditprint/auditprint.go new file mode 100644 index 00000000..0d9b3863 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/auditprint/auditprint.go @@ -0,0 +1,105 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// auditprint is a simple command line tool that loads an audit rule set from a JSON file, +// applies it to the current kernel and begins printing any audit event the kernel sends in +// JSON format. +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + + "github.com/mozilla/libaudit-go" +) + +func auditProc(e *libaudit.AuditEvent, err error) { + if err != nil { + // See if the error is libaudit.ErrorAuditParse, if so convert and also display + // the audit record we could not parse + if nerr, ok := err.(libaudit.ErrorAuditParse); ok { + fmt.Printf("parser error: %v: %v\n", nerr, nerr.Raw) + } else { + fmt.Printf("callback received error: %v\n", err) + } + return + } + // Marshal the event to JSON and print + buf, err := json.Marshal(e) + if err != nil { + fmt.Printf("callback was unable to marshal event: %v\n", err) + return + } + fmt.Printf("%v\n", string(buf)) +} + +func main() { + s, err := libaudit.NewNetlinkConnection() + if err != nil { + fmt.Fprintf(os.Stderr, "NetNetlinkConnection: %v\n", err) + os.Exit(1) + } + + if len(os.Args) != 2 { + fmt.Printf("usage: %v path_to_rules.json\n", os.Args[0]) + os.Exit(0) + } + + err = libaudit.AuditSetEnabled(s, true) + if err != nil { + fmt.Fprintf(os.Stderr, "AuditSetEnabled: %v\n", err) + os.Exit(1) + } + + err = libaudit.AuditSetPID(s, os.Getpid()) + if err != nil { + fmt.Fprintf(os.Stderr, "AuditSetPid: %v\n", err) + os.Exit(1) + } + err = libaudit.AuditSetRateLimit(s, 1000) + if err != nil { + fmt.Fprintf(os.Stderr, "AuditSetRateLimit: %v\n", err) + os.Exit(1) + } + err = libaudit.AuditSetBacklogLimit(s, 250) + if err != nil { + fmt.Fprintf(os.Stderr, "AuditSetBacklogLimit: %v\n", err) + os.Exit(1) + } + + var ar libaudit.AuditRules + buf, err := ioutil.ReadFile(os.Args[1]) + if err != nil { + fmt.Fprintf(os.Stderr, "ReadFile: %v\n", err) + os.Exit(1) + } + // Make sure we can unmarshal the rules JSON to validate it is the correct + // format + err = json.Unmarshal(buf, &ar) + if err != nil { + fmt.Fprintf(os.Stderr, "Unmarshaling rules JSON: %v\n", err) + os.Exit(1) + } + + // Remove current rule set and send rules to the kernel + err = libaudit.DeleteAllRules(s) + if err != nil { + fmt.Fprintf(os.Stderr, "DeleteAllRules: %v\n", err) + os.Exit(1) + } + warnings, err := libaudit.SetRules(s, buf) + if err != nil { + fmt.Fprintf(os.Stderr, "SetRules: %v\n", err) + os.Exit(1) + } + // Print any warnings we got back but still continue + for _, x := range warnings { + fmt.Fprintf(os.Stderr, "ruleset warning: %v\n", x) + } + + doneCh := make(chan bool, 1) + libaudit.GetAuditMessages(s, auditProc, &doneCh) +} diff --git a/vendor/github.com/mozilla/libaudit-go/buffer.go b/vendor/github.com/mozilla/libaudit-go/buffer.go new file mode 100644 index 00000000..117d7182 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/buffer.go @@ -0,0 +1,58 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package libaudit + +import ( + "strconv" +) + +var bufferMap map[uint64][]*AuditEvent + +// bufferEvent buffers an incoming audit event which contains partial record informatioa. +func bufferEvent(a *AuditEvent) { + if bufferMap == nil { + bufferMap = make(map[uint64][]*AuditEvent) + } + + serial, err := strconv.ParseUint(a.Serial, 10, 64) + if err != nil { + return + } + if _, ok := bufferMap[serial]; !ok { + bufferMap[serial] = make([]*AuditEvent, 5) + } + bufferMap[serial] = append(bufferMap[serial], a) +} + +// bufferGet returns the complete audit event from the buffer, given the AUDIT_EOE event a. +func bufferGet(a *AuditEvent) *AuditEvent { + serial, err := strconv.ParseUint(a.Serial, 10, 64) + if err != nil { + return nil + } + + var ( + bm []*AuditEvent + ok bool + ) + if bm, ok = bufferMap[serial]; !ok { + return nil + } + rlen := len(a.Raw) + for i := range bm { + if bm[i] == nil { + continue + } + for k, v := range bm[i].Data { + a.Data[k] = v + } + if len(bm[i].Raw) > rlen { + a.Raw += " " + bm[i].Raw[rlen:] + } + } + + delete(bufferMap, serial) + return a +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/access_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/access_tab.go new file mode 100644 index 00000000..23b62165 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/access_tab.go @@ -0,0 +1,7 @@ +package headers + +var AccessLookUp = map[int]string{ + 1: "X_OK", + 2: "W_OK", + 4: "R_OK", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/audit_x64.go b/vendor/github.com/mozilla/libaudit-go/headers/audit_x64.go new file mode 100644 index 00000000..ebfa7cf7 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/audit_x64.go @@ -0,0 +1,333 @@ +package headers + +// SysMapX64 is a mapping between x64 syscall names and their integer values +// The list is taken from x86_64_table.h of auditd library +var SysMapX64 = map[string]int{ + "read": 0, + "write": 1, + "open": 2, + "close": 3, + "stat": 4, + "fstat": 5, + "lstat": 6, + "poll": 7, + "lseek": 8, + "mmap": 9, + "mprotect": 10, + "munmap": 11, + "brk": 12, + "rt_sigaction": 13, + "rt_sigprocmask": 14, + "rt_sigreturn": 15, + "ioctl": 16, + "pread64": 17, + "pwrite64": 18, + "readv": 19, + "writev": 20, + "access": 21, + "pipe": 22, + "select": 23, + "sched_yield": 24, + "mremap": 25, + "msync": 26, + "mincore": 27, + "madvise": 28, + "shmget": 29, + "shmat": 30, + "shmctl": 31, + "dup": 32, + "dup2": 33, + "pause": 34, + "nanosleep": 35, + "getitimer": 36, + "alarm": 37, + "setitimer": 38, + "getpid": 39, + "sendfile": 40, + "socket": 41, + "connect": 42, + "accept": 43, + "sendto": 44, + "recvfrom": 45, + "sendmsg": 46, + "recvmsg": 47, + "shutdown": 48, + "bind": 49, + "listen": 50, + "getsockname": 51, + "getpeername": 52, + "socketpair": 53, + "setsockopt": 54, + "getsockopt": 55, + "clone": 56, + "fork": 57, + "vfork": 58, + "execve": 59, + "exit": 60, + "wait4": 61, + "kill": 62, + "uname": 63, + "semget": 64, + "semop": 65, + "semctl": 66, + "shmdt": 67, + "msgget": 68, + "msgsnd": 69, + "msgrcv": 70, + "msgctl": 71, + "fcntl": 72, + "flock": 73, + "fsync": 74, + "fdatasync": 75, + "truncate": 76, + "ftruncate": 77, + "getdents": 78, + "getcwd": 79, + "chdir": 80, + "fchdir": 81, + "rename": 82, + "mkdir": 83, + "rmdir": 84, + "creat": 85, + "link": 86, + "unlink": 87, + "symlink": 88, + "readlink": 89, + "chmod": 90, + "fchmod": 91, + "chown": 92, + "fchown": 93, + "lchown": 94, + "umask": 95, + "gettimeofday": 96, + "getrlimit": 97, + "getrusage": 98, + "sysinfo": 99, + "times": 100, + "ptrace": 101, + "getuid": 102, + "syslog": 103, + "getgid": 104, + "setuid": 105, + "setgid": 106, + "geteuid": 107, + "getegid": 108, + "setpgid": 109, + "getppid": 110, + "getpgrp": 111, + "setsid": 112, + "setreuid": 113, + "setregid": 114, + "getgroups": 115, + "setgroups": 116, + "setresuid": 117, + "getresuid": 118, + "setresgid": 119, + "getresgid": 120, + "getpgid": 121, + "setfsuid": 122, + "setfsgid": 123, + "getsid": 124, + "capget": 125, + "capset": 126, + "rt_sigpending": 127, + "rt_sigtimedwait": 128, + "rt_sigqueueinfo": 129, + "rt_sigsuspend": 130, + "sigaltstack": 131, + "utime": 132, + "mknod": 133, + "uselib": 134, + "personality": 135, + "ustat": 136, + "statfs": 137, + "fstatfs": 138, + "sysfs": 139, + "getpriority": 140, + "setpriority": 141, + "sched_setparam": 142, + "sched_getparam": 143, + "sched_setscheduler": 144, + "sched_getscheduler": 145, + "sched_get_priority_max": 146, + "sched_get_priority_min": 147, + "sched_rr_get_interval": 148, + "mlock": 149, + "munlock": 150, + "mlockall": 151, + "munlockall": 152, + "vhangup": 153, + "modify_ldt": 154, + "pivot_root": 155, + "_sysctl": 156, + "prctl": 157, + "arch_prctl": 158, + "adjtimex": 159, + "setrlimit": 160, + "chroot": 161, + "sync": 162, + "acct": 163, + "settimeofday": 164, + "mount": 165, + "umount2": 166, + "swapon": 167, + "swapoff": 168, + "reboot": 169, + "sethostname": 170, + "setdomainname": 171, + "iopl": 172, + "ioperm": 173, + "create_module": 174, + "init_module": 175, + "delete_module": 176, + "get_kernel_syms": 177, + "query_module": 178, + "quotactl": 179, + "nfsservctl": 180, + "getpmsg": 181, + "putpmsg": 182, + "afs_": 183, + "tuxcall": 184, + "security": 185, + "gettid": 186, + "readahead": 187, + "setxattr": 188, + "lsetxattr": 189, + "fsetxattr": 190, + "getxattr": 191, + "lgetxattr": 192, + "fgetxattr": 193, + "listxattr": 194, + "llistxattr": 195, + "flistxattr": 196, + "removexattr": 197, + "lremovexattr": 198, + "fremovexattr": 199, + "tkill": 200, + "time": 201, + "futex": 202, + "sched_setaffinity": 203, + "sched_getaffinity": 204, + "set_thread_area": 205, + "io_setup": 206, + "io_destroy": 207, + "io_getevents": 208, + "io_submit": 209, + "io_cancel": 210, + "get_thread_area": 211, + "lookup_dcookie": 212, + "epoll_create": 213, + "epoll_ctl_old": 214, + "epoll_wait_old": 215, + "remap_file_pages": 216, + "getdents64": 217, + "set_tid_address": 218, + "restart_": 219, + "semtimedop": 220, + "fadvise64": 221, + "timer_create": 222, + "timer_settime": 223, + "timer_gettime": 224, + "timer_getoverrun": 225, + "timer_delete": 226, + "clock_settime": 227, + "clock_gettime": 228, + "clock_getres": 229, + "clock_nanosleep": 230, + "exit_group": 231, + "epoll_wait": 232, + "epoll_ctl": 233, + "tgkill": 234, + "utimes": 235, + "vserver": 236, + "mbind": 237, + "set_mempolicy": 238, + "get_mempolicy": 239, + "mq_open": 240, + "mq_unlink": 241, + "mq_timedsend": 242, + "mq_timedreceive": 243, + "mq_notify": 244, + "mq_getsetattr": 245, + "kexec_load": 246, + "waitid": 247, + "add_key": 248, + "request_key": 249, + "keyctl": 250, + "ioprio_set": 251, + "ioprio_get": 252, + "inotify_init": 253, + "inotify_add_watch": 254, + "inotify_rm_watch": 255, + "migrate_pages": 256, + "openat": 257, + "mkdirat": 258, + "mknodat": 259, + "fchownat": 260, + "futimesat": 261, + "newfstatat": 262, + "unlinkat": 263, + "renameat": 264, + "linkat": 265, + "symlinkat": 266, + "readlinkat": 267, + "fchmodat": 268, + "faccessat": 269, + "pselect6": 270, + "ppoll": 271, + "unshare": 272, + "set_robust_list": 273, + "get_robust_list": 274, + "splice": 275, + "tee": 276, + "sync_file_range": 277, + "vmsplice": 278, + "move_pages": 279, + "utimensat": 280, + "epoll_pwait": 281, + "signalfd": 282, + "timerfd_create": 283, + "eventfd": 284, + "fallocate": 285, + "timerfd_settime": 286, + "timerfd_gettime": 287, + "accept4": 288, + "signalfd4": 289, + "eventfd2": 290, + "epoll_create1": 291, + "dup3": 292, + "pipe2": 293, + "inotify_init1": 294, + "preadv": 295, + "pwritev": 296, + "rt_tgsigqueueinfo": 297, + "perf_event_open": 298, + "recvmmsg": 299, + "fanotify_init": 300, + "fanotify_mark": 301, + "prlimit64": 302, + "name_to_handle_at": 303, + "open_by_handle_at": 304, + "clock_adjtime": 305, + "syncfs": 306, + "sendmmsg": 307, + "setns": 308, + "getcpu": 309, + "process_vm_readv": 310, + "process_vm_writev": 311, + "kcmp": 312, + "finit_module": 313, + "sched_setattr": 314, + "sched_getattr": 315, + "renameat2": 316, + "seccomp": 317, + "getrandom": 318, + "memfd_create": 319, + "kexec_file_load": 320, + "bpf": 321, + "execveat": 322, + "userfaultfd": 323, + "membarrier": 324, + "mlock2": 325, + "copy_file_range": 326, +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/audit_x64_i2s.go b/vendor/github.com/mozilla/libaudit-go/headers/audit_x64_i2s.go new file mode 100644 index 00000000..2e7b3361 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/audit_x64_i2s.go @@ -0,0 +1,333 @@ +package headers + +// ReverseSysMapX64 is a mapping between x64 syscall integer values and their names +// The list is taken from x86_64_table.h of auditd library +var ReverseSysMapX64 = map[string]string{ + "0": "read", + "1": "write", + "2": "open", + "3": "close", + "4": "stat", + "5": "fstat", + "6": "lstat", + "7": "poll", + "8": "lseek", + "9": "mmap", + "10": "mprotect", + "11": "munmap", + "12": "brk", + "13": "rt_sigaction", + "14": "rt_sigprocmask", + "15": "rt_sigreturn", + "16": "ioctl", + "17": "pread64", + "18": "pwrite64", + "19": "readv", + "20": "writev", + "21": "access", + "22": "pipe", + "23": "select", + "24": "sched_yield", + "25": "mremap", + "26": "msync", + "27": "mincore", + "28": "madvise", + "29": "shmget", + "30": "shmat", + "31": "shmctl", + "32": "dup", + "33": "dup2", + "34": "pause", + "35": "nanosleep", + "36": "getitimer", + "37": "alarm", + "38": "setitimer", + "39": "getpid", + "40": "sendfile", + "41": "socket", + "42": "connect", + "43": "accept", + "44": "sendto", + "45": "recvfrom", + "46": "sendmsg", + "47": "recvmsg", + "48": "shutdown", + "49": "bind", + "50": "listen", + "51": "getsockname", + "52": "getpeername", + "53": "socketpair", + "54": "setsockopt", + "55": "getsockopt", + "56": "clone", + "57": "fork", + "58": "vfork", + "59": "execve", + "60": "exit", + "61": "wait4", + "62": "kill", + "63": "uname", + "64": "semget", + "65": "semop", + "66": "semctl", + "67": "shmdt", + "68": "msgget", + "69": "msgsnd", + "70": "msgrcv", + "71": "msgctl", + "72": "fcntl", + "73": "flock", + "74": "fsync", + "75": "fdatasync", + "76": "truncate", + "77": "ftruncate", + "78": "getdents", + "79": "getcwd", + "80": "chdir", + "81": "fchdir", + "82": "rename", + "83": "mkdir", + "84": "rmdir", + "85": "creat", + "86": "link", + "87": "unlink", + "88": "symlink", + "89": "readlink", + "90": "chmod", + "91": "fchmod", + "92": "chown", + "93": "fchown", + "94": "lchown", + "95": "umask", + "96": "gettimeofday", + "97": "getrlimit", + "98": "getrusage", + "99": "sysinfo", + "100": "times", + "101": "ptrace", + "102": "getuid", + "103": "syslog", + "104": "getgid", + "105": "setuid", + "106": "setgid", + "107": "geteuid", + "108": "getegid", + "109": "setpgid", + "110": "getppid", + "111": "getpgrp", + "112": "setsid", + "113": "setreuid", + "114": "setregid", + "115": "getgroups", + "116": "setgroups", + "117": "setresuid", + "118": "getresuid", + "119": "setresgid", + "120": "getresgid", + "121": "getpgid", + "122": "setfsuid", + "123": "setfsgid", + "124": "getsid", + "125": "capget", + "126": "capset", + "127": "rt_sigpending", + "128": "rt_sigtimedwait", + "129": "rt_sigqueueinfo", + "130": "rt_sigsuspend", + "131": "sigaltstack", + "132": "utime", + "133": "mknod", + "134": "uselib", + "135": "personality", + "136": "ustat", + "137": "statfs", + "138": "fstatfs", + "139": "sysfs", + "140": "getpriority", + "141": "setpriority", + "142": "sched_setparam", + "143": "sched_getparam", + "144": "sched_setscheduler", + "145": "sched_getscheduler", + "146": "sched_get_priority_max", + "147": "sched_get_priority_min", + "148": "sched_rr_get_interval", + "149": "mlock", + "150": "munlock", + "151": "mlockall", + "152": "munlockall", + "153": "vhangup", + "154": "modify_ldt", + "155": "pivot_root", + "156": "_sysctl", + "157": "prctl", + "158": "arch_prctl", + "159": "adjtimex", + "160": "setrlimit", + "161": "chroot", + "162": "sync", + "163": "acct", + "164": "settimeofday", + "165": "mount", + "166": "umount2", + "167": "swapon", + "168": "swapoff", + "169": "reboot", + "170": "sethostname", + "171": "setdomainname", + "172": "iopl", + "173": "ioperm", + "174": "create_module", + "175": "init_module", + "176": "delete_module", + "177": "get_kernel_syms", + "178": "query_module", + "179": "quotactl", + "180": "nfsservctl", + "181": "getpmsg", + "182": "putpmsg", + "183": "afs_", + "184": "tuxcall", + "185": "security", + "186": "gettid", + "187": "readahead", + "188": "setxattr", + "189": "lsetxattr", + "190": "fsetxattr", + "191": "getxattr", + "192": "lgetxattr", + "193": "fgetxattr", + "194": "listxattr", + "195": "llistxattr", + "196": "flistxattr", + "197": "removexattr", + "198": "lremovexattr", + "199": "fremovexattr", + "200": "tkill", + "201": "time", + "202": "futex", + "203": "sched_setaffinity", + "204": "sched_getaffinity", + "205": "set_thread_area", + "206": "io_setup", + "207": "io_destroy", + "208": "io_getevents", + "209": "io_submit", + "210": "io_cancel", + "211": "get_thread_area", + "212": "lookup_dcookie", + "213": "epoll_create", + "214": "epoll_ctl_old", + "215": "epoll_wait_old", + "216": "remap_file_pages", + "217": "getdents64", + "218": "set_tid_address", + "219": "restart_", + "220": "semtimedop", + "221": "fadvise64", + "222": "timer_create", + "223": "timer_settime", + "224": "timer_gettime", + "225": "timer_getoverrun", + "226": "timer_delete", + "227": "clock_settime", + "228": "clock_gettime", + "229": "clock_getres", + "230": "clock_nanosleep", + "231": "exit_group", + "232": "epoll_wait", + "233": "epoll_ctl", + "234": "tgkill", + "235": "utimes", + "236": "vserver", + "237": "mbind", + "238": "set_mempolicy", + "239": "get_mempolicy", + "240": "mq_open", + "241": "mq_unlink", + "242": "mq_timedsend", + "243": "mq_timedreceive", + "244": "mq_notify", + "245": "mq_getsetattr", + "246": "kexec_load", + "247": "waitid", + "248": "add_key", + "249": "request_key", + "250": "keyctl", + "251": "ioprio_set", + "252": "ioprio_get", + "253": "inotify_init", + "254": "inotify_add_watch", + "255": "inotify_rm_watch", + "256": "migrate_pages", + "257": "openat", + "258": "mkdirat", + "259": "mknodat", + "260": "fchownat", + "261": "futimesat", + "262": "newfstatat", + "263": "unlinkat", + "264": "renameat", + "265": "linkat", + "266": "symlinkat", + "267": "readlinkat", + "268": "fchmodat", + "269": "faccessat", + "270": "pselect6", + "271": "ppoll", + "272": "unshare", + "273": "set_robust_list", + "274": "get_robust_list", + "275": "splice", + "276": "tee", + "277": "sync_file_range", + "278": "vmsplice", + "279": "move_pages", + "280": "utimensat", + "281": "epoll_pwait", + "282": "signalfd", + "283": "timerfd_create", + "284": "eventfd", + "285": "fallocate", + "286": "timerfd_settime", + "287": "timerfd_gettime", + "288": "accept4", + "289": "signalfd4", + "290": "eventfd2", + "291": "epoll_create1", + "292": "dup3", + "293": "pipe2", + "294": "inotify_init1", + "295": "preadv", + "296": "pwritev", + "297": "rt_tgsigqueueinfo", + "298": "perf_event_open", + "299": "recvmmsg", + "300": "fanotify_init", + "301": "fanotify_mark", + "302": "prlimit64", + "303": "name_to_handle_at", + "304": "open_by_handle_at", + "305": "clock_adjtime", + "306": "syncfs", + "307": "sendmmsg", + "308": "setns", + "309": "getcpu", + "310": "process_vm_readv", + "311": "process_vm_writev", + "312": "kcmp", + "313": "finit_module", + "314": "sched_setattr", + "315": "sched_getattr", + "316": "renameat2", + "317": "seccomp", + "318": "getrandom", + "319": "memfd_create", + "320": "kexec_file_load", + "321": "bpf", + "322": "execveat", + "323": "userfaultfd", + "324": "membarrier", + "325": "mlock2", + "326": "copy_file_range", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/cap_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/cap_tab.go new file mode 100644 index 00000000..f8a29ec7 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/cap_tab.go @@ -0,0 +1,43 @@ +package headers + +//Location: include/uapi/linux/capability.h +var CapabLookup = map[int]string{ + 0: "chown", + 1: "dac_override", + 2: "dac_read_search", + 3: "fowner", + 4: "fsetid", + 5: "kill", + 6: "setgid", + 7: "setuid", + 8: "setpcap", + 9: "linux_immutable", + 10: "net_bind_service", + 11: "net_broadcast", + 12: "net_admin", + 13: "net_raw", + 14: "ipc_lock", + 15: "ipc_owner", + 16: "sys_module", + 17: "sys_rawio", + 18: "sys_chroot", + 19: "sys_ptrace", + 20: "sys_pacct", + 21: "sys_admin", + 22: "sys_boot", + 23: "sys_nice", + 24: "sys_resource", + 25: "sys_time", + 26: "sys_tty_config", + 27: "mknod", + 28: "lease", + 29: "audit_write", + 30: "audit_control", + 31: "setfcap", + 32: "mac_override", + 33: "mac_admin", + 34: "syslog", + 35: "wake_alarm", + 36: "block_suspend", + 37: "audit_read", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/clock_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/clock_tab.go new file mode 100644 index 00000000..445f497e --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/clock_tab.go @@ -0,0 +1,17 @@ +package headers + +//Location: include/uapi/linux/time.h +var ClockLookup = map[int]string{ + 0: "CLOCK_REALTIME", + 1: "CLOCK_MONOTONIC", + 2: "CLOCK_PROCESS_CPUTIME_ID", + 3: "CLOCK_THREAD_CPUTIME_ID", + 4: "CLOCK_MONOTONIC_RAW", + 5: "CLOCK_REALTIME_COARSE", + 6: "CLOCK_MONOTONIC_COARSE", + 7: "CLOCK_BOOTTIME", + 8: "CLOCK_REALTIME_ALARM", + 9: "CLOCK_BOOTTIME_ALARM", + 10: "CLOCK_SGI_CYCLE", + 11: "CLOCK_TAI", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/cloneflag_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/cloneflag_tab.go new file mode 100644 index 00000000..005679a3 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/cloneflag_tab.go @@ -0,0 +1,28 @@ +package headers + +// Location: include/uapi/linux/sched.h +var CloneLookUp = map[int]string{ + 0x00000100: "CLONE_VM", + 0x00000200: "CLONE_FS", + 0x00000400: "CLONE_FILES", + 0x00000800: "CLONE_SIGHAND", + 0x00002000: "CLONE_PTRACE", + 0x00004000: "CLONE_VFORK", + 0x00008000: "CLONE_PARENT", + 0x00010000: "CLONE_THREAD", + 0x00020000: "CLONE_NEWNS", + 0x00040000: "CLONE_SYSVSEM", + 0x00080000: "CLONE_SETTLS", + 0x00100000: "CLONE_PARENT_SETTID", + 0x00200000: "CLONE_CHILD_CLEARTID", + 0x00400000: "CLONE_DETACHED", + 0x00800000: "CLONE_UNTRACED", + 0x01000000: "CLONE_CHILD_SETTID", + 0x02000000: "CLONE_STOPPED", + 0x04000000: "CLONE_NEWUTS", + 0x08000000: "CLONE_NEWIPC", + 0x10000000: "CLONE_NEWUSER", + 0x20000000: "CLONE_NEWPID", + 0x40000000: "CLONE_NEWNET", + 0x80000000: "CLONE_IO", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/epollctl_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/epollctl_tab.go new file mode 100644 index 00000000..52f134c9 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/epollctl_tab.go @@ -0,0 +1,8 @@ +package headers + +// Location: include/uapi/linux/eventpoll.h +var EpollLookup = map[int]string{ + 1: "EPOLL_CTL_ADD", + 2: "EPOLL_CTL_DEL", + 3: "EPOLL_CTL_MOD", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/fcntl_cmd_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/fcntl_cmd_tab.go new file mode 100644 index 00000000..5965da76 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/fcntl_cmd_tab.go @@ -0,0 +1,33 @@ +package headers + +// Location: include/uapi/asm-generic/fcntl.h <17 +// include/uapi/linux/fcntl.h >= 1024 +var FcntlLookup = map[int]string{ + 0: "F_DUPFD", + 1: "F_GETFD", + 2: "F_SETFD", + 3: "F_GETFL", + 4: "F_SETFL", + 5: "F_GETLK", + 6: "F_SETLK", + 7: "F_SETLKW", + 8: "F_SETOWN", + 9: "F_GETOWN", + 10: "F_SETSIG", + 11: "F_GETSIG", + 12: "F_GETLK64", + 13: "F_SETLK64", + 14: "F_SETLKW64", + 15: "F_SETOWN_EX", + 16: "F_GETOWN_EX", + 17: "F_GETOWNER_UIDS", + 1024: "F_SETLEASE", + 1025: "F_GETLEASE", + 1026: "F_NOTIFY", + 1029: "F_CANCELLK", + 1030: "F_DUPFD_CLOEXEC", + 1031: "F_SETPIPE_SZ", + 1032: "F_GETPIPE_SZ", + 1033: "F_ADD_SEALS", + 1034: "F_GET_SEALS", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/field_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/field_tab.go new file mode 100644 index 00000000..2a240c9f --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/field_tab.go @@ -0,0 +1,46 @@ +package headers + +var FieldMap = map[string]int{ + "pid": 0, + "uid": 1, + "euid": 2, + "suid": 3, + "fsuid": 4, + "gid": 5, + "egid": 6, + "sgid": 7, + "fsgid": 8, + "auid": 9, + "loginuid": 9, + "pers": 10, + "arch": 11, + "msgtype": 12, + "subj_user": 13, + "subj_role": 14, + "subj_type": 15, + "subj_sen": 16, + "subj_clr": 17, + "ppid": 18, + "obj_user": 19, + "obj_role": 20, + "obj_type": 21, + "obj_lev_low": 22, + "obj_lev_high": 23, + "devmajor": 100, + "devminor": 101, + "inode": 102, + "exit": 103, + "success": 104, + "path": 105, + "perm": 106, + "dir": 107, + "filetype": 108, + "obj_uid": 109, + "obj_gid": 110, + "field_compare": 111, + "a0": 200, + "a1": 201, + "a2": 202, + "a3": 203, + "key": 210, +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/ftype_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/ftype_tab.go new file mode 100644 index 00000000..e320c8ad --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/ftype_tab.go @@ -0,0 +1,11 @@ +package headers + +var FtypeTab = map[string]int{ + "block": 24576, + "character": 8192, + "dir": 16384, + "fifo": 4096, + "file": 32768, + "link": 40960, + "socket": 49152, +} \ No newline at end of file diff --git a/vendor/github.com/mozilla/libaudit-go/headers/icmptype_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/icmptype_tab.go new file mode 100644 index 00000000..34617275 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/icmptype_tab.go @@ -0,0 +1,18 @@ +package headers + +// Location: include/uapi/linux/icmp.h +var IcmpLookup = map[int]string{ + 0: "echo-reply", + 3: "destination-unreachable", + 4: "source-quench", + 5: "redirect", + 8: "echo", + 11: "time-exceeded", + 12: "parameter-problem", + 13: "timestamp-request", + 14: "timestamp-reply", + 15: "info-request", + 16: "info-reply", + 17: "address-mask-request", + 18: "address-mask-reply", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/ioctlreq_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/ioctlreq_tab.go new file mode 100644 index 00000000..6023d549 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/ioctlreq_tab.go @@ -0,0 +1,39 @@ +package headers + +// Location: include/uapi/linux/kd.h +// include/uapi/linux/cdrom.h +// include/uapi/asm-generic/ioctls.h +// include/uapi/drm/drm.h + +var IoctlLookup = map[int]string{ + 0x4B3A: "KDSETMODE", + 0x4B3B: "KDGETMODE", + 0x5309: "CDROMEJECT", + 0x530F: "CDROMEJECT_SW", + 0x5311: "CDROM_GET_UPC", + 0x5316: "CDROMSEEK", + 0x5401: "TCGETS", + 0x5402: "TCSETS", + 0x5403: "TCSETSW", + 0x5404: "TCSETSF", + 0x5409: "TCSBRK", + 0x540B: "TCFLSH", + 0x540E: "TIOCSCTTY", + 0x540F: "TIOCGPGRP", + 0x5410: "TIOCSPGRP", + 0x5413: "TIOCGWINSZ", + 0x5414: "TIOCSWINSZ", + 0x541B: "TIOCINQ", + 0x5421: "FIONBIO", + 0x8901: "FIOSETOWN", + 0x8903: "FIOGETOWN", + 0x8910: "SIOCGIFNAME", + 0x8927: "SIOCGIFHWADDR", + 0x8933: "SIOCGIFINDEX", + 0x89a2: "SIOCBRADDIF", + 0x40045431: "TIOCSPTLCK", + 0x80045430: "TIOCGPTN", + 0x80045431: "TIOCSPTLCK", + 0xC01C64A3: "DRM_IOCTL_MODE_CURSOR", + 0xC01864B0: "DRM_IOCTL_MODE_PAGE_FLIP", + 0xC01864B1: "DRM_IOCTL_MODE_DIRTYFB"} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/ip6optname_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/ip6optname_tab.go new file mode 100644 index 00000000..1694d0aa --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/ip6optname_tab.go @@ -0,0 +1,70 @@ +package headers + +// Location: include/uapi/linux/in6.h +// include/uapi/linux/netfilter_ipv6/ip6_tables.h +// include/uapi/linux/mroute6.h + +var Ip6OptLookup = map[int]string{ + 1: "IPV6_ADDRFORM", + 2: "IPV6_2292PKTINFO", + 3: "IPV6_2292HOPOPTS", + 4: "IPV6_2292DSTOPTS", + 5: "IPV6_2292RTHDR", + 6: "IPV6_2292PKTOPTIONS", + 7: "IPV6_CHECKSUM", + 8: "IPV6_2292HOPLIMIT", + 9: "IPV6_NEXTHOP", + 10: "IPV6_AUTHHDR", + 11: "IPV6_FLOWINFO", + 16: "IPV6_UNICAST_HOPS", + 17: "IPV6_MULTICAST_IF", + 18: "IPV6_MULTICAST_HOPS", + 19: "IPV6_MULTICAST_LOOP", + 20: "IPV6_ADD_MEMBERSHIP", + 21: "IPV6_DROP_MEMBERSHIP", + 22: "IPV6_ROUTER_ALERT", + 23: "IPV6_MTU_DISCOVER", + 24: "IPV6_MTU", + 25: "IPV6_RECVERR", + 26: "IPV6_V6ONLY", + 27: "IPV6_JOIN_ANYCAST", + 28: "IPV6_LEAVE_ANYCAST", + 32: "IPV6_FLOWLABEL_MGR", + 33: "IPV6_FLOWINFO_SEND", + 34: "IPV6_IPSEC_POLICY", + 35: "IPV6_XFRM_POLICY", + 42: "MCAST_JOIN_GROUP", + 43: "MCAST_BLOCK_SOURCE", + 44: "MCAST_UNBLOCK_SOURCE", + 45: "MCAST_LEAVE_GROUP", + 46: "MCAST_JOIN_SOURCE_GROUP", + 47: "MCAST_LEAVE_SOURCE_GROUP", + 48: "MCAST_MSFILTER", + 49: "IPV6_RECVPKTINFO", + 50: "IPV6_PKTINFO", + 51: "IPV6_RECVHOPLIMIT", + 52: "IPV6_HOPLIMIT", + 53: "IPV6_RECVHOPOPTS", + 54: "IPV6_HOPOPTS", + 55: "IPV6_RTHDRDSTOPTS", + 56: "IPV6_RECVRTHDR", + 57: "IPV6_RTHDR", + 58: "IPV6_RECVDSTOPTS", + 59: "IPV6_DSTOPTS", + 60: "IPV6_RECVPATHMTU", + 61: "IPV6_PATHMTU", + 62: "IPV6_DONTFRAG", + 63: "IPV6_USE_MIN_MTU", + 64: "IP6T_SO_SET_REPLACE", + 65: "IP6T_SO_SET_ADD_COUNTERS", + 66: "IPV6_RECVTCLASS", + 67: "IPV6_TCLASS", + 68: "IP6T_SO_GET_REVISION_MATCH", + 69: "IP6T_SO_GET_REVISION_TARGET", + 72: "IPV6_ADDR_PREFERENCES", + 73: "IPV6_MINHOPCOUNT", + 74: "IPV6_ORIGDSTADDR", + 75: "IPV6_TRANSPARENT", + 76: "IPV6_UNICAST_IF", + 80: "IP6T_SO_ORIGINAL_DST", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/ipc_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/ipc_tab.go new file mode 100644 index 00000000..cd18ddb1 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/ipc_tab.go @@ -0,0 +1,19 @@ +package headers + +import "syscall" + +// Location: include/uapi/linux/ipc.h +var IpccallLookup = map[int]string{ + syscall.SYS_SEMOP: "semop", + syscall.SYS_SEMGET: "semget", + syscall.SYS_SEMCTL: "semctl", + 4: "semtimedop", + syscall.SYS_MSGSND: "msgsnd", + syscall.SYS_MSGRCV: "msgrcv", + syscall.SYS_MSGGET: "msgget", + syscall.SYS_MSGCTL: "msgctl", + syscall.SYS_SHMAT: "shmat", + syscall.SYS_SHMDT: "shmdt", + syscall.SYS_SHMGET: "shmget", + syscall.SYS_SHMCTL: "shmctl", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/ipoptname_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/ipoptname_tab.go new file mode 100644 index 00000000..440c76f3 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/ipoptname_tab.go @@ -0,0 +1,50 @@ +package headers + +// Location: include/uapi/linux/in.h +// include/uapi/linux/netfilter_ipv4/ip_tables.h +var IpOptLookup = map[int]string{ + 1: "IP_TOS", + 2: "IP_TTL", + 3: "IP_HDRINCL", + 4: "IP_OPTIONS", + 5: "IP_ROUTER_ALERT", + 6: "IP_RECVOPTS", + 7: "IP_RETOPTS", + 8: "IP_PKTINFO", + 9: "IP_PKTOPTIONS", + 10: "IP_MTU_DISCOVER", + 11: "IP_RECVERR", + 12: "IP_RECVTTL", + 14: "IP_MTU", + 15: "IP_FREEBIND", + 16: "IP_IPSEC_POLICY", + 17: "IP_XFRM_POLICY", + 18: "IP_PASSSEC", + 19: "IP_TRANSPARENT", + 20: "IP_ORIGDSTADDR", + 21: "IP_MINTTL", + 22: "IP_NODEFRAG", + 23: "IP_CHECKSUM", + 32: "IP_MULTICAST_IF", + 33: "IP_MULTICAST_TTL", + 34: "IP_MULTICAST_LOOP", + 35: "IP_ADD_MEMBERSHIP", + 36: "IP_DROP_MEMBERSHIP", + 37: "IP_UNBLOCK_SOURCE", + 38: "IP_BLOCK_SOURCE", + 39: "IP_ADD_SOURCE_MEMBERSHIP", + 40: "IP_DROP_SOURCE_MEMBERSHIP", + 41: "IP_MSFILTER", + 42: "MCAST_JOIN_GROUP", + 43: "MCAST_BLOCK_SOURCE", + 44: "MCAST_UNBLOCK_SOURCE", + 45: "MCAST_LEAVE_GROUP", + 46: "MCAST_JOIN_SOURCE_GROUP", + 47: "MCAST_LEAVE_SOURCE_GROUP", + 48: "MCAST_MSFILTER", + 49: "IP_MULTICAST_ALL", + 50: "IP_UNICAST_IF", + 64: "IPT_SO_SET_REPLACE", + 65: "IPT_SO_SET_ADD_COUNTERS", + 66: "IPT_SO_GET_REVISION_TARGET", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/mmap_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/mmap_tab.go new file mode 100644 index 00000000..ccf064a5 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/mmap_tab.go @@ -0,0 +1,20 @@ +package headers + +// Location: include/uapi/asm-generic/mman.h >0x100 +// include/uapi/asm-generic/mman-common.h < 0x100 +var MmapLookUp = map[int]string{ + 0x00001: "MAP_SHARED", + 0x00002: "MAP_PRIVATE", + 0x00010: "MAP_FIXED", + 0x00020: "MAP_ANONYMOUS", + 0x00040: "MAP_32BIT", + 0x00100: "MAP_GROWSDOWN", + 0x00800: "MAP_DENYWRITE", + 0x01000: "MAP_EXECUTABLE", + 0x02000: "MAP_LOCKED", + 0x04000: "MAP_NORESERVE", + 0x08000: "MAP_POPULATE", + 0x10000: "MAP_NONBLOCK", + 0x20000: "MAP_STACK", + 0x40000: "MAP_HUGETLB", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/mount_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/mount_tab.go new file mode 100644 index 00000000..c5bbd545 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/mount_tab.go @@ -0,0 +1,36 @@ +package headers + +import "syscall" + +// Location: include/uapi/linux/fs.h +// when updating look at printMount +var MountLookUp = map[int]string{ + syscall.MS_RDONLY: "MS_RDONLY", + syscall.MS_NOSUID: "MS_NOSUID", + syscall.MS_NODEV: "MS_NODEV", + syscall.MS_NOEXEC: "MS_NOEXEC", + syscall.MS_SYNCHRONOUS: "MS_SYNCHRONOUS", + syscall.MS_REMOUNT: "MS_REMOUNT", + syscall.MS_MANDLOCK: "MS_MANDLOCK", + syscall.MS_DIRSYNC: "MS_DIRSYNC", + syscall.MS_NOATIME: "MS_NOATIME", + syscall.MS_NODIRATIME: "MS_NODIRATIME", + syscall.MS_BIND: "MS_BIND", + syscall.MS_MOVE: "MS_MOVE", + syscall.MS_REC: "MS_REC", + syscall.MS_SILENT: "MS_SILENT", + syscall.MS_POSIXACL: "MS_POSIXACL", + syscall.MS_UNBINDABLE: "MS_UNBINDABLE", + syscall.MS_PRIVATE: "MS_PRIVATE", + syscall.MS_SLAVE: "MS_SLAVE", + syscall.MS_SHARED: "MS_SHARED", + syscall.MS_RELATIME: "MS_RELATIME", + syscall.MS_KERNMOUNT: "MS_KERNMOUNT", + syscall.MS_I_VERSION: "MS_I_VERSION", + 1 << 24: "MS_STRICTATIME", + 1 << 27: "MS_SNAP_STABLE", + 1 << 28: "MS_NOSEC", + 1 << 29: "MS_BORN", + syscall.MS_ACTIVE: "MS_ACTIVE", + syscall.MS_NOUSER: "MS_NOUSER", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/nfproto_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/nfproto_tab.go new file mode 100644 index 00000000..381fd04b --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/nfproto_tab.go @@ -0,0 +1,12 @@ +package headers + +//Location: include/uapi/linux/netfilter.h +var NfProtoLookup = map[int]string{ + 0: "unspecified", + 1: "inet", + 2: "ipv4", + 3: "arp", + 7: "bridge", + 10: "ipv6", + 12: "decnet", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/pktoptname_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/pktoptname_tab.go new file mode 100644 index 00000000..df410c53 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/pktoptname_tab.go @@ -0,0 +1,24 @@ +package headers + +// Location: include/uapi/linux/if_packet.h +var PktOptLookup = map[int]string{ + 1: "PACKET_ADD_MEMBERSHIP", + 2: "PACKET_DROP_MEMBERSHIP", + 3: "PACKET_RECV_OUTPUT", + 5: "PACKET_RX_RING", + 6: "PACKET_STATISTICS", + 7: "PACKET_COPY_THRESH", + 8: "PACKET_AUXDATA", + 9: "PACKET_ORIGDEV", + 10: "PACKET_VERSION", + 11: "PACKET_HDRLEN", + 12: "PACKET_RESERVE", + 13: "PACKET_TX_RING", + 14: "PACKET_LOSS", + 15: "PACKET_VNET_HDR", + 16: "PACKET_TX_TIMESTAMP", + 17: "PACKET_TIMESTAMP", + 18: "PACKET_FANOUT", + 19: "PACKET_TX_HAS_OFF", + 20: "PACKET_QDISC_BYPASS", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/prctl_opt_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/prctl_opt_tab.go new file mode 100644 index 00000000..9cd052d1 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/prctl_opt_tab.go @@ -0,0 +1,51 @@ +package headers + +// Location: include/uapi/linux/prctl.h + +var PrctlLookup = map[int]string{ + 1: "PR_SET_PDEATHSIG", + 2: "PR_GET_PDEATHSIG", + 3: "PR_GET_DUMPABLE", + 4: "PR_SET_DUMPABLE", + 5: "PR_GET_UNALIGN", + 6: "PR_SET_UNALIGN", + 7: "PR_GET_KEEPCAPS", + 8: "PR_SET_KEEPCAPS", + 9: "PR_GET_FPEMU", + 10: "PR_SET_FPEMU", + 11: "PR_GET_FPEXC", + 12: "PR_SET_FPEXC", + 13: "PR_GET_TIMING", + 14: "PR_SET_TIMING", + 15: "PR_SET_NAME", + 16: "PR_GET_NAME", + 19: "PR_GET_ENDIAN", + 20: "PR_SET_ENDIAN", + 21: "PR_GET_SECCOMP", + 22: "PR_SET_SECCOMP", + 23: "PR_CAPBSET_READ", + 24: "PR_CAPBSET_DROP", + 25: "PR_GET_TSC", + 26: "PR_SET_TSC", + 27: "PR_GET_SECUREBITS", + 28: "PR_SET_SECUREBITS", + 29: "PR_SET_TIMERSLACK", + 30: "PR_GET_TIMERSLACK", + 31: "PR_TASK_PERF_EVENTS_DISABLE", + 32: "PR_TASK_PERF_EVENTS_ENABLE", + 33: "PR_MCE_KILL", + 34: "PR_MCE_KILL_GET", + 35: "PR_SET_MM", + 36: "PR_SET_CHILD_SUBREAPER", + 37: "PR_GET_CHILD_SUBREAPER", + 38: "PR_SET_NO_NEW_PRIVS", + 39: "PR_GET_NO_NEW_PRIVS", + 40: "PR_GET_TID_ADDRESS", + 41: "PR_SET_THP_DISABLE", + 42: "PR_GET_THP_DISABLE", + 43: "PR_MPX_ENABLE_MANAGEMENT", + 44: "PR_MPX_DISABLE_MANAGEMENT", + 45: "PR_SET_FP_MODE", + 46: "PR_GET_FP_MODE", + 47: "PR_CAP_AMBIENT", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/protocol_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/protocol_tab.go new file mode 100644 index 00000000..6a09df37 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/protocol_tab.go @@ -0,0 +1,10 @@ +// Location: include/uapi/asm-generic/mman-common.h + +package headers + +var ProtLookUp = map[int]string{ + 1: "PROT_READ", + 2: "PROT_WRITE", + 4: "PROT_EXEC", + 8: "PROT_SEM", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/ptrace_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/ptrace_tab.go new file mode 100644 index 00000000..322a5cc1 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/ptrace_tab.go @@ -0,0 +1,37 @@ +// Location: include/uapi/linux/ptrace.h + +package headers + +var PtraceLookup = map[int]string{ + 0: "PTRACE_TRACEME", + 1: "PTRACE_PEEKTEXT", + 2: "PTRACE_PEEKDATA", + 3: "PTRACE_PEEKUSER", + 4: "PTRACE_POKETEXT", + 5: "PTRACE_POKEDATA", + 6: "PTRACE_POKEUSER", + 7: "PTRACE_CONT", + 8: "PTRACE_KILL", + 9: "PTRACE_SINGLESTEP", + 12: "PTRACE_GETREGS", + 13: "PTRACE_SETREGS", + 14: "PTRACE_GETFPREGS", + 15: "PTRACE_SETFPREGS", + 16: "PTRACE_ATTACH", + 17: "PTRACE_DETACH", + 18: "PTRACE_GETFPXREGS", + 19: "PTRACE_SETFPXREGS", + 24: "PTRACE_SYSCALL", + 0x4200: "PTRACE_SETOPTIONS", + 0x4201: "PTRACE_GETEVENTMSG", + 0x4202: "PTRACE_GETSIGINFO", + 0x4203: "PTRACE_SETSIGINFO", + 0x4204: "PTRACE_GETREGSET", + 0x4205: "PTRACE_SETREGSET", + 0x4206: "PTRACE_SEIZE", + 0x4207: "PTRACE_INTERRUPT", + 0x4208: "PTRACE_LISTEN", + 0x4209: "PTRACE_PEEKSIGINFO", + 0x420a: "PTRACE_GETSIGMASK", + 0x420b: "PTRACE_SETSIGMASK", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/recv_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/recv_tab.go new file mode 100644 index 00000000..7e398e98 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/recv_tab.go @@ -0,0 +1,26 @@ +package headers + +// Location: include/linux/socket.h +var RecvLookUp = map[int]string{ + 0x00000001: "MSG_OOB", + 0x00000002: "MSG_PEEK", + 0x00000004: "MSG_DONTROUTE", + 0x00000008: "MSG_CTRUNC", + 0x00000010: "MSG_PROXY", + 0x00000020: "MSG_TRUNC", + 0x00000040: "MSG_DONTWAIT", + 0x00000080: "MSG_EOR", + 0x00000100: "MSG_WAITALL", + 0x00000200: "MSG_FIN", + 0x00000400: "MSG_SYN", + 0x00000800: "MSG_CONFIRM", + 0x00001000: "MSG_RST", + 0x00002000: "MSG_ERRQUEUE", + 0x00004000: "MSG_NOSIGNAL", + 0x00008000: "MSG_MORE", + 0x00010000: "MSG_WAITFORONE", + 0x00020000: "MSG_SENDPAGE_NOTLAST", + 0x20000000: "MSG_FASTOPEN", + 0x40000000: "MSG_CMSG_CLOEXEC", + 0x80000000: "MSG_CMSG_COMPAT", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/rlimit_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/rlimit_tab.go new file mode 100644 index 00000000..47896fe7 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/rlimit_tab.go @@ -0,0 +1,21 @@ +package headers + +// Location: include/uapi/asm-generic/resource.h +var RlimitLookup = map[int]string{ + 0: "RLIMIT_CPU", + 1: "RLIMIT_FSIZE", + 2: "RLIMIT_DATA", + 3: "RLIMIT_STACK", + 4: "RLIMIT_CORE", + 5: "RLIMIT_RSS", + 6: "RLIMIT_NPROC", + 7: "RLIMIT_NOFILE", + 8: "RLIMIT_MEMLOCK", + 9: "RLIMIT_AS", + 10: "RLIMIT_LOCKS", + 11: "RLIMIT_SIGPENDING", + 12: "RLIMIT_MSGQUEUE", + 13: "RLIMIT_NICE", + 14: "RLIMIT_RTPRIO", + 15: "RLIMIT_RTTIME", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/sched_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/sched_tab.go new file mode 100644 index 00000000..2f162c85 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/sched_tab.go @@ -0,0 +1,12 @@ +package headers + +// Location: include/uapi/linux/sched.h + +var SchedLookup = map[int]string{ + 0: "SCHED_OTHER", + 1: "SCHED_FIFO", + 2: "SCHED_RR", + 3: "SCHED_BATCH", + 5: "SCHED_IDLE", + 6: "SCHED_DEADLINE", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/seccomp_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/seccomp_tab.go new file mode 100644 index 00000000..27b42c32 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/seccomp_tab.go @@ -0,0 +1,10 @@ +package headers + +// Location: include/uapi/linux/seccomp.h +var SeccompCodeLookUp = map[int]string{ + 0x00000000: "kill", + 0x00030000: "trap", + 0x00050000: "errno", + 0x7ff00000: "trace", + 0x7fff0000: "allow", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/seek_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/seek_tab.go new file mode 100644 index 00000000..e9dcd1d6 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/seek_tab.go @@ -0,0 +1,10 @@ +package headers + +// Location: include/uapi/linux/fs.h +var SeekLookup = map[int]string{ + 0: "SEEK_SET", + 1: "SEEK_CUR", + 2: "SEEK_END", + 3: "SEEK_DATA", + 4: "SEEK_HOLE", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/signal_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/signal_tab.go new file mode 100644 index 00000000..8d2fe851 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/signal_tab.go @@ -0,0 +1,37 @@ +package headers + +//Location: include/uapi/asm-generic/signal.h +var SignalLookup = map[int]string{ + 0: "SIG0", + 1: "SIGHUP", + 2: "SIGINT", + 3: "SIGQUIT", + 4: "SIGILL", + 5: "SIGTRAP", + 6: "SIGABRT", + 7: "SIGBUS", + 8: "SIGFPE", + 9: "SIGKILL", + 10: "SIGUSR1", + 11: "SIGSEGV", + 12: "SIGUSR2", + 13: "SIGPIPE", + 14: "SIGALRM", + 15: "SIGTERM", + 16: "SIGSTKFLT", + 17: "SIGCHLD", + 18: "SIGCONT", + 19: "SIGSTOP", + 20: "SIGTSTP", + 21: "SIGTTIN", + 22: "SIGTTOU", + 23: "SIGURG", + 24: "SIGXCPU", + 25: "SIGXFSZ", + 26: "SIGVTALRM", + 27: "SIGPROF", + 28: "SIGWINCH", + 29: "SIGIO", + 30: "IGPWR", + 31: "SIGSYS", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/sock_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/sock_tab.go new file mode 100644 index 00000000..ae7e2149 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/sock_tab.go @@ -0,0 +1,27 @@ +package headers + +import "syscall" + +// Location: include/uapi/linux/net.h +var SockLookup = map[int]string{ + syscall.SYS_SOCKET: "socket", + syscall.SYS_BIND: "bind", + syscall.SYS_CONNECT: "connect", + syscall.SYS_LISTEN: "listen", + syscall.SYS_ACCEPT: "accept", + syscall.SYS_GETSOCKNAME: "getsockname", + syscall.SYS_GETPEERNAME: "getpeername", + syscall.SYS_SOCKETPAIR: "socketpair", + 9: "send", + 10: "recv", + syscall.SYS_SENDTO: "sendto", + syscall.SYS_RECVFROM: "recvfrom", + syscall.SYS_SHUTDOWN: "shutdown", + syscall.SYS_SETSOCKOPT: "setsockopt", + syscall.SYS_GETSOCKOPT: "getsockopt", + syscall.SYS_SENDMSG: "sendmsg", + syscall.SYS_RECVMSG: "recvmsg", + syscall.SYS_ACCEPT4: "accept4", + 19: "recvmmsg", + 20: "sendmmsg", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/sockfam_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/sockfam_tab.go new file mode 100644 index 00000000..5a37f2f2 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/sockfam_tab.go @@ -0,0 +1,45 @@ +package headers + +import "syscall" + +//Location: include/linux/socket.h +var SocketFamLookup = map[int]string{ + syscall.AF_LOCAL: "local", + syscall.AF_INET: "inet", + syscall.AF_AX25: "ax25", + syscall.AF_IPX: "ipx", + syscall.AF_APPLETALK: "appletalk", + syscall.AF_NETROM: "netrom", + syscall.AF_BRIDGE: "bridge", + syscall.AF_ATMPVC: "atmpvc", + syscall.AF_X25: "x25", + syscall.AF_INET6: "inet6", + syscall.AF_ROSE: "rose", + syscall.AF_DECnet: "decnet", + syscall.AF_NETBEUI: "netbeui", + syscall.AF_SECURITY: "security", + syscall.AF_KEY: "key", + syscall.AF_NETLINK: "netlink", + syscall.AF_PACKET: "packet", + syscall.AF_ASH: "ash", + syscall.AF_ECONET: "econet", + syscall.AF_ATMSVC: "atmsvc", + syscall.AF_RDS: "rds", + syscall.AF_SNA: "sna", + syscall.AF_IRDA: "irda", + syscall.AF_PPPOX: "pppox", + syscall.AF_WANPIPE: "wanpipe", + syscall.AF_LLC: "llc", + syscall.AF_CAN: "can", + syscall.AF_TIPC: "tipc", + syscall.AF_BLUETOOTH: "bluetooth", + syscall.AF_IUCV: "iucv", + syscall.AF_RXRPC: "rxrpc", + syscall.AF_ISDN: "isdn", + syscall.AF_PHONET: "phonet", + syscall.AF_IEEE802154: "ieee802154", + 37: "caif", + 38: "alg", + 39: "nfc", + 40: "vsock", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/socklevel_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/socklevel_tab.go new file mode 100644 index 00000000..a2319a0c --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/socklevel_tab.go @@ -0,0 +1,37 @@ +package headers + +// Location: include/linux/socket.h +var SockOptLookup = map[int]string{ + 0: "SOL_IP", + 6: "SOL_TCP", + 17: "SOL_UDP", + 41: "SOL_IPV6", + 58: "SOL_ICMPV6", + 132: "SOL_SCTP", + 136: "SOL_UDPLITE", + 255: "SOL_RAW", + 256: "SOL_IPX", + 257: "SOL_AX25", + 258: "SOL_ATALK", + 259: "SOL_NETROM", + 260: "SOL_ROSE", + 261: "SOL_DECNET", + 263: "SOL_PACKET", + 264: "SOL_ATM", + 265: "SOL_AAL", + 266: "SOL_IRDA", + 267: "SOL_NETBEUI", + 268: "SOL_LLC", + 269: "SOL_DCCP", + 270: "SOL_NETLINK", + 271: "SOL_TIPC", + 272: "SOL_RXRPC", + 273: "SOL_PPPOL2TP", + 274: "SOL_BLUETOOTH", + 275: "SOL_PNPIPE", + 276: "SOL_RDS", + 277: "SOL_IUCV", + 278: "SOL_CAIF", + 279: "SOL_ALG", + 280: "SOL_NFC", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/sockoptname_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/sockoptname_tab.go new file mode 100644 index 00000000..9fa1b45d --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/sockoptname_tab.go @@ -0,0 +1,63 @@ +package headers + +// File: include/uapi/asm-generic/socket.h +var SockOptNameLookup = map[int]string{ + 1: "SO_DEBUG", + 2: "SO_REUSEADDR", + 3: "SO_TYPE", + 4: "SO_ERROR", + 5: "SO_DONTROUTE", + 6: "SO_BROADCAST", + 7: "SO_SNDBUF", + 8: "SO_RCVBUF", + 9: "SO_KEEPALIVE", + 10: "SO_OOBINLINE", + 11: "SO_NO_CHECK", + 12: "SO_PRIORITY", + 13: "SO_LINGER", + 14: "SO_BSDCOMPAT", + 15: "SO_REUSEPORT", + 16: "SO_PASSCRED", + 17: "SO_PEERCRED", + 18: "SO_RCVLOWAT", + 19: "SO_SNDLOWAT", + 20: "SO_RCVTIMEO", + 21: "SO_SNDTIMEO", + 22: "SO_SECURITY_AUTHENTICATION", + 23: "SO_SECURITY_ENCRYPTION_TRANSPORT", + 24: "SO_SECURITY_ENCRYPTION_NETWORK", + 25: "SO_BINDTODEVICE", + 26: "SO_ATTACH_FILTER", + 27: "SO_DETACH_FILTER", + 28: "SO_PEERNAME", + 29: "SO_TIMESTAMP", + 30: "SO_ACCEPTCONN", + 31: "SO_PEERSEC", + 32: "SO_SNDBUFFORCE", + 33: "SO_RCVBUFFORCE", + 34: "SO_PASSSEC", + 35: "SO_TIMESTAMPNS", + 36: "SO_MARK", + 37: "SO_TIMESTAMPING", + 38: "SO_PROTOCOL", + 39: "SO_DOMAIN", + 40: "SO_RXQ_OVFL", + 41: "SO_WIFI_STATUS", + 42: "SO_PEEK_OFF", + 43: "SO_NOFCS", + 44: "SO_LOCK_FILTER", + 45: "SO_SELECT_ERR_QUEUE", + 46: "SO_BUSY_POLL", + 47: "SO_MAX_PACING_RATE", + 48: "SO_BPF_EXTENSIONS", + 49: "SO_INCOMING_CPU", + 50: "SO_ATTACH_BPF", + + // PPC has these different + 116: "SO_RCVLOWAT", + 117: "SO_SNDLOWAT", + 118: "SO_RCVTIMEO", + 119: "SO_SNDTIMEO", + 120: "SO_PASSCRED", + 121: "SO_PEERCRED", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/socktype_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/socktype_tab.go new file mode 100644 index 00000000..1d8590ad --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/socktype_tab.go @@ -0,0 +1,12 @@ +package headers + +// Location: include/linux/net.h +var SockTypeLookup = map[int]string{ + 1: "SOCK_STREAM", + 2: "SOCK_DGRAM", + 3: "SOCK_RAW", + 4: "SOCK_RDM", + 5: "SOCK_SEQPACKET", + 6: "SOCK_DCCP", + 10: "SOCK_PACKET", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/tcpoptname_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/tcpoptname_tab.go new file mode 100644 index 00000000..c0704af5 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/tcpoptname_tab.go @@ -0,0 +1,30 @@ +package headers + +// Location: include/uapi/linux/tcp.h +var TcpOptLookup = map[int]string{ + 1: "TCP_NODELAY", + 2: "TCP_MAXSEG", + 3: "TCP_CORK", + 4: "TCP_KEEPIDLE", + 5: "TCP_KEEPINTVL", + 6: "TCP_KEEPCNT", + 7: "TCP_SYNCNT", + 8: "TCP_LINGER2", + 9: "TCP_DEFER_ACCEPT", + 10: "TCP_WINDOW_CLAMP", + 11: "TCP_INFO", + 12: "TCP_QUICKACK", + 13: "TCP_CONGESTION", + 14: "TCP_MD5SIG", + 15: "TCP_COOKIE_TRANSACTIONS", + 16: "TCP_THIN_LINEAR_TIMEOUTS", + 17: "TCP_THIN_DUPACK", + 18: "TCP_USER_TIMEOUT", + 19: "TCP_REPAIR", + 20: "TCP_REPAIR_QUEUE", + 21: "TCP_QUEUE_SEQ", + 22: "TCP_REPAIR_OPTIONS", + 23: "TCP_FASTOPEN", + 24: "TCP_TIMESTAMP", + 25: "TCP_NOTSENT_LOWAT", +} diff --git a/vendor/github.com/mozilla/libaudit-go/headers/umount_tab.go b/vendor/github.com/mozilla/libaudit-go/headers/umount_tab.go new file mode 100644 index 00000000..3aa666c9 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/headers/umount_tab.go @@ -0,0 +1,10 @@ +package headers + +// Location: include/linux/fs.h +var UmountLookUp = map[int]string{ + 0x00000001: "MNT_FORCE", + 0x00000002: "MNT_DETACH", + 0x00000004: "MNT_EXPIRE", + 0x00000008: "UMOUNT_NOFOLLOW", + 0x80000001: "UMOUNT_UNUSED", +} diff --git a/vendor/github.com/mozilla/libaudit-go/interpret.go b/vendor/github.com/mozilla/libaudit-go/interpret.go new file mode 100644 index 00000000..a8237774 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/interpret.go @@ -0,0 +1,1491 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package libaudit + +import ( + "bytes" + "encoding/hex" + "fmt" + "net" + "os/user" + "runtime" + "strconv" + "strings" + "syscall" + + "github.com/lunixbochs/struc" + "github.com/mozilla/libaudit-go/headers" +) + +// fieldType denotes the integer values of various fields occuring in audit messages +type fieldType int + +const ( + typeUID fieldType = iota + typeGID + typeSyscall + typeArch + typeExit + typePerm + typeEscaped + typeMode + typeSockaddr + typePromisc + typeCapability + typeSuccess + typeA0 + typeA1 + typeA2 + typeA3 + typeSignal + typeList + typeTTYData + typeSession + typeCapBitmap + typeNFProto + typeICMP + typeProtocol + typeAddr + typePersonality + typeOFlag + typeSeccomp + typeMmap + typeMacLabel + typeProctile + typeUnclassified + typeModeShort +) + +// interpretField takes fieldName and the encoded fieldValue (part of the audit message) and +// returns the string representations for the values e.g., syscall numbers to names, uids to +// usernames, etc. +func interpretField(fieldName string, fieldValue string, msgType auditConstant, r record) (string, error) { + // the code follows the same logic as these auditd functions (call chain is shown) => + // auparse_interpret_field() [auparse.c] -> nvlist_interp_cur_val(const rnode *r) [nvlist.c] + // -> interpret(r) [interpret.c] -> type = auparse_interp_adjust_type(r->type, id.name, id.val); [interpret.c] + // out = auparse_do_interpretation(type, &id); [interpret.c] + var ( + ftype fieldType + result string + err error + ok bool + ) + + if msgType == AUDIT_EXECVE && strings.HasPrefix(fieldName, "a") && + fieldName != "argc" && strings.Index(fieldName, "_len") == -1 { + ftype = typeEscaped + } else if msgType == AUDIT_AVC && fieldName == "saddr" { + ftype = typeUnclassified + } else if msgType == AUDIT_USER_TTY && fieldName == "msg" { + ftype = typeEscaped + } else if msgType == AUDIT_NETFILTER_PKT && fieldName == "saddr" { + ftype = typeAddr + } else if fieldName == "acct" { + if strings.HasPrefix(fieldValue, `"`) { + ftype = typeEscaped + } else if _, err := strconv.ParseInt(fieldValue, 16, -1); err != nil { + ftype = typeEscaped + } else { + ftype = typeUnclassified + } + } else if msgType == AUDIT_MQ_OPEN && fieldName == "mode" { + ftype = typeModeShort + } else if msgType == AUDIT_CRYPTO_KEY_USER && fieldName == "fp" { + ftype = typeUnclassified + } else if fieldName == "id" && (msgType == AUDIT_ADD_GROUP || msgType == AUDIT_GRP_MGMT || + msgType == AUDIT_DEL_GROUP) { + ftype = typeGID + } else { + if ftype, ok = fieldLookupMap[fieldName]; !ok { + ftype = typeUnclassified + } + } + + switch ftype { + case typeUID: + result, err = printUID(fieldValue) + if err != nil { + return "", err + } + case typeGID: + // XXX printGID is currently only a stub + result, err = printGID(fieldValue) + if err != nil { + return "", err + } + case typeSyscall: + result, err = printSyscall(fieldValue) + if err != nil { + return "", err + } + case typeArch: + return printArch() + case typeExit: + result, err = printExit(fieldValue) // peek on exit codes (stderror) + if err != nil { + return "", err + } + case typePerm: + result, err = printPerm(fieldValue) + if err != nil { + return "", err + } + case typeEscaped: + result, err = printEscaped(fieldValue) + if err != nil { + return "", err + } + case typeMode: + result, err = printMode(fieldValue, 8) + if err != nil { + return "", err + } + case typeModeShort: + result, err = printModeShort(fieldValue, 8) + if err != nil { + return "", err + } + case typeSockaddr: + result, err = printSockAddr(fieldValue) + if err != nil { + return "", err + } + case typePromisc: + result, err = printPromiscuous(fieldValue) + if err != nil { + return "", err + } + case typeCapability: + result, err = printCapabilities(fieldValue, 10) + if err != nil { + return "", err + } + case typeSuccess: + result, err = printSuccess(fieldValue) + if err != nil { + return "", err + } + case typeA0: + result, err = printA0(fieldValue, r.syscallNum) + if err != nil { + return "", err + } + case typeA1: + result, err = printA1(fieldValue, r.syscallNum, r.a0) + if err != nil { + return "", err + } + case typeA2: + result, err = printA2(fieldValue, r.syscallNum, r.a1) + if err != nil { + return "", err + } + case typeA3: + result, err = printA3(fieldValue, r.syscallNum) + if err != nil { + return "", err + } + case typeSignal: + result, err = printSignals(fieldValue, 10) + if err != nil { + return "", err + } + case typeList: + result, err = printList(fieldValue) + if err != nil { + return "", err + } + case typeTTYData: + // TODO: add printTTYData (see interpret.c (auparse) for ideas) + // result, err = printTTYData(fieldValue) + // if err != nil { + // return "", err + // } + case typeSession: + result, err = printSession(fieldValue) + if err != nil { + return "", err + } + case typeCapBitmap: + // TODO: add printCapBitMap (see interpret.c (auparse) for ideas) + // result, err = printCapBitMap(fieldValue) + // if err != nil { + // return "", err + // } + case typeNFProto: + result, err = printNFProto(fieldValue) + if err != nil { + return "", err + } + case typeICMP: + result, err = printICMP(fieldValue) + if err != nil { + return "", err + } + case typeProtocol: + // getprotobynumber + // result, err = printProtocol(fieldValue) + // if err != nil { + // return "", err + // } + case typeAddr: + result, err = printAddr(fieldValue) + if err != nil { + return "", err + } + case typePersonality: + result, err = printPersonality(fieldValue) + if err != nil { + return "", err + } + case typeOFlag: + result, err = printOpenFlags(fieldValue) + if err != nil { + return "", err + } + case typeSeccomp: + result, err = printSeccompCode(fieldValue) + if err != nil { + return "", err + } + case typeMmap: + result, err = printMmap(fieldValue) + if err != nil { + return "", err + } + case typeProctile: + // Printing proctitle is same as printing escaped + result, err = printEscaped(fieldValue) + if err != nil { + return "", err + } + case typeMacLabel: + fallthrough + case typeUnclassified: + fallthrough + default: + result = fieldValue + } + + return result, nil +} + +func printUID(fieldValue string) (string, error) { + name, err := user.LookupId(fieldValue) + if err != nil { + return fmt.Sprintf("unknown(%v)", fieldValue), nil + } + return name.Username, nil +} + +func printGID(fieldValue string) (string, error) { + return fieldValue, nil +} + +func printSyscall(fieldValue string) (string, error) { + name, err := syscallToName(fieldValue) + if err != nil { + return "", err + } + return name, nil +} + +func printArch() (string, error) { + return runtime.GOARCH, nil +} + +func printExit(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 10, 64) + if err != nil { + return "", err + } + // c version of this method tries to retrieve string description of the error code + // ignoring the same approach as the codes can vary + if ival == 0 { + return "success", nil + } + return fieldValue, nil +} + +func printPerm(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 10, 64) + if err != nil { + return "", err + } + var perm string + if ival == 0 { + ival = 0x0F + } + if ival&AUDIT_PERM_READ > 0 { + perm += "read" + } + if ival&AUDIT_PERM_WRITE > 0 { + if len(perm) > 0 { + perm += ",write" + } else { + perm += "write" + } + } + if ival&AUDIT_PERM_EXEC > 0 { + if len(perm) > 0 { + perm += ",exec" + } else { + perm += "exec" + } + } + if ival&AUDIT_PERM_ATTR > 0 { + if len(perm) > 0 { + perm += ",attr" + } else { + perm += "attr" + } + } + return perm, nil +} + +func printMode(fieldValue string, base int) (string, error) { + ival, err := strconv.ParseInt(fieldValue, base, 64) + if err != nil { + return "", err + } + var name string + firstIFMTbit := syscall.S_IFMT & ^(syscall.S_IFMT - 1) + if syscall.S_IFMT&ival == syscall.S_IFSOCK { + name = "socket" + } else if syscall.S_IFMT&ival == syscall.S_IFBLK { + name = "block" + } else if syscall.S_IFMT&ival == syscall.S_IFREG { + name = "file" + } else if syscall.S_IFMT&ival == syscall.S_IFDIR { + name = "dir" + } else if syscall.S_IFMT&ival == syscall.S_IFCHR { + name = "character" + } else if syscall.S_IFMT&ival == syscall.S_IFIFO { + name = "fifo" + } else if syscall.S_IFMT&ival == syscall.S_IFLNK { + name = "link" + } else { + name += fmt.Sprintf("%03o", (int(ival)&syscall.S_IFMT)/firstIFMTbit) + } + // check on special bits + if ival&syscall.S_ISUID > 0 { + name += ",suid" + } + if ival&syscall.S_ISGID > 0 { + name += ",sgid" + } + if ival&syscall.S_ISVTX > 0 { + name += ",sticky" + } + // the read, write, execute flags in octal + name += fmt.Sprintf("%03o", ((syscall.S_IRWXU | syscall.S_IRWXG | syscall.S_IRWXO) & int(ival))) + return name, nil +} + +func printModeShort(fieldValue string, base int) (string, error) { + ival, err := strconv.ParseInt(fieldValue, base, 64) + if err != nil { + return "", err + } + return printModeShortInt(ival) +} + +func printModeShortInt(ival int64) (string, error) { + var name string + // check on special bits + if ival&syscall.S_ISUID > 0 { + name += "suid" + } + if ival&syscall.S_ISGID > 0 { + if len(name) > 0 { + name += "," + } + name += "sgid" + } + if ival&syscall.S_ISVTX > 0 { + if len(name) > 0 { + name += "," + } + name += "sticky" + } + name += fmt.Sprintf("0%03o", ((syscall.S_IRWXU | syscall.S_IRWXG | syscall.S_IRWXO) & int(ival))) + + return name, nil +} + +func printSockAddr(fieldValue string) (string, error) { + // representations of c struct to unpack bytestream into + type sockaddr struct { + SaFamily uint16 `struc:"uint16,little"` // address family, AF_xxx + SaData [14]byte `struc:"[14]byte,little"` // 14 bytes of protocol address + } + + type sockaddrUn struct { + SunFamily uint16 `struc:"uint16,little"` /* AF_UNIX */ + SunPath [108]byte `struc:"[108]byte,little"` /* pathname */ + } + + type sockaddrNl struct { + SunFamily uint16 `struc:"uint16,little"` /* AF_NETLINK */ + NlPad uint16 `struc:"uint16,little"` /* Zero. */ + NlPid int32 `struc:"int32,little"` /* Port ID. */ + NlGroups uint32 `struc:"uint32,little"` /* Multicast groups mask. */ + } + + type sockaddrLl struct { + SllFamily uint16 `struc:"uint16,little"` /* Always AF_PACKET */ + SllProtocol uint16 `struc:"uint16,little"` /* Physical-layer protocol */ + SllIfindex int32 `struc:"int32,little"` /* Interface number */ + SllHatype uint16 `struc:"uint16,little"` /* ARP hardware type */ + SllPkttype byte `struc:"byte,little"` /* Packet type */ + SllHalen byte `struc:"byte,little"` /* Length of address */ + SllAddr [8]byte `struc:"[8]byte,little"` /* Physical-layer address */ + } + + type sockaddrIn struct { + SinFamily uint16 `struc:"uint16,little"` // e.g. AF_INET, AF_INET6 + SinPort uint16 `struc:"uint16,big"` // port in network byte order + InAddr [4]byte `struc:"[4]byte,big"` // address in network byte order + SinZero [8]byte `struc:"[8]byte,little"` + } + + type sockaddrIn6 struct { + Sin6Family uint16 `struc:"uint16,little"` // address family, AF_INET6 + Sin6Port uint16 `struc:"uint16,big"` // port in network byte order + Sin6Flowinfo uint32 `struc:"uint32,little"` // IPv6 flow information + Sin6Addr [16]byte `struc:"[16]byte,big"` // IPv6 address + Sin6ScopeID uint32 `struc:"uint32,little"` // Scope ID + } + + var ( + name string + s sockaddr + ) + + bytestr, err := hex.DecodeString(fieldValue) + if err != nil { + return fieldValue, err + } + + buf := bytes.NewBuffer(bytestr) + err = struc.Unpack(buf, &s) + if err != nil { + return fieldValue, err + } + family := int(s.SaFamily) + + if _, ok := headers.SocketFamLookup[int(family)]; !ok { + return fmt.Sprintf("unknown family (%v)", family), nil + } + + errstring := fmt.Errorf("%s (error resolving addr)", headers.SocketFamLookup[family]) + + switch family { + case syscall.AF_LOCAL: + var p sockaddrUn + nbuf := bytes.NewBuffer(bytestr) + + err = struc.Unpack(nbuf, &p) + if err != nil { + return fieldValue, errstring + } + name = fmt.Sprintf("%s %s", headers.SocketFamLookup[family], string(p.SunPath[:])) + return name, nil + case syscall.AF_INET: + var ip4 sockaddrIn + + nbuf := bytes.NewBuffer(bytestr) + err = struc.Unpack(nbuf, &ip4) + if err != nil { + return fieldValue, errstring + } + addrBytes := ip4.InAddr[:] + var x net.IP = addrBytes + name = fmt.Sprintf("%s host:%s serv:%d", headers.SocketFamLookup[family], x.String(), ip4.SinPort) + return name, nil + case syscall.AF_INET6: + var ip6 sockaddrIn6 + nbuf := bytes.NewBuffer(bytestr) + err = struc.Unpack(nbuf, &ip6) + if err != nil { + return fieldValue, errstring + } + addrBytes := ip6.Sin6Addr[:] + var x net.IP = addrBytes + name = fmt.Sprintf("%s host:%s serv:%d", headers.SocketFamLookup[family], x.String(), ip6.Sin6Port) + return name, nil + case syscall.AF_NETLINK: + var n sockaddrNl + + nbuf := bytes.NewBuffer(bytestr) + err = struc.Unpack(nbuf, &n) + if err != nil { + return fieldValue, errstring + } + name = fmt.Sprintf("%s pid:%d", headers.SocketFamLookup[family], n.NlPid) + return name, nil + case syscall.AF_PACKET: + var l sockaddrLl + + nbuf := bytes.NewBuffer(bytestr) + err = struc.Unpack(nbuf, &l) + if err != nil { + return fieldValue, errstring + } + // TODO: decide on kind of information to return + // currently only returning the family name + // name = fmt.Sprintf("%s pid:%u", famLookup[family], l.) + return headers.SocketFamLookup[family], nil + } + return headers.SocketFamLookup[family], nil +} + +// this is currently just a stub as its only used in RHEL kernels, interpretation +// can be added, see auparse -> interpret.c -> print_flags() +func printFlags(fieldValue string) (string, error) { + return fieldValue, nil +} + +func printEscaped(fieldValue string) (string, error) { + if fieldValue[0] == '"' && fieldValue[len(fieldValue)-1] == '"' { + return fieldValue[1 : len(fieldValue)-1], nil + } + if strings.HasPrefix(fieldValue, "00") { + newStr := unescape(fieldValue[2:]) + if newStr == "" { + return fieldValue, nil + } + } + newStr := unescape(fieldValue) + if newStr == "" { + return fieldValue, nil + } + + return newStr, nil +} + +func unescape(fieldvalue string) string { + if strings.HasPrefix(fieldvalue, "(") { + return fieldvalue + } + if len(fieldvalue) < 2 { + return "" + } + var str []byte + // try to chop 2 characters at a time and convert them from hexadecimal to decimal + str, err := hex.DecodeString(fieldvalue) + if err != nil { + return fieldvalue + } + return string(str) +} + +func printPromiscuous(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 10, 64) + if err != nil { + return "", err + } + if ival == 0 { + return "no", nil + } + return "yes", nil +} + +func printCapabilities(fieldValue string, base int) (string, error) { + ival, err := strconv.ParseInt(fieldValue, base, 64) + if err != nil { + return "", err + } + cap, ok := headers.CapabLookup[int(ival)] + if ok { + return cap, nil + } + if base == 16 { + return fmt.Sprintf("unknown capability(0x%d)", ival), nil + } + return fmt.Sprintf("unknown capability(%d)", ival), nil +} + +func printSuccess(fieldValue string) (string, error) { + + ival, err := strconv.ParseInt(fieldValue, 10, 64) + if err != nil { + // if we are unable to parse success values just return them as is, + // behaviour is the same as auparse interpret.c + return fieldValue, nil + } + const ( + sUnset = -1 + sFailed = iota + sSuccess + ) + + switch int(ival) { + case sSuccess: + return "yes", nil + case sFailed: + return "no", nil + default: + return "unset", nil + } + +} + +func printA0(fieldValue string, sysNum string) (string, error) { + name, err := syscallToName(sysNum) + if err != nil { + return "", err + } + if strings.HasPrefix(name, "r") { + if name == "rt_sigaction" { + return printSignals(fieldValue, 16) + } else if name == "renameat" { + return printDirFd(fieldValue) + } else if name == "readlinkat" { + return printDirFd(fieldValue) + } + } else if strings.HasPrefix(name, "c") { + if name == "clone" { + return printCloneFlags(fieldValue) + } else if name == "clock_settime" { + return printClockID(fieldValue) + } + } else if strings.HasPrefix(name, "p") { + if name == "personality" { + return printPersonality(fieldValue) + } else if name == "ptrace" { + return printPtrace(fieldValue) + } else if name == "prctl" { + return printPrctlOpt(fieldValue) + } + } else if strings.HasPrefix(name, "m") { + if name == "mkdirat" { + return printDirFd(fieldValue) + } else if name == "mknodat" { + return printDirFd(fieldValue) + } + } else if strings.HasPrefix(name, "f") { + if name == "fchownat" { + return printDirFd(fieldValue) + } else if name == "futimesat" { + return printDirFd(fieldValue) + } else if name == "fchmodat" { + return printDirFd(fieldValue) + } else if name == "faccessat" { + return printDirFd(fieldValue) + } else if name == "ftimensat" { + return printDirFd(fieldValue) + } + } else if strings.HasPrefix(name, "u") { + if name == "unshare" { + return printCloneFlags(fieldValue) + } else if name == "unlinkat" { + return printDirFd(fieldValue) + } else if name == "utimesat" { + return printDirFd(fieldValue) + } else if name == "etrlimit" { + return printRLimit(fieldValue) + } + } else if strings.HasPrefix(name, "s") { + if name == "setuid" { + return printUID(fieldValue) + } else if name == "setreuid" { + return printUID(fieldValue) + } else if name == "setresuid" { + return printUID(fieldValue) + } else if name == "setfsuid" { + return printUID(fieldValue) + } else if name == "setgid" { + return printGID(fieldValue) + } else if name == "setregid" { + return printGID(fieldValue) + } else if name == "setresgid" { + return printGID(fieldValue) + } else if name == "socket" { + return printSocketDomain(fieldValue) + } else if name == "setfsgid" { + return printGID(fieldValue) + } else if name == "socketcall" { + return printSocketCall(fieldValue, 16) + } + } else if name == "linkat" { + return printDirFd(fieldValue) + } else if name == "newfsstat" { + return printDirFd(fieldValue) + } else if name == "openat" { + return printDirFd(fieldValue) + } else if name == "ipccall" { + return printIpcCall(fieldValue, 16) + } + + return fmt.Sprintf("0x%s", fieldValue), nil +} + +func printSignals(fieldValue string, base int) (string, error) { + + ival, err := strconv.ParseInt(fieldValue, base, 64) + if err != nil { + return "", err + } + if ival < 31 { + return headers.SignalLookup[int(ival)], nil + } + if base == 16 { + return fmt.Sprintf("unknown signal (0x%s)", fieldValue), nil + } + return fmt.Sprintf("unknown signal (%s)", fieldValue), nil +} + +func printDirFd(fieldValue string) (string, error) { + if fieldValue == "-100" { + return "AT_FDWD", nil + } + return fmt.Sprintf("0x%s", fieldValue), nil +} + +func printCloneFlags(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + + var name string + for key, val := range headers.CloneLookUp { + if key&int(ival) > 0 { + if len(name) > 0 { + name += "|" + } + name += val + } + } + var cloneSignal = ival & 0xFF + if cloneSignal > 0 && cloneSignal < 32 { + if len(name) > 0 { + name += "|" + } + name += headers.SignalLookup[int(cloneSignal)] + } + if len(name) == 0 { + return fmt.Sprintf("0x%d", ival), nil + } + return name, nil +} + +func printClockID(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + if ival < 7 { + return headers.ClockLookup[int(ival)], nil + } + return fmt.Sprintf("unknown clk_id (0x%s)", fieldValue), nil +} + +// TODO: add personality interpretation +// see auparse -> interpret.c -> print_personality() lookup table persontab.h +func printPersonality(fieldValue string) (string, error) { + return fieldValue, nil +} + +func printPtrace(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + if _, ok := headers.PtraceLookup[int(ival)]; !ok { + return fmt.Sprintf("unknown ptrace (0x%s)", fieldValue), nil + } + return headers.PtraceLookup[int(ival)], nil +} + +func printPrctlOpt(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + if _, ok := headers.PrctlLookup[int(ival)]; !ok { + return fmt.Sprintf("unknown prctl option (0x%s)", fieldValue), nil + } + return headers.PrctlLookup[int(ival)], nil +} + +func printSocketDomain(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + if _, ok := headers.SocketFamLookup[int(ival)]; !ok { + return fmt.Sprintf("unknown family (0x%s)", fieldValue), nil + } + return headers.SocketFamLookup[int(ival)], nil + +} + +func printSocketCall(fieldValue string, base int) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + if _, ok := headers.SockLookup[int(ival)]; !ok { + return fmt.Sprintf("unknown socketcall (0x%s)", fieldValue), nil + } + return headers.SockLookup[int(ival)], nil +} + +func printRLimit(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + if _, ok := headers.RlimitLookup[int(ival)]; !ok { + return fmt.Sprintf("unknown rlimit (0x%s)", fieldValue), nil + } + return headers.RlimitLookup[int(ival)], nil +} + +func printIpcCall(fieldValue string, base int) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + if _, ok := headers.IpccallLookup[int(ival)]; !ok { + return fmt.Sprintf("unknown ipccall (%s)", fieldValue), nil + } + return headers.IpccallLookup[int(ival)], nil +} + +func printA1(fieldValue, sysNum string, a0 int) (string, error) { + name, err := syscallToName(sysNum) + if err != nil { + return "", err + } + if strings.HasPrefix(name, "f") { + if name == "fchmod" { + return printModeShort(fieldValue, 16) + } else if name == "fcntl" { + return printFcntlCmd(fieldValue) + } + } + if strings.HasPrefix(name, "c") { + if name == "chmod" { + return printModeShort(fieldValue, 16) + } else if k := strings.Index(name, "chown"); k != -1 { + return printUID(fieldValue) + } else if name == "creat" { + return printModeShort(fieldValue, 16) + } + } + if name[1:] == "etsocketopt" { + return printSockOptLevel(fieldValue) + } else if strings.HasPrefix(name, "s") { + if name == "setreuid" { + return printUID(fieldValue) + } else if name == "setresuid" { + return printUID(fieldValue) + } else if name == "setregid" { + return printGID(fieldValue) + } else if name == "setresgid" { + return printGID(fieldValue) + } else if name == "socket" { + return printSocketType(fieldValue) + } else if name == "setns" { + return printCloneFlags(fieldValue) + } else if name == "sched_setscheduler" { + return printSched(fieldValue) + } + } else if strings.HasPrefix(name, "m") { + if name == "mkdir" { + return printModeShort(fieldValue, 16) + } else if name == "mknod" { + return printMode(fieldValue, 16) + } else if name == "mq_open" { + return printOpenFlags(fieldValue) + } + } else if name == "open" { + return printOpenFlags(fieldValue) + } else if name == "access" { + return printAccess(fieldValue) + } else if name == "epoll_ctl" { + return printEpollCtl(fieldValue) + } else if name == "kill" { + return printSignals(fieldValue, 16) + } else if name == "prctl" { + if a0 == syscall.PR_CAPBSET_READ || a0 == syscall.PR_CAPBSET_DROP { + return printCapabilities(fieldValue, 16) + } else if a0 == syscall.PR_SET_PDEATHSIG { + return printSignals(fieldValue, 16) + } + } else if name == "tkill" { + return printSignals(fieldValue, 16) + } else if name == "umount2" { + return printUmount(fieldValue) + } else if name == "ioctl" { + return printIoctlReq(fieldValue) + } + return fmt.Sprintf("0x%s", fieldValue), nil +} + +func printFcntlCmd(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + if _, ok := headers.FcntlLookup[int(ival)]; !ok { + return fmt.Sprintf("unknown fcntl command(%d)", ival), nil + } + return headers.FcntlLookup[int(ival)], nil +} + +func printSocketType(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + if _, ok := headers.SockTypeLookup[int(ival)]; !ok { + return fmt.Sprintf("unknown socket type(%d)", ival), nil + } + return headers.SockTypeLookup[int(ival)], nil +} + +func printSched(fieldValue string) (string, error) { + const schedResetOnFork int64 = 0x40000000 + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + if _, ok := headers.SchedLookup[int(ival)&0x0F]; !ok { + return fmt.Sprintf("unknown scheduler policy (0x%s)", fieldValue), nil + } + if ival&schedResetOnFork > 0 { + return headers.SchedLookup[int(ival)] + "|SCHED_RESET_ON_FORK", nil + } + return headers.SchedLookup[int(ival)], nil +} + +// TODO: add interpretation +// see auparse -> interpret.c -> print_open_flags() for ideas +// useful for debugging rather than forensics actual policy is to filter either on open or write or both +// and emit msg that this happened so if its opened in r,rw, etc. All endup looking the same i.e READ or WRITE +// auparse specific table is open-flagtab.h. +func printOpenFlags(fieldValue string) (string, error) { + // look at table of values from /usr/include/asm-generic/fcntl.h + return fieldValue, nil +} + +// policy is to only log success or denial but not read the actual value +// ie make a rule on the arguments but dont read it and just trust that right rule is reported +// auparse specific table is accesstab.h +func printAccess(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + if ival&0x0F == 0 { + return "F_OK", nil + } + var name string + for key, val := range headers.AccessLookUp { + if key&int(ival) > 0 { + if len(name) > 0 { + name += "|" + } + name += val + } + } + if len(name) == 0 { + return fmt.Sprintf("0x%s", fieldValue), nil + } + return name, nil +} + +func printEpollCtl(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + if _, ok := headers.EpollLookup[int(ival)]; !ok { + return fmt.Sprintf("unknown epoll_ctl operation (%d)", ival), nil + } + return headers.EpollLookup[int(ival)], nil +} + +func printUmount(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + var name string + for key, val := range headers.UmountLookUp { + if key&int(ival) > 0 { + if len(name) > 0 { + name += "|" + } + name += val + } + } + + if len(name) == 0 { + return fmt.Sprintf("0x%s", fieldValue), nil + } + return name, nil +} + +func printIoctlReq(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + + if _, ok := headers.IoctlLookup[int(ival)]; !ok { + return fmt.Sprintf("0x%s", fieldValue), nil + } + return headers.IoctlLookup[int(ival)], nil +} + +// TODO: add interpretation +// see auparse -> interpret.c -> print_sock_opt_level +// needs a go implementation of getprotobynumber +func printSockOptLevel(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + if ival == syscall.SOL_SOCKET { + return "SOL_SOCKET", nil + } + // pure go implementation of getprotobynumber + // if not find by getprotobynumber use map + if _, ok := headers.SockOptLookup[int(ival)]; !ok { + return fmt.Sprintf("unknown sockopt level (0x%s)", fieldValue), nil + } + return headers.SockOptLookup[int(ival)], nil +} + +// TODO: add interpretation +// see auparse -> interpret.c -> print_socket_proto +// add pure go implementation of getprotobynumber +func printSocketProto(fieldValue string) (string, error) { + // ival, err := strconv.ParseInt(fieldValue, 16, 64) + // if err != nil { + // return "", err + // } + //protocol = getprotobynumber(ival) + // if not found + // return fmt.Sprintf("unknown proto(%s)", fieldValue), nil + return fieldValue, nil +} + +func printA2(fieldValue, sysNum string, a1 int) (string, error) { + name, err := syscallToName(sysNum) + if err != nil { + return "", err + } + if name == "fcntl" { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + switch a1 { + case syscall.F_SETOWN: + return printUID(fieldValue) + case syscall.F_SETFD: + if ival == syscall.FD_CLOEXEC { + return "FD_CLOSEXEC", nil + } + case syscall.F_SETFL: + case syscall.F_SETLEASE: + case syscall.F_GETLEASE: + case syscall.F_NOTIFY: + } + } else if name[1:] == "esockopt" { + if a1 == syscall.IPPROTO_IP { + return printIPOptName(fieldValue) + } else if a1 == syscall.SOL_SOCKET { + return printSockOptName(fieldValue) // add machine ? + } else if a1 == syscall.IPPROTO_UDP { + return printUDPOptName(fieldValue) + } else if a1 == syscall.IPPROTO_IPV6 { + return printIP6OptName(fieldValue) + } else if a1 == syscall.SOL_PACKET { + return printPktOptName(fieldValue) + } + return fmt.Sprintf("0x%s", fieldValue), nil + } else if strings.HasPrefix(name, "o") { + if name == "openat" { + return printOpenFlags(fieldValue) + } + if name == "open" && (a1&syscall.O_CREAT > 0) { + return printModeShort(fieldValue, 16) + } + } else if strings.HasPrefix(name, "f") { + if name == "fchmodat" { + return printModeShort(fieldValue, 16) + } else if name == "faccessat" { + return printAccess(fieldValue) + } + } else if strings.HasPrefix(name, "s") { + if name == "setresuid" { + return printUID(fieldValue) + } else if name == "setresgid" { + return printGID(fieldValue) + } else if name == "socket" { + return printSocketProto(fieldValue) + } else if name == "sendmsg" { + return printRecv(fieldValue) + } else if name == "shmget" { + return printSHMFlags(fieldValue) + } + } else if strings.HasPrefix(name, "m") { + if name == "mmap" { + return printProt(fieldValue, 1) + } else if name == "mkdirat" { + return printModeShort(fieldValue, 16) + } else if name == "mknodat" { + return printModeShort(fieldValue, 16) + } else if name == "mprotect" { + return printProt(fieldValue, 0) + } else if name == "mqopen" && a1&syscall.O_CREAT > 0 { + return printModeShort(fieldValue, 16) + } + } else if strings.HasPrefix(name, "r") { + if name == "recvmsg" { + return printRecv(fieldValue) + } else if name == "readlinkat" { + return printDirFd(fieldValue) + } + } else if strings.HasPrefix(name, "l") { + if name == "linkat" { + return printDirFd(fieldValue) + } else if name == "lseek" { + return printSeek(fieldValue) + } + } else if name == "chown" { + return printGID(fieldValue) + } else if name == "tgkill" { + return printSignals(fieldValue, 16) + } + return fmt.Sprintf("0x%s", fieldValue), nil +} + +func printIPOptName(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + if _, ok := headers.IpOptLookup[int(ival)]; !ok { + return fmt.Sprintf("unknown ipopt name (0x%s)", fieldValue), nil + } + return headers.IpOptLookup[int(ival)], nil +} + +func printIP6OptName(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + if _, ok := headers.Ip6OptLookup[int(ival)]; !ok { + return fmt.Sprintf("unknown ip6opt name (0x%s)", fieldValue), nil + } + return headers.Ip6OptLookup[int(ival)], nil +} + +func printTCPOptName(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + if _, ok := headers.TcpOptLookup[int(ival)]; !ok { + return fmt.Sprintf("unknown tcpopt name (0x%s)", fieldValue), nil + } + return headers.TcpOptLookup[int(ival)], nil +} + +func printUDPOptName(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + if ival == 1 { + return "UDP_CORK", nil + } else if ival == 100 { + return "UDP_ENCAP", nil + } + + return fmt.Sprintf("unknown udpopt name (0x%s)", fieldValue), nil +} + +func printPktOptName(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + if _, ok := headers.PktOptLookup[int(ival)]; !ok { + return fmt.Sprintf("unknown pktopt name (0x%s)", fieldValue), nil + } + return headers.PktOptLookup[int(ival)], nil +} + +// printSHMFlags - What are the actual values from table ( are they in binary?) +func printSHMFlags(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + var ipccmdLookUp = map[int]string{ + 00001000: "IPC_CREAT", + 00002000: "IPC_EXCL", + 00004000: "IPC_NOWAIT", + } + var name string + var partial = ival & 00003000 + for key, val := range ipccmdLookUp { + if key&int(partial) > 0 { + if len(name) > 0 { + name += "|" + } + name += val + } + } + partial = ival & 00014000 + var shmLookUp = map[int]string{ + 00001000: "SHM_DEST", + 00002000: "SHM_LOCKED", + 00004000: "SHM_HUGETLB", + 00010000: "SHM_NORESERVE", + } + for key, val := range shmLookUp { + if key&int(partial) > 0 { + if len(name) > 0 { + name += "|" + } + name += val + } + } + partial = ival & 000777 + tmode, err := printModeShortInt(partial) + if err != nil { + return "", err + } + if len(name) > 0 { + name += "|" + } + name += tmode + + if len(name) == 0 { + return fmt.Sprintf("0x%s", fieldValue), nil + } + + return name, nil +} + +func printProt(fieldValue string, isMmap int) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + if ival&0x07 == 0 { + return "PROT_NONE", nil + } + + var name string + for key, val := range headers.ProtLookUp { + if key&int(ival) > 0 { + if len(name) > 0 { + name += "|" + } + // skip last key if isMmap == 0 + if isMmap == 0 && val == "PROT_SEM" { + continue + } + name += val + } + } + + if len(name) == 0 { + return fmt.Sprintf("0x%s", fieldValue), nil + } + + return name, nil +} + +func printSockOptName(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + if _, ok := headers.SockOptNameLookup[int(ival)]; !ok { + return fmt.Sprintf("unknown sockopt name (0x%s)", fieldValue), nil + } + return headers.SockOptNameLookup[int(ival)], nil +} + +func printRecv(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + var name string + for key, val := range headers.RecvLookUp { + if key&int(ival) > 0 { + if len(name) > 0 { + name += "|" + } + name += val + } + } + + if len(name) == 0 { + return fmt.Sprintf("0x%s", fieldValue), nil + } + return name, nil +} + +func printSeek(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + var whence = int(ival) & 0xFF + if _, ok := headers.SeekLookup[whence]; !ok { + return fmt.Sprintf("unknown whence(0x%s)", fieldValue), nil + } + return headers.SeekLookup[whence], nil +} + +func printA3(fieldValue, sysNum string) (string, error) { + name, err := syscallToName(sysNum) + if err != nil { + return "", err + } + if strings.HasPrefix(name, "m") { + if name == "mmap" { + return printMmap(fieldValue) + } else if name == "mount" { + return printMount(fieldValue) + } + } else if strings.HasPrefix(name, "r") { + if name == "recv" { + return printRecv(fieldValue) + } else if name == "recvfrom" { + return printRecv(fieldValue) + } else if name == "recvmsg" { + return printRecv(fieldValue) + } + } else if strings.HasPrefix(name, "s") { + if name == "send" { + return printRecv(fieldValue) + } else if name == "sendto" { + return printRecv(fieldValue) + } else if name == "sendmmsg" { + return printRecv(fieldValue) + } + } + return fmt.Sprintf("0x%s", fieldValue), nil +} + +func printMmap(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + var name string + if ival&0x0F == 0 { + name += "MAP_FILE" + } + for key, val := range headers.MmapLookUp { + if key&int(ival) > 0 { + if len(name) > 0 { + name += "|" + } + name += val + } + } + + if len(name) == 0 { + return fmt.Sprintf("0x%s", fieldValue), nil + } + return name, nil +} + +func printMount(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + var name string + for key, val := range headers.MountLookUp { + if key&int(ival) > 0 { + if len(name) > 0 { + name += "|" + } + name += val + } + } + + if len(name) == 0 { + return fmt.Sprintf("0x%s", fieldValue), nil + } + return name, nil +} + +func printSession(fieldValue string) (string, error) { + if fieldValue == "4294967295" { + return "unset", nil + } + return fieldValue, nil +} + +func printNFProto(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 10, 64) + if err != nil { + return "", err + } + if _, ok := headers.NfProtoLookup[int(ival)]; !ok { + return fmt.Sprintf("unknown netfilter protocol (%s)", fieldValue), nil + } + return headers.NfProtoLookup[int(ival)], nil +} + +func printICMP(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 10, 64) + if err != nil { + return "", err + } + if _, ok := headers.IcmpLookup[int(ival)]; !ok { + return fmt.Sprintf("unknown icmp type (%s)", fieldValue), nil + } + return headers.IcmpLookup[int(ival)], nil +} + +func printAddr(fieldValue string) (string, error) { + return fieldValue, nil +} + +func printSeccompCode(fieldValue string) (string, error) { + if strings.HasPrefix(fieldValue, "0x") { + fieldValue = fieldValue[2:] + } + ival, err := strconv.ParseInt(fieldValue, 16, 64) + if err != nil { + return "", err + } + var SECCOMPRETACTION = 0x7fff0000 + if _, ok := headers.SeccompCodeLookUp[int(ival)&SECCOMPRETACTION]; !ok { + return fmt.Sprintf("unknown seccomp code (%s)", fieldValue), nil + } + return headers.SeccompCodeLookUp[int(ival)&SECCOMPRETACTION], nil +} + +func printList(fieldValue string) (string, error) { + ival, err := strconv.ParseInt(fieldValue, 10, 64) + if err != nil { + return "", err + } + if _, ok := flagLookup[int(ival)]; !ok { + return fmt.Sprintf("unknown list (%s)", fieldValue), nil + } + return flagLookup[int(ival)], nil +} diff --git a/vendor/github.com/mozilla/libaudit-go/libaudit.go b/vendor/github.com/mozilla/libaudit-go/libaudit.go new file mode 100644 index 00000000..bea2ecbd --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/libaudit.go @@ -0,0 +1,444 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Package libaudit is a client library used for interfacing with the Linux kernel auditing framework. It +// provides an API for executing audit related tasks such as setting audit rules, changing the auditing +// configuration, and processing incoming audit events. +// +// The intent for this package is to provide a means for an application to take the role of auditd, for +// consumption and analysis of audit events in your go program. +package libaudit + +import ( + "bytes" + "encoding/binary" + "fmt" + "sync/atomic" + "syscall" + "unsafe" +) + +// The sequence number used for requests from us to the kernel in netlink messages, +// just increments. +var sequenceNumber uint32 + +// hostEndian is initialized to the byte order of the system +var hostEndian binary.ByteOrder + +func init() { + hostEndian = nativeEndian() +} + +func nextSequence() uint32 { + return atomic.AddUint32(&sequenceNumber, 1) +} + +// NetlinkMessage is the struct type that is used for communicating on netlink sockets. +type NetlinkMessage syscall.NetlinkMessage + +// auditStatus represents the c struct audit_status (libaudit.h). It is used for passing +// information related to the status of the auditing services between the kernel and +// userspace. +type auditStatus struct { + Mask uint32 /* Bit mask for valid entries */ + Enabled uint32 /* 1 = enabled, 0 = disabled */ + Failure uint32 /* Failure-to-log action */ + Pid uint32 /* pid of auditd process */ + RateLimit uint32 /* messages rate limit (per second) */ + BacklogLimit uint32 /* waiting messages limit */ + Lost uint32 /* messages lost */ + Backlog uint32 /* messages waiting in queue */ + Version uint32 /* audit api version number */ + BacklogWaitTime uint32 /* message queue wait timeout */ +} + +// Netlink is an abstracting netlink IO functions; generally used with NetlinkConnection +type Netlink interface { + Send(request *NetlinkMessage) error // Send a NetlinkMessage + Receive(nonblocking bool) ([]NetlinkMessage, error) // Receive netlink message(s) from the kernel + GetPID() (int, error) // Get netlink peer PID +} + +// NetlinkConnection describes a netlink interface with the kernel. +// +// Programs should call NewNetlinkConnection() to create a new instance. +type NetlinkConnection struct { + fd int // File descriptor used for communication + address syscall.SockaddrNetlink // Netlink sockaddr +} + +// Close closes the Netlink connection. +func (s *NetlinkConnection) Close() { + syscall.Close(s.fd) +} + +// Send sends NetlinkMessage request using an allocated NetlinkConnection. +func (s *NetlinkConnection) Send(request *NetlinkMessage) error { + return syscall.Sendto(s.fd, request.ToWireFormat(), 0, &s.address) +} + +// Receive returns any available netlink messages being sent to us by the kernel. +func (s *NetlinkConnection) Receive(nonblocking bool) ([]NetlinkMessage, error) { + var ( + flags = 0 + ) + if nonblocking { + flags |= syscall.MSG_DONTWAIT + } + buf := make([]byte, MAX_AUDIT_MESSAGE_LENGTH+syscall.NLMSG_HDRLEN) + nr, _, err := syscall.Recvfrom(s.fd, buf, flags) + if err != nil { + return nil, err + } + return parseAuditNetlinkMessage(buf[:nr]) +} + +// GetPID returns the netlink port ID of the netlink socket peer. +func (s *NetlinkConnection) GetPID() (int, error) { + var ( + address syscall.Sockaddr + v *syscall.SockaddrNetlink + err error + ) + address, err = syscall.Getsockname(s.fd) + if err != nil { + return 0, err + } + v = address.(*syscall.SockaddrNetlink) + return int(v.Pid), nil +} + +// nativeEndian determines the byte order for the system +func nativeEndian() binary.ByteOrder { + var x uint32 = 0x01020304 + if *(*byte)(unsafe.Pointer(&x)) == 0x01 { + return binary.BigEndian + } + return binary.LittleEndian +} + +// ToWireFormat converts a given NetlinkMessage to a byte stream suitable to be sent to +// the kernel. +func (rr *NetlinkMessage) ToWireFormat() []byte { + buf := new(bytes.Buffer) + pbytes := nlmAlignOf(int(rr.Header.Len)) - int(rr.Header.Len) + err := binary.Write(buf, hostEndian, rr.Header.Len) + if err != nil { + return nil + } + err = binary.Write(buf, hostEndian, rr.Header.Type) + if err != nil { + return nil + } + err = binary.Write(buf, hostEndian, rr.Header.Flags) + if err != nil { + return nil + } + err = binary.Write(buf, hostEndian, rr.Header.Seq) + if err != nil { + return nil + } + err = binary.Write(buf, hostEndian, rr.Header.Pid) + if err != nil { + return nil + } + err = binary.Write(buf, hostEndian, rr.Data) + if err != nil { + return nil + } + if pbytes > 0 { + pbuf := make([]byte, pbytes) + _, err = buf.Write(pbuf) + if err != nil { + return nil + } + } + return buf.Bytes() +} + +// nlmAlignOf rounds the length of a netlink message up to align it properly. +func nlmAlignOf(msglen int) int { + return (msglen + syscall.NLMSG_ALIGNTO - 1) & ^(syscall.NLMSG_ALIGNTO - 1) +} + +// parseAuditNetlinkMessage processes an incoming netlink message from the socket, +// and returns a slice of NetlinkMessage types, or an error if an error is encountered. +// +// This function handles incoming messages with NLM_F_MULTI; in the case of +// a multipart message, ret will contain all netlink messages which are part +// of the kernel message. If it is not a multipart message, ret will simply +// contain a single message. +func parseAuditNetlinkMessage(b []byte) (ret []NetlinkMessage, err error) { + for len(b) != 0 { + multi := false + var ( + m NetlinkMessage + ) + + m.Header.Len, b, err = netlinkPopuint32(b) + if err != nil { + return + } + // Determine our alignment size given the reported header length + alignbounds := nlmAlignOf(int(m.Header.Len)) + padding := alignbounds - int(m.Header.Len) + + // Subtract 4 from alignbounds here to account for already having popped 4 bytes + // off the input buffer + if len(b) < alignbounds-4 { + return ret, fmt.Errorf("short read on audit message, expected %v bytes had %v", + alignbounds, len(b)+4) + } + // If we get here, we have enough data for the entire message + m.Header.Type, b, err = netlinkPopuint16(b) + if err != nil { + return ret, err + } + m.Header.Flags, b, err = netlinkPopuint16(b) + if err != nil { + return ret, err + } + if (m.Header.Flags & syscall.NLM_F_MULTI) != 0 { + multi = true + } + m.Header.Seq, b, err = netlinkPopuint32(b) + if err != nil { + return ret, err + } + m.Header.Pid, b, err = netlinkPopuint32(b) + if err != nil { + return ret, err + } + // Determine how much data we want to read here; if this isn't NLM_F_MULTI, we'd + // typically want to read m.Header.Len bytes (the length of the payload indicated in + // the netlink header. + // + // However, this isn't always the case. Depending on what is generating the audit + // message (e.g., via audit_log_end) the kernel does not include the netlink header + // size in the submitted audit message. So, we just read whatever is left in the buffer + // we have if this isn't multipart. + // + // Additionally, it seems like there are also a few messages types where the netlink paylaod + // value is inaccurate and can't be relied upon. + // + // XXX Just consuming the rest of the buffer based on the event type might be a better + // approach here. + if !multi { + m.Data = b + } else { + datalen := m.Header.Len - syscall.NLMSG_HDRLEN + m.Data = b[:datalen] + b = b[int(datalen)+padding:] + } + ret = append(ret, m) + if !multi { + break + } + } + return ret, nil +} + +// netlinkPopuint16 pops a uint16 off the front of b, returning the value and the new buffer +func netlinkPopuint16(b []byte) (uint16, []byte, error) { + if len(b) < 2 { + return 0, b, fmt.Errorf("not enough bytes for uint16") + } + return hostEndian.Uint16(b[:2]), b[2:], nil +} + +// netlinkPopuint32 pops a uint32 off the front of b, returning the value and the new buffer +func netlinkPopuint32(b []byte) (uint32, []byte, error) { + if len(b) < 4 { + return 0, b, fmt.Errorf("not enough bytes for uint32") + } + return hostEndian.Uint32(b[:4]), b[4:], nil +} + +// newNetlinkAuditRequest initializes the header section as preparation for sending a new +// netlink message. +func newNetlinkAuditRequest(proto uint16, family, sizeofData int) *NetlinkMessage { + rr := &NetlinkMessage{} + rr.Header.Len = uint32(syscall.NLMSG_HDRLEN + sizeofData) + rr.Header.Type = proto + rr.Header.Flags = syscall.NLM_F_REQUEST | syscall.NLM_F_ACK + rr.Header.Seq = nextSequence() + return rr +} + +// NewNetlinkConnection creates a new netlink connection with the kernel audit subsystem +// and returns a NetlinkConnection describing it. The process should ensure it has the +// required privileges before calling. An error is returned if any error is encountered +// creating the netlink connection. +func NewNetlinkConnection() (ret *NetlinkConnection, err error) { + ret = &NetlinkConnection{} + ret.fd, err = syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_AUDIT) + if err != nil { + return + } + ret.address.Family = syscall.AF_NETLINK + ret.address.Groups = 0 + ret.address.Pid = 0 // 0 for kernel space + if err = syscall.Bind(ret.fd, &ret.address); err != nil { + syscall.Close(ret.fd) + return + } + return +} + +// auditGetReply gets a reply to a message from the kernel. The message(s) we are looking for are +// indicated by passing sequence number seq. +// +// Once we recieve the full response any matching messages are returned. Note this function +// would generally be used to retrieve a response from various AUDIT_SET functions or similar +// configuration routines, and we do not use this for draining the audit event queue. +// +// chkAck should be set to true if the response we are expecting is just an ACK packet back +// from netlink. If chkAck is false, the function will also retrieve other types of messages +// related to the specified sequence number (like the response messages related to a query). +// +// XXX Right now we just discard any unrelated messages, which is not neccesarily +// ideal. This could be adapted to handle this better. +// +// XXX This function also waits until it gets the correct message, so if for some reason +// the message does not come through it will not return. This should also be improved. +func auditGetReply(s Netlink, seq uint32, chkAck bool) (ret []NetlinkMessage, err error) { +done: + for { + dbrk := false + msgs, err := s.Receive(false) + if err != nil { + return ret, err + } + for _, m := range msgs { + socketPID, err := s.GetPID() + if err != nil { + return ret, err + } + if m.Header.Seq != seq { + // Wasn't the sequence number we are looking for, just discard it + continue + } + if int(m.Header.Pid) != socketPID { + // PID didn't match, just discard it + continue + } + if m.Header.Type == syscall.NLMSG_DONE { + break done + } + if m.Header.Type == syscall.NLMSG_ERROR { + e := int32(hostEndian.Uint32(m.Data[0:4])) + if e == 0 { + // ACK response from the kernel; if chkAck is true + // we just return as there is nothing left to do + if chkAck { + break done + } + // Otherwise, keep going so we can get the response + // we want + continue + } else { + return ret, fmt.Errorf("error while recieving reply %v", e) + } + } + ret = append(ret, m) + if (m.Header.Flags & syscall.NLM_F_MULTI) == 0 { + // If it's not a multipart message, once we get one valid + // message just return + dbrk = true + break + } + } + if dbrk { + break + } + } + return ret, nil +} + +// auditSendStatus sends AUDIT_SET with the associated auditStatus configuration +func auditSendStatus(s Netlink, status auditStatus) (err error) { + buf := new(bytes.Buffer) + err = binary.Write(buf, hostEndian, status) + if err != nil { + return + } + wb := newNetlinkAuditRequest(uint16(AUDIT_SET), syscall.AF_NETLINK, AUDIT_STATUS_SIZE) + wb.Data = buf.Bytes() + if err = s.Send(wb); err != nil { + return + } + _, err = auditGetReply(s, wb.Header.Seq, true) + if err != nil { + return + } + return nil +} + +// AuditSetEnabled enables or disables auditing in the kernel. +func AuditSetEnabled(s Netlink, enabled bool) (err error) { + var status auditStatus + if enabled { + status.Enabled = 1 + } else { + status.Enabled = 0 + } + status.Mask = AUDIT_STATUS_ENABLED + return auditSendStatus(s, status) +} + +// AuditIsEnabled returns true if auditing is enabled in the kernel. +func AuditIsEnabled(s Netlink) (bool, error) { + var status auditStatus + + wb := newNetlinkAuditRequest(uint16(AUDIT_GET), syscall.AF_NETLINK, 0) + if err := s.Send(wb); err != nil { + return false, err + } + + msgs, err := auditGetReply(s, wb.Header.Seq, false) + if err != nil { + return false, err + } + if len(msgs) != 1 { + return false, fmt.Errorf("unexpected number of responses from kernel for status request") + } + m := msgs[0] + if m.Header.Type != uint16(AUDIT_GET) { + return false, fmt.Errorf("status request response type was invalid") + } + // Convert the response to auditStatus + buf := bytes.NewBuffer(m.Data) + err = binary.Read(buf, hostEndian, &status) + if err != nil { + return false, err + } + if status.Enabled == 1 { + return true, nil + } + return false, nil +} + +// AuditSetPID sets the PID for the audit daemon in the kernel (audit_set_pid(3)) +func AuditSetPID(s Netlink, pid int) error { + var status auditStatus + status.Mask = AUDIT_STATUS_PID + status.Pid = uint32(pid) + return auditSendStatus(s, status) +} + +// AuditSetRateLimit sets the rate limit for audit messages from the kernel +func AuditSetRateLimit(s Netlink, limit int) error { + var status auditStatus + status.Mask = AUDIT_STATUS_RATE_LIMIT + status.RateLimit = uint32(limit) + return auditSendStatus(s, status) +} + +// AuditSetBacklogLimit sets the backlog limit for audit messages in the kernel +func AuditSetBacklogLimit(s Netlink, limit int) error { + var status auditStatus + status.Mask = AUDIT_STATUS_BACKLOG_LIMIT + status.BacklogLimit = uint32(limit) + return auditSendStatus(s, status) +} diff --git a/vendor/github.com/mozilla/libaudit-go/libaudit_test.go b/vendor/github.com/mozilla/libaudit-go/libaudit_test.go new file mode 100644 index 00000000..5f419e9a --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/libaudit_test.go @@ -0,0 +1,143 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package libaudit + +import ( + "bufio" + "bytes" + "math/rand" + "os" + "os/exec" + "strconv" + "strings" + "syscall" + "testing" + "time" +) + +func TestWireFormat(t *testing.T) { + rr := NetlinkMessage{} + rr.Header.Len = uint32(syscall.NLMSG_HDRLEN + 4) + rr.Header.Type = syscall.AF_NETLINK + rr.Header.Flags = syscall.NLM_F_REQUEST | syscall.NLM_F_ACK + rr.Header.Seq = 2 + + data := make([]byte, 4) + hostEndian.PutUint32(data, 12) + rr.Data = append(rr.Data[:], data[:]...) + + expected := []byte{20, 0, 0, 0, 16, 0, 5, 0, 2, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0} + result := rr.ToWireFormat() + if bytes.Compare(expected, result) != 0 { + t.Fatalf("ToWireFormat: resulting bytes unexpected") + } +} + +func TestNetlinkConnection(t *testing.T) { + if os.Getuid() != 0 { + t.Skipf("skipping test, not root user") + } + s, err := NewNetlinkConnection() + if err != nil { + t.Fatalf("NewNetlinkConnection: %v", err) + } + defer s.Close() + wb := newNetlinkAuditRequest(uint16(AUDIT_GET), syscall.AF_NETLINK, 0) + if err = s.Send(wb); err != nil { + t.Errorf("Send: %v", err) + } + _, err = auditGetReply(s, wb.Header.Seq, true) + if err != nil { + t.Errorf("TestNetlinkConnection: test failed %v", err) + } +} + +func TestSetters(t *testing.T) { + rand.Seed(time.Now().Unix()) + var ( + s *NetlinkConnection + pid = os.Getpid() + ratelimit = 20 + rand.Intn(480) + backlog = 20 + rand.Intn(480) + ) + if os.Getuid() != 0 { + t.Skipf("skipping test, not root user") + } + s, err := NewNetlinkConnection() + if err != nil { + t.Fatalf("NewNetlinkConnection: %v", err) + } + defer s.Close() + err = AuditSetEnabled(s, true) + if err != nil { + t.Fatalf("AuditSetEnabled: %v", err) + } + auditstatus, err := AuditIsEnabled(s) + if err != nil { + t.Fatalf("AuditIsEnabled: %v", err) + } + if !auditstatus { + t.Fatalf("AuditIsEnabled returned false") + } + err = AuditSetRateLimit(s, ratelimit) + if err != nil { + t.Fatalf("AuditSetRateLimit: %v", err) + } + err = AuditSetBacklogLimit(s, backlog) + if err != nil { + t.Fatalf("AuditSetBacklogLimit: %v", err) + } + err = AuditSetPID(s, pid) + if err != nil { + t.Fatalf("AuditSetPID: %v", err) + } + + // Use the external auditctl program to obtain the set values, and compare to what we + // expect + cmd := exec.Command("auditctl", "-s") + cmdOutput := &bytes.Buffer{} + cmd.Stdout = cmdOutput + if err := cmd.Run(); err != nil { + t.Fatalf("exec auditctl: %v", err) + } + + scanner := bufio.NewScanner(cmdOutput) + for scanner.Scan() { + args := strings.Split(scanner.Text(), " ") + if len(args) < 2 { + t.Fatalf("auditctl: malformed output %q", scanner.Text()) + } + switch args[0] { + case "enabled": + if args[1] != "1" { + t.Fatalf("enabled should have been 1") + } + case "pid": + v, err := strconv.Atoi(args[1]) + if err != nil { + t.Fatalf("pid argument was not an integer") + } + if v != pid { + t.Fatalf("pid should have been %v, was %v", pid, v) + } + case "rate_limit": + v, err := strconv.Atoi(args[1]) + if err != nil { + t.Fatalf("rate_limit argument was not an integer") + } + if v != ratelimit { + t.Fatalf("ratelimit should have been %v, was %v", ratelimit, v) + } + case "backlog_limit": + v, err := strconv.Atoi(args[1]) + if err != nil { + t.Fatalf("backlog_limit argument was not an integer") + } + if v != backlog { + t.Fatalf("backlog_limit should have been %v, was %v", backlog, v) + } + } + } +} diff --git a/vendor/github.com/mozilla/libaudit-go/lookup_tables.go b/vendor/github.com/mozilla/libaudit-go/lookup_tables.go new file mode 100644 index 00000000..595919be --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/lookup_tables.go @@ -0,0 +1,358 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package libaudit + +// fieldLookupMap is for interpreting field names in audit messages for their integer values +var fieldLookupMap = map[string]fieldType{ + "auid": typeUID, + "uid": typeUID, + "euid": typeUID, + "suid": typeUID, + "fsuid": typeUID, + "ouid": typeUID, + "oauid": typeUID, + "iuid": typeUID, + "id": typeUID, + "inode_uid": typeUID, + "sauid": typeUID, + "obj_uid": typeUID, + "obj_gid": typeGID, + "gid": typeGID, + "egid": typeGID, + "sgid": typeGID, + "fsgid": typeGID, + "ogid": typeGID, + "igid": typeGID, + "inode_gid": typeGID, + "new_gid": typeGID, + "syscall": typeSyscall, + "arch": typeArch, + "exit": typeExit, + "path": typeEscaped, + "comm": typeEscaped, + "exe": typeEscaped, + "file": typeEscaped, + "name": typeEscaped, + "watch": typeEscaped, + "cwd": typeEscaped, + "cmd": typeEscaped, + "acct": typeEscaped, + "dir": typeEscaped, + "key": typeEscaped, + "vm": typeEscaped, + "old-disk": typeEscaped, + "new-disk": typeEscaped, + "old-fs": typeEscaped, + "new-fs": typeEscaped, + "device": typeEscaped, + "cgroup": typeEscaped, + "perm": typePerm, + "perm_mask": typePerm, + "mode": typeMode, + "saddr": typeSockaddr, + "prom": typePromisc, + "old_prom": typePromisc, + "capability": typeCapability, + "res": typeSuccess, + "result": typeSuccess, + "a0": typeA0, + "a1": typeA1, + "a2": typeA2, + "a3": typeA3, + "sig": typeSignal, + "list": typeList, + "data": typeTTYData, + "ses": typeSession, + "cap_pi": typeCapBitmap, + "cap_pe": typeCapBitmap, + "cap_pp": typeCapBitmap, + "cap_fi": typeCapBitmap, + "cap_fp": typeCapBitmap, + "fp": typeCapBitmap, + "fi": typeCapBitmap, + "fe": typeCapBitmap, + "old_pp": typeCapBitmap, + "old_pi": typeCapBitmap, + "old_pe": typeCapBitmap, + "new_pp": typeCapBitmap, + "new_pi": typeCapBitmap, + "new_pe": typeCapBitmap, + "family": typeNFProto, + "icmptype": typeICMP, + "proto": typeProtocol, + "addr": typeAddr, + "apparmor": typeEscaped, + "operation": typeEscaped, + "denied_mask": typeEscaped, + "info": typeEscaped, + "profile": typeEscaped, + "requested_mask": typeEscaped, + "per": typePersonality, + "code": typeSeccomp, + "old-rng": typeEscaped, + "new-rng": typeEscaped, + "oflag": typeOFlag, + "ocomm": typeEscaped, + "flags": typeMmap, + "sigev_signo": typeEscaped, + "subj": typeMacLabel, + "obj": typeMacLabel, + "scontext": typeMacLabel, + "tcontext": typeMacLabel, + "vm-ctx": typeMacLabel, + "img-ctx": typeMacLabel, + "proctitle": typeProctile, + "grp": typeEscaped, + "new_group": typeEscaped, +} + +// actionLookup is for mapping audit actions applied on auditRuleData +var actionLookup = map[int]string{ + AUDIT_NEVER: "never", + AUDIT_POSSIBLE: "possible", + AUDIT_ALWAYS: "always", +} + +// flagLookup is for mapping flags applied on auditRuleData +var flagLookup = map[int]string{ + AUDIT_FILTER_TASK: "task", + AUDIT_FILTER_ENTRY: "entry", + AUDIT_FILTER_EXIT: "exit", + AUDIT_FILTER_USER: "user", + AUDIT_FILTER_EXCLUDE: "exclude", +} + +// opLookup is for mapping operators applied on auditRuleData +var opLookup = map[int]string{ + AUDIT_EQUAL: "=", + AUDIT_NOT_EQUAL: "!=", + AUDIT_GREATER_THAN: ">", + AUDIT_GREATER_THAN_OR_EQUAL: ">=", + AUDIT_LESS_THAN: "<", + AUDIT_LESS_THAN_OR_EQUAL: "<=", + AUDIT_BIT_MASK: "&", + AUDIT_BIT_TEST: "&=", +} + +// fieldLookup is for mapping fields applied on auditRuleData and also used for interpreting +// fields set in auditRuleData struct +var fieldLookup = map[int]string{ + AUDIT_PID: "pid", + AUDIT_UID: "uid", + AUDIT_EUID: "euid", + AUDIT_SUID: "suid", + AUDIT_FSUID: "fsuid", + AUDIT_GID: "gid", + AUDIT_EGID: "egid", + AUDIT_SGID: "sgid", + AUDIT_FSGID: "fsgid", + AUDIT_LOGINUID: "auid", + // AUDIT_LOGINUID: "loginuid", + AUDIT_PERS: "pers", + AUDIT_ARCH: "arch", + AUDIT_MSGTYPE: "msgtype", + AUDIT_SUBJ_USER: "subj_user", + AUDIT_SUBJ_ROLE: "subj_role", + AUDIT_SUBJ_TYPE: "subj_type", + AUDIT_SUBJ_SEN: "subj_sen", + AUDIT_SUBJ_CLR: "subj_clr", + AUDIT_PPID: "ppid", + AUDIT_OBJ_USER: "obj_user", + AUDIT_OBJ_ROLE: "obj_role", + AUDIT_OBJ_TYPE: "obj_type", + AUDIT_OBJ_LEV_LOW: "obj_lev_low", + AUDIT_OBJ_LEV_HIGH: "obj_lev_high", + AUDIT_DEVMAJOR: "devmajor", + AUDIT_DEVMINOR: "devminor", + AUDIT_INODE: "inode", + AUDIT_EXIT: "exit", + AUDIT_SUCCESS: "success", + AUDIT_WATCH: "path", + AUDIT_PERM: "perm", + AUDIT_DIR: "dir", + AUDIT_FILETYPE: "filetype", + AUDIT_OBJ_UID: "obj_uid", + AUDIT_OBJ_GID: "obj_gid", + AUDIT_FIELD_COMPARE: "field_compare", + AUDIT_ARG0: "a0", + AUDIT_ARG1: "a1", + AUDIT_ARG2: "a2", + AUDIT_ARG3: "a3", + AUDIT_FILTERKEY: "key", + AUDIT_EXE: "exe", +} + +// msgTypeTab is to look up audit header type based on string prefixes attached to audit messages +var msgTypeTab = map[string]auditConstant{ + "USER": AUDIT_USER, + "LOGIN": AUDIT_LOGIN, + "USER_AUTH": AUDIT_USER_AUTH, + "USER_ACCT": AUDIT_USER_ACCT, + "USER_MGMT": AUDIT_USER_MGMT, + "CRED_ACQ": AUDIT_CRED_ACQ, + "CRED_DISP": AUDIT_CRED_DISP, + "USER_START": AUDIT_USER_START, + "USER_END": AUDIT_USER_END, + "USER_AVC": AUDIT_USER_AVC, + "USER_CHAUTHTOK": AUDIT_USER_CHAUTHTOK, + "USER_ERR": AUDIT_USER_ERR, + "CRED_REFR": AUDIT_CRED_REFR, + "USYS_CONFIG": AUDIT_USYS_CONFIG, + "USER_LOGIN": AUDIT_USER_LOGIN, + "USER_LOGOUT": AUDIT_USER_LOGOUT, + "ADD_USER": AUDIT_ADD_USER, + "DEL_USER": AUDIT_DEL_USER, + "ADD_GROUP": AUDIT_ADD_GROUP, + "DEL_GROUP": AUDIT_DEL_GROUP, + "DAC_CHECK": AUDIT_DAC_CHECK, + "CHGRP_ID": AUDIT_CHGRP_ID, + "TEST": AUDIT_TEST, + "TRUSTED_APP": AUDIT_TRUSTED_APP, + "USER_SELINUX_ERR": AUDIT_USER_SELINUX_ERR, + "USER_CMD": AUDIT_USER_CMD, + "USER_TTY": AUDIT_USER_TTY, + "CHUSER_ID": AUDIT_CHUSER_ID, + "GRP_AUTH": AUDIT_GRP_AUTH, + "MAC_CHECK": AUDIT_MAC_CHECK, + "ACCT_LOCK": AUDIT_ACCT_LOCK, + "ACCT_UNLOCK": AUDIT_ACCT_UNLOCK, + "SYSTEM_BOOT": AUDIT_SYSTEM_BOOT, + "SYSTEM_SHUTDOWN": AUDIT_SYSTEM_SHUTDOWN, + "SYSTEM_RUNLEVEL": AUDIT_SYSTEM_RUNLEVEL, + "SERVICE_START": AUDIT_SERVICE_START, + "SERVICE_STOP": AUDIT_SERVICE_STOP, + "GRP_MGMT": AUDIT_GRP_MGMT, + "GRP_CHAUTHTOK": AUDIT_GRP_CHAUTHTOK, + // "DAEMON_START": AUDIT_DAEMON_START, + // "DAEMON_END": AUDIT_DAEMON_END, + // "DAEMON_ABORT": AUDIT_DAEMON_ABORT, + "DAEMON_CONFIG": AUDIT_DAEMON_CONFIG, + "DAEMON_RECONFIG": AUDIT_DAEMON_RECONFIG, + "DAEMON_ROTATE": AUDIT_DAEMON_ROTATE, + "DAEMON_RESUME": AUDIT_DAEMON_RESUME, + "DAEMON_ACCEPT": AUDIT_DAEMON_ACCEPT, + "DAEMON_CLOSE": AUDIT_DAEMON_CLOSE, + // "DAEMON_ERR": AUDIT_DAEMON_ERR, + "SYSCALL": AUDIT_SYSCALL, + // "FS_WATCH": AUDIT_FS_WATCH, + "PATH": AUDIT_PATH, + "IPC": AUDIT_IPC, + "SOCKETCALL": AUDIT_SOCKETCALL, + "CONFIG_CHANGE": AUDIT_CONFIG_CHANGE, + "SOCKADDR": AUDIT_SOCKADDR, + "CWD": AUDIT_CWD, + // "FS_INODE": AUDIT_FS_INODE, + "EXECVE": AUDIT_EXECVE, + "IPC_SET_PERM": AUDIT_IPC_SET_PERM, + "MQ_OPEN": AUDIT_MQ_OPEN, + "MQ_SENDRECV": AUDIT_MQ_SENDRECV, + "MQ_NOTIFY": AUDIT_MQ_NOTIFY, + "MQ_GETSETATTR": AUDIT_MQ_GETSETATTR, + "KERNEL_OTHER": AUDIT_KERNEL_OTHER, + "FD_PAIR": AUDIT_FD_PAIR, + "OBJ_PID": AUDIT_OBJ_PID, + "TTY": AUDIT_TTY, + "EOE": AUDIT_EOE, + "BPRM_FCAPS": AUDIT_BPRM_FCAPS, + "CAPSET": AUDIT_CAPSET, + "MMAP": AUDIT_MMAP, + "NETFILTER_PKT": AUDIT_NETFILTER_PKT, + "NETFILTER_CFG": AUDIT_NETFILTER_CFG, + "SECCOMP": AUDIT_SECCOMP, + "PROCTITLE": AUDIT_PROCTITLE, + "FEATURE_CHANGE": AUDIT_FEATURE_CHANGE, + "AVC": AUDIT_AVC, + "SELINUX_ERR": AUDIT_SELINUX_ERR, + "AVC_PATH": AUDIT_AVC_PATH, + "MAC_POLICY_LOAD": AUDIT_MAC_POLICY_LOAD, + "MAC_STATUS": AUDIT_MAC_STATUS, + "MAC_CONFIG_CHANGE": AUDIT_MAC_CONFIG_CHANGE, + "MAC_UNLBL_ALLOW": AUDIT_MAC_UNLBL_ALLOW, + "MAC_CIPSOV4_ADD": AUDIT_MAC_CIPSOV4_ADD, + "MAC_CIPSOV4_DEL": AUDIT_MAC_CIPSOV4_DEL, + "MAC_MAP_ADD": AUDIT_MAC_MAP_ADD, + "MAC_MAP_DEL": AUDIT_MAC_MAP_DEL, + "MAC_IPSEC_ADDSA": AUDIT_MAC_IPSEC_ADDSA, + "MAC_IPSEC_DELSA": AUDIT_MAC_IPSEC_DELSA, + "MAC_IPSEC_ADDSPD": AUDIT_MAC_IPSEC_ADDSPD, + "MAC_IPSEC_DELSPD": AUDIT_MAC_IPSEC_DELSPD, + "MAC_IPSEC_EVENT": AUDIT_MAC_IPSEC_EVENT, + "MAC_UNLBL_STCADD": AUDIT_MAC_UNLBL_STCADD, + "MAC_UNLBL_STCDEL": AUDIT_MAC_UNLBL_STCDEL, + "ANOM_PROMISCUOUS": AUDIT_ANOM_PROMISCUOUS, + "ANOM_ABEND": AUDIT_ANOM_ABEND, + "ANOM_LINK": AUDIT_ANOM_LINK, + "INTEGRITY_DATA": AUDIT_INTEGRITY_DATA, + "INTEGRITY_METADATA": AUDIT_INTEGRITY_METADATA, + "INTEGRITY_STATUS": AUDIT_INTEGRITY_STATUS, + "INTEGRITY_HASH": AUDIT_INTEGRITY_HASH, + "INTEGRITY_PCR": AUDIT_INTEGRITY_PCR, + "INTEGRITY_RULE": AUDIT_INTEGRITY_RULE, + "APPARMOR": AUDIT_AA, + "APPARMOR_AUDIT": AUDIT_APPARMOR_AUDIT, + "APPARMOR_ALLOWED": AUDIT_APPARMOR_ALLOWED, + "APPARMOR_DENIED": AUDIT_APPARMOR_DENIED, + // "APPARMOR_HINT": AUDIT_APPARMOR_HINT, + "APPARMOR_STATUS": AUDIT_APPARMOR_STATUS, + "APPARMOR_ERROR": AUDIT_APPARMOR_ERROR, + "KERNEL": AUDIT_KERNEL, + "ANOM_LOGIN_FAILURES": AUDIT_ANOM_LOGIN_FAILURES, + "ANOM_LOGIN_TIME": AUDIT_ANOM_LOGIN_TIME, + "ANOM_LOGIN_SESSIONS": AUDIT_ANOM_LOGIN_SESSIONS, + "ANOM_LOGIN_ACCT": AUDIT_ANOM_LOGIN_ACCT, + "ANOM_LOGIN_LOCATION": AUDIT_ANOM_LOGIN_LOCATION, + "ANOM_MAX_DAC": AUDIT_ANOM_MAX_DAC, + "ANOM_MAX_MAC": AUDIT_ANOM_MAX_MAC, + "ANOM_AMTU_FAIL": AUDIT_ANOM_AMTU_FAIL, + "ANOM_RBAC_FAIL": AUDIT_ANOM_RBAC_FAIL, + "ANOM_RBAC_INTEGRITY_FAIL": AUDIT_ANOM_RBAC_INTEGRITY_FAIL, + "ANOM_CRYPTO_FAIL": AUDIT_ANOM_CRYPTO_FAIL, + "ANOM_ACCESS_FS": AUDIT_ANOM_ACCESS_FS, + "ANOM_EXEC": AUDIT_ANOM_EXEC, + "ANOM_MK_EXEC": AUDIT_ANOM_MK_EXEC, + "ANOM_ADD_ACCT": AUDIT_ANOM_ADD_ACCT, + "ANOM_DEL_ACCT": AUDIT_ANOM_DEL_ACCT, + "ANOM_MOD_ACCT": AUDIT_ANOM_MOD_ACCT, + "ANOM_ROOT_TRANS": AUDIT_ANOM_ROOT_TRANS, + "RESP_ANOMALY": AUDIT_RESP_ANOMALY, + "RESP_ALERT": AUDIT_RESP_ALERT, + "RESP_KILL_PROC": AUDIT_RESP_KILL_PROC, + "RESP_TERM_ACCESS": AUDIT_RESP_TERM_ACCESS, + "RESP_ACCT_REMOTE": AUDIT_RESP_ACCT_REMOTE, + "RESP_ACCT_LOCK_TIMED": AUDIT_RESP_ACCT_LOCK_TIMED, + "RESP_ACCT_UNLOCK_TIMED": AUDIT_RESP_ACCT_UNLOCK_TIMED, + "RESP_ACCT_LOCK": AUDIT_RESP_ACCT_LOCK, + "RESP_TERM_LOCK": AUDIT_RESP_TERM_LOCK, + "RESP_SEBOOL": AUDIT_RESP_SEBOOL, + "RESP_EXEC": AUDIT_RESP_EXEC, + "RESP_SINGLE": AUDIT_RESP_SINGLE, + "RESP_HALT": AUDIT_RESP_HALT, + "USER_ROLE_CHANGE": AUDIT_USER_ROLE_CHANGE, + "ROLE_ASSIGN": AUDIT_ROLE_ASSIGN, + "ROLE_REMOVE": AUDIT_ROLE_REMOVE, + "LABEL_OVERRIDE": AUDIT_LABEL_OVERRIDE, + "LABEL_LEVEL_CHANGE": AUDIT_LABEL_LEVEL_CHANGE, + "USER_LABELED_EXPORT": AUDIT_USER_LABELED_EXPORT, + "USER_UNLABELED_EXPORT": AUDIT_USER_UNLABELED_EXPORT, + "DEV_ALLOC": AUDIT_DEV_ALLOC, + "DEV_DEALLOC": AUDIT_DEV_DEALLOC, + "FS_RELABEL": AUDIT_FS_RELABEL, + "USER_MAC_POLICY_LOAD": AUDIT_USER_MAC_POLICY_LOAD, + "ROLE_MODIFY": AUDIT_ROLE_MODIFY, + "USER_MAC_CONFIG_CHANGE": AUDIT_USER_MAC_CONFIG_CHANGE, + "CRYPTO_TEST_USER": AUDIT_CRYPTO_TEST_USER, + "CRYPTO_PARAM_CHANGE_USER": AUDIT_CRYPTO_PARAM_CHANGE_USER, + "CRYPTO_LOGIN": AUDIT_CRYPTO_LOGIN, + "CRYPTO_LOGOUT": AUDIT_CRYPTO_LOGOUT, + "CRYPTO_KEY_USER": AUDIT_CRYPTO_KEY_USER, + "CRYPTO_FAILURE_USER": AUDIT_CRYPTO_FAILURE_USER, + "CRYPTO_REPLAY_USER": AUDIT_CRYPTO_REPLAY_USER, + "CRYPTO_SESSION": AUDIT_CRYPTO_SESSION, + "CRYPTO_IKE_SA": AUDIT_CRYPTO_IKE_SA, + "CRYPTO_IPSEC_SA": AUDIT_CRYPTO_IPSEC_SA, + "VIRT_CONTROL": AUDIT_VIRT_CONTROL, + "VIRT_RESOURCE": AUDIT_VIRT_RESOURCE, + "VIRT_MACHINE_ID": AUDIT_VIRT_MACHINE_ID, +} diff --git a/vendor/github.com/mozilla/libaudit-go/parser.go b/vendor/github.com/mozilla/libaudit-go/parser.go new file mode 100644 index 00000000..a1624b11 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/parser.go @@ -0,0 +1,292 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package libaudit + +import ( + "fmt" + "strconv" + "strings" +) + +type record struct { + syscallNum string + arch string + a0 int + a1 int +} + +// ErrorAuditParse is an implementation of the error interface that is returned by +// ParseAuditEvent. msg will contain a description of the error, and the raw audit event +// which failed parsing is returned in raw for inspection by the calling program. +type ErrorAuditParse struct { + Msg string + Raw string +} + +// Error returns a string representation of ErrorAuditParse e +func (e ErrorAuditParse) Error() string { + return e.Msg +} + +// newErrorAuditParse returns a new ErrorAuditParse type with the fields populated +func newErrorAuditParse(raw string, f string, v ...interface{}) ErrorAuditParse { + ret := ErrorAuditParse{ + Raw: raw, + Msg: fmt.Sprintf(f, v...), + } + return ret +} + +// ParseAuditEvent parses an incoming audit message from kernel and returns an AuditEvent. +// +// msgType is supposed to come from the calling function which holds the msg header indicating header +// type of the messages. It uses simple string parsing techniques and provider better performance than +// the regex parser, idea taken from parse_up_record(rnode* r) in ellist.c (libauparse). +func ParseAuditEvent(str string, msgType auditConstant, interpret bool) (*AuditEvent, error) { + var r record + var event = AuditEvent{ + Raw: str, + } + + // Create the map which will store the audit record fields for this event, note we + // provide an allocation hint here based on the average number of fields we would come + // across in an audit event + m := make(map[string]string, 24) + + if strings.HasPrefix(str, "audit(") { + str = str[6:] + } else { + return nil, newErrorAuditParse(event.Raw, "malformed, missing audit prefix") + } + index := strings.Index(str, ":") + if index == -1 { + return nil, newErrorAuditParse(event.Raw, "malformed, can't locate start of fields") + } + + // determine timestamp + timestamp := str[:index] + // move further on string, skipping ':' + str = str[index+1:] + index = strings.Index(str, ")") + if index == -1 { + return nil, newErrorAuditParse(event.Raw, "malformed, can't locate end of prefix") + } + serial := str[:index] + if strings.HasPrefix(str, serial+"): ") { + str = str[index+3:] + } else { + return nil, newErrorAuditParse(event.Raw, "malformed, prefix termination unexpected") + } + + var ( + nBytes string + orig = len(str) + n int + key string + value string + av bool + ) + + for n < orig { + getSpaceSlice(&str, &nBytes, &n) + var newIndex int + newIndex = strings.Index(nBytes, "=") + if newIndex == -1 { + // check type for special cases of AVC and USER_AVC + if msgType == AUDIT_AVC || msgType == AUDIT_USER_AVC { + if nBytes == "avc:" && strings.HasPrefix(str, "avc:") { + // skip over 'avc:' + str = str[len(nBytes)+1:] + av = true + continue + } + if av { + key = "seresult" + value = nBytes + if interpret { + var err error + value, err = interpretField(key, value, msgType, r) + if err != nil { + return nil, newErrorAuditParse(event.Raw, "interpretField: %v", err) + } + } + m[key] = value + av = false + if len(str) == len(nBytes) { + break + } else { + str = str[len(nBytes)+1:] + } + continue + } + if strings.HasPrefix(nBytes, "{") { + key = "seperms" + str = str[len(nBytes)+1:] + var v string + getSpaceSlice(&str, &nBytes, &n) + for nBytes != "}" { + if len(v) != 0 { + v += "," + } + v += nBytes + str = str[len(nBytes)+1:] + getSpaceSlice(&str, &nBytes, &n) + } + value = v + if interpret { + var err error + value, err = interpretField(key, value, msgType, r) + if err != nil { + return nil, newErrorAuditParse(event.Raw, "interpretField: %v", err) + } + } + m[key] = value + fixPunctuations(&value) + if len(str) == len(nBytes) { + //reached the end of message + break + } else { + str = str[len(nBytes)+1:] + } + continue + } else { + // We might get values with space, add it to prev key + // skip 'for' in avc message (special case) + if nBytes == "for" { + str = str[len(nBytes)+1:] + continue + } + value += " " + nBytes + fixPunctuations(&value) + if interpret { + var err error + value, err = interpretField(key, value, msgType, r) + if err != nil { + return nil, newErrorAuditParse(event.Raw, "interpretField: %v", err) + } + } + m[key] = value + } + } else { + // We might get values with space, add it to prev key + value += " " + nBytes + fixPunctuations(&value) + if interpret { + var err error + value, err = interpretField(key, value, msgType, r) + if err != nil { + return nil, newErrorAuditParse(event.Raw, "interpretField: %v", err) + } + } + m[key] = value + } + + } else { + key = nBytes[:newIndex] + value = nBytes[newIndex+1:] + // for cases like msg=' + // we look again for key value pairs + if strings.HasPrefix(value, "'") && key == "msg" { + newIndex = strings.Index(value, "=") + if newIndex == -1 { + // special case USER_AVC messages, start of: msg='avc: + if strings.HasPrefix(str, "msg='avc") { + str = str[5:] + } + continue + } + key = value[1:newIndex] + value = value[newIndex+1:] + } + + fixPunctuations(&value) + if key == "arch" { + // determine machine type + } + if key == "a0" { + val, err := strconv.ParseInt(value, 16, 64) + if err != nil { + r.a0 = -1 + } else { + r.a0 = int(val) + } + } + if key == "a1" { + val, err := strconv.ParseInt(value, 16, 64) + if err != nil { + r.a1 = -1 + } else { + r.a1 = int(val) + } + } + if key == "syscall" { + r.syscallNum = value + } + if interpret { + var err error + value, err = interpretField(key, value, msgType, r) + if err != nil { + return nil, newErrorAuditParse(event.Raw, "interpretField: %v", err) + } + } + m[key] = value + } + if len(str) == len(nBytes) { + // Reached the end of message + break + } else { + str = str[len(nBytes)+1:] + } + + } + + event.Timestamp = timestamp + event.Serial = serial + event.Data = m + event.Type = msgType.String()[6:] + return &event, nil + +} + +// getSpaceSlice checks the index of the next space and put the string up to that space into +// the second string, total number of characters processed is updated with each call to the function +func getSpaceSlice(str *string, b *string, v *int) { + index := strings.Index(*str, " ") + if index != -1 { + if index == 0 { + // Found space on the first location only, just forward on the orig + // string and try again + *str = (*str)[1:] + getSpaceSlice(str, b, v) + } else { + *b = (*str)[:index] + // Keep updating total characters processed + *v += len(*b) + } + } else { + *b = (*str) + // Keep updating total characters processed + *v += len(*b) + } +} + +func fixPunctuations(value *string) { + // Remove trailing punctuation + l := len(*value) + if l > 0 && strings.HasSuffix(*value, "'") { + *value = (*value)[:l-1] + l-- + } + if l > 0 && strings.HasSuffix(*value, ",") { + *value = (*value)[:l-1] + l-- + } + if l > 0 && strings.HasSuffix(*value, ")") { + if *value != "(none)" && *value != "(null)" { + *value = (*value)[:l-1] + l-- + } + } +} diff --git a/vendor/github.com/mozilla/libaudit-go/parser_test.go b/vendor/github.com/mozilla/libaudit-go/parser_test.go new file mode 100644 index 00000000..8aaccc5c --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/parser_test.go @@ -0,0 +1,340 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package libaudit + +import ( + "reflect" + "testing" +) + +var auditTests = []struct { + msg string + msgType auditConstant + expected error + match bool + event AuditEvent +}{ + { + `audit(1226874073.147:96): avc: denied { getattr } for pid=2465 comm="httpd" path="/var/www/html/file1 space" dev=dm-0 ino=284133 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:samba_share_t:s0 tclass=file`, + AUDIT_AVC, + nil, + true, + AuditEvent{ + Serial: "96", + Timestamp: "1226874073.147", + Type: "AVC", + Data: map[string]string{ + "path": `"/var/www/html/file1 space"`, "dev": "dm-0", "ino": "284133", "scontext": "unconfined_u:system_r:httpd_t:s0", "tcontext": "unconfined_u:object_r:samba_share_t:s0", "pid": "2465", "seperms": "getattr", "comm": `"httpd"`, "tclass": "file", "seresult": "denied"}, + }, + }, + { + `audit(1464176620.068:1445): auid=4294967295 uid=1000 gid=1000 ses=4294967295 pid=23975 comm="chrome" exe="/opt/google/chrome/chrome" sig=0 arch=c000003e syscall=273 compat=0 ip=0x7f1da6d8b694 code=0x50000`, + AUDIT_AVC, + nil, + true, + AuditEvent{ + Serial: "1445", + Timestamp: "1464176620.068", + Type: "AVC", + Data: map[string]string{ + "comm": `"chrome"`, "exe": `"/opt/google/chrome/chrome"`, "arch": "c000003e", "compat": "0", "code": "0x50000", "ses": "4294967295", "uid": "1000", "gid": "1000", "pid": "23975", "sig": "0", "syscall": "273", "ip": "0x7f1da6d8b694", "auid": "4294967295"}, + }, + }, + {`audit(1464163771.720:20): arch=c000003e syscall=1 success=yes exit=658651 a0=6 a1=7f26862ea010 a2=a0cdb a3=0 items=0 ppid=712 pid=716 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="apparmor_parser" exe="/sbin/apparmor_parser" key=(null)`, + AUDIT_AVC, + nil, + true, + AuditEvent{ + Serial: "20", + Timestamp: "1464163771.720", + Type: "AVC", + Data: map[string]string{ + "success": "yes", "a2": "a0cdb", "uid": "0", "sgid": "0", "fsgid": "0", "ses": "4294967295", "exit": "658651", "a0": "6", "ppid": "712", "suid": "0", "key": "(null)", "tty": "(none)", "comm": `"apparmor_parser"`, "arch": "c000003e", "syscall": "1", "a1": "7f26862ea010", "items": "0", "pid": "716", "fsuid": "0", "exe": `"/sbin/apparmor_parser"`, "a3": "0", "auid": "4294967295", "gid": "0", "euid": "0", "egid": "0"}, + }, + }, + {`audit(1464093935.845:993): pid=4148 uid=0 auid=4294967295 ses=4294967295 msg='op=PAM:setcred acct="root" exe="/usr/bin/sudo" hostname=? addr=? terminal=/dev/pts/18 res=success'`, + AUDIT_AVC, + nil, + true, + AuditEvent{ + Serial: "993", + Timestamp: "1464093935.845", + Type: "AVC", + Data: map[string]string{ + "op": "PAM:setcred", "acct": `"root"`, "hostname": "?", "addr": "?", "res": "success", "uid": "0", "auid": "4294967295", "exe": `"/usr/bin/sudo"`, "terminal": "/dev/pts/18", "pid": "4148", "ses": "4294967295"}, + }, + }, + { + `audit(1267534395.930:19): user pid=1169 uid=0 auid=4294967295 ses=4294967295 subj=system_u:unconfined_r:unconfined_t msg='avc: denied { read } for request=SELinux:SELinuxGetClientContext comm=X-setest resid=3c00001 restype= scontext=unconfined_u:unconfined_r:x_select_paste_t tcontext=unconfined_u:unconfined_r:unconfined_t tclass=x_resource : exe="/usr/bin/Xorg " sauid=0 hostname=? addr=? terminal=?'`, + AUDIT_AVC, + nil, + true, + AuditEvent{ + Serial: "19", + Timestamp: "1267534395.930", + Type: "AVC", + Data: map[string]string{ + "": " user", "uid": "0", "subj": "system_u:unconfined_r:unconfined_t", "scontext": "unconfined_u:unconfined_r:x_select_paste_t", "ses": "4294967295", "comm": "X-setest", "sauid": "0", "addr": "?", "pid": "1169", "auid": "4294967295", "request": "SELinux:SELinuxGetClientContext", "resid": "3c00001", "restype": "", "hostname": "?", "terminal": "?", "seresult": "denied", "seperms": "read", "tcontext": "unconfined_u:unconfined_r:unconfined_t", "tclass": "x_resource :", "exe": `"/usr/bin/Xorg "`}, + }, + }, + { + `audit(1464617439.911:1421): pid=30576 uid=0 auid=4294967295 ses=4294967295 msg='op=PAM:setcred acct="root" exe="/usr/bin/sudo" hostname=? addr=? terminal=/dev/pts/18 res=success'`, + AUDIT_AVC, + nil, + true, + AuditEvent{ + Serial: "1421", + Timestamp: "1464617439.911", + Type: "AVC", + Data: map[string]string{ + "pid": "30576", "auid": "4294967295", "exe": `"/usr/bin/sudo"`, "addr": "?", "terminal": "/dev/pts/18", "uid": "0", "ses": "4294967295", "op": "PAM:setcred", "acct": `"root"`, "hostname": "?", "res": "success"}, + }, + }, + { + `audit(1464617439.911:1422): pid=30576 uid=0 auid=4294967295 ses=4294967295 msg='op=PAM:session_open acct="root" exe="/usr/bin/sudo" hostname=? addr=? terminal=/dev/pts/18 res=success'`, + AUDIT_AVC, + nil, + true, + AuditEvent{ + Serial: "1422", + Timestamp: "1464617439.911", + Type: "AVC", + Data: map[string]string{ + "uid": "0", "auid": "4294967295", "ses": "4294967295", "op": "PAM:session_open", "exe": `"/usr/bin/sudo"`, "addr": "?", "terminal": "/dev/pts/18", "pid": "30576", "res": "success", "hostname": "?", "acct": `"root"`}, + }, + }, + { + `audit(1464617444.219:1425): pid=30579 uid=1000 auid=4294967295 ses=4294967295 msg='cwd="/home/arun/Work/go-ground/src/github.com/arunk-s/parser" cmd=636174202F7661722F6C6F672F61756469742F61756469742E6C6F67 terminal=pts/18 res=success'`, + AUDIT_AVC, + nil, + true, + AuditEvent{ + Serial: "1425", + Timestamp: "1464617444.219", + Type: "AVC", + Data: map[string]string{ + "auid": "4294967295", "ses": "4294967295", "cwd": `"/home/arun/Work/go-ground/src/github.com/arunk-s/parser"`, "cmd": "636174202F7661722F6C6F672F61756469742F61756469742E6C6F67", "terminal": "pts/18", "res": "success", "pid": "30579", "uid": "1000"}, + }, + }, + { + `audit(1464617461.107:1431): pid=30586 uid=0 auid=4294967295 ses=4294967295 msg='op=PAM:setcred acct="root" exe="/usr/bin/sudo" hostname=? addr=? terminal=/dev/pts/18 res=success'`, + AUDIT_AVC, + nil, + true, + AuditEvent{ + Serial: "1431", + Timestamp: "1464617461.107", + Type: "AVC", + Data: map[string]string{ + "exe": `"/usr/bin/sudo"`, "hostname": "?", "addr": "?", "terminal": "/dev/pts/18", "res": "success", "pid": "30586", "uid": "0", "auid": "4294967295", "ses": "4294967295", "op": "PAM:setcred", "acct": `"root"`}, + }, + }, + { + `audit(1464614823.239:1290): pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=NetworkManager-dispatcher comm="systemd" exe="/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'`, + AUDIT_AVC, + nil, + true, + AuditEvent{ + Serial: "1290", + Timestamp: "1464614823.239", + Type: "AVC", + Data: map[string]string{ + "hostname": "?", "addr": "?", "res": "success", "auid": "4294967295", "ses": "4294967295", "unit": "NetworkManager-dispatcher", "comm": `"systemd"`, "exe": `"/lib/systemd/systemd"`, "pid": "1", "uid": "0", "terminal": "?"}, + }, + }, + { + `audit(1464614843.495:1292): pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=systemd-rfkill comm="systemd" exe="/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'`, + AUDIT_AVC, + nil, + true, + AuditEvent{ + Serial: "1292", + Timestamp: "1464614843.495", + Type: "AVC", + Data: map[string]string{ + "pid": "1", "auid": "4294967295", "ses": "4294967295", "unit": "systemd-rfkill", "comm": `"systemd"`, "exe": `"/lib/systemd/systemd"`, "hostname": "?", "res": "success", "uid": "0", "addr": "?", "terminal": "?"}, + }, + }, + { + `audit(1464590772.564:302): auid=4294967295 uid=1000 gid=1000 ses=4294967295 pid=5803 comm="chrome" exe="/opt/google/chrome/chrome" sig=0 arch=c000003e syscall=273 compat=0 ip=0x7f3deee65694 code=0x50000`, + AUDIT_AVC, + nil, + true, + AuditEvent{ + Serial: "302", + Timestamp: "1464590772.564", + Type: "AVC", + Data: map[string]string{ + "pid": "5803", "comm": `"chrome"`, "syscall": "273", "ip": "0x7f3deee65694", "gid": "1000", "uid": "1000", "ses": "4294967295", "exe": `"/opt/google/chrome/chrome"`, "sig": "0", "arch": "c000003e", "compat": "0", "code": "0x50000", "auid": "4294967295"}, + }, + }, + { + `audit(1464505771.166:388): pid=1 uid=0 auid=4294967295 ses=4294967295'unit=NetworkManager-dispatcher comm="systemd" exe="/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'`, + AUDIT_AVC, + nil, + true, + AuditEvent{ + Serial: "388", + Timestamp: "1464505771.166", + Type: "AVC", + Data: map[string]string{ + "pid": "1", "hostname": "?", "res": "success", "terminal": "?", "uid": "0", "auid": "4294967295", "ses": "4294967295'unit=NetworkManager-dispatcher", "comm": `"systemd"`, "exe": `"/lib/systemd/systemd"`, "addr": "?"}, + }, + }, + { + `audit(1464505794.710:389): auid=4294967295 uid=1000 gid=1000 ses=4294967295 pid=4075 comm="Chrome_libJingl" exe="/opt/google/chrome/chrome" sig=0 arch=c000003e syscall=273 compat=0 ip=0x7fb359e4d694 code=0x50000`, + AUDIT_AVC, + nil, + true, + AuditEvent{ + Serial: "389", + Timestamp: "1464505794.710", + Type: "AVC", + Data: map[string]string{ + "auid": "4294967295", "comm": `"Chrome_libJingl"`, "sig": "0", "arch": "c000003e", "ip": "0x7fb359e4d694", "code": "0x50000", "uid": "1000", "gid": "1000", "ses": "4294967295", "pid": "4075", "exe": `"/opt/google/chrome/chrome"`, "syscall": "273", "compat": "0"}, + }, + }, + { + `audit(1464505808.342:401): auid=4294967295 uid=1000 gid=1000 ses=4294967295 pid=4076 comm="Chrome_libJingl" exe="/opt/google/chrome/chrome" sig=0 arch=c000003e syscall=273 compat=0 ip=0x7fb359e4d694 code=0x50000`, + AUDIT_AVC, + nil, + true, + AuditEvent{ + Serial: "401", + Timestamp: "1464505808.342", + Type: "AVC", + Data: map[string]string{ + "pid": "4076", "comm": `"Chrome_libJingl"`, "exe": `"/opt/google/chrome/chrome"`, "sig": "0", "syscall": "273", "compat": "0", "code": "0x50000", "ses": "4294967295", "uid": "1000", "gid": "1000", "arch": "c000003e", "ip": "0x7fb359e4d694", "auid": "4294967295"}, + }, + }, + { + `audit(1464505810.566:403): auid=4294967295 uid=1000 gid=1000 ses=4294967295 pid=4078 comm="chrome" exe="/opt/google/chrome/chrome" sig=0 arch=c000003e syscall=273 compat=0 ip=0x7fb359e4d694 code=0x50000`, + AUDIT_AVC, + nil, + true, + AuditEvent{ + Serial: "403", + Timestamp: "1464505810.566", + Type: "AVC", + Data: map[string]string{ + "auid": "4294967295", "exe": `"/opt/google/chrome/chrome"`, "sig": "0", "arch": "c000003e", "syscall": "273", "compat": "0", "code": "0x50000", "uid": "1000", "gid": "1000", "ses": "4294967295", "pid": "4078", "comm": `"chrome"`, "ip": "0x7fb359e4d694"}, + }, + }, + { + `audit(1464505927.046:474): pid=1 uid=0 auid=4294967295 ses=4294967295 unit=lm-sensors comm="systemd" exe="/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'`, + AUDIT_AVC, + nil, + true, + AuditEvent{ + Serial: "474", + Timestamp: "1464505927.046", + Type: "AVC", + Data: map[string]string{ + "uid": "0", "exe": `"/lib/systemd/systemd"`, "hostname": "?", "addr": "?", "terminal": "?", "res": "success", "pid": "1", "auid": "4294967295", "ses": "4294967295", "unit": "lm-sensors", "comm": `"systemd"`}, + }, + }, + { + `audit(1464505927.314:508): pid=1 uid=0 auid=4294967295 ses=4294967295 unit=rc-local comm="systemd" exe="/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'`, + AUDIT_AVC, + nil, + true, + AuditEvent{ + Serial: "508", + Timestamp: "1464505927.314", + Type: "AVC", + Data: map[string]string{ + "pid": "1", "hostname": "?", "addr": "?", "unit": "rc-local", "comm": `"systemd"`, "exe": `"/lib/systemd/systemd"`, "terminal": "?", "res": "success", "uid": "0", "auid": "4294967295", "ses": "4294967295"}, + }, + }, + { + `audit(1464550921.784:3509): auid=4294967295 uid=1000 gid=1000 ses=4294967295 pid=14869 comm="chrome" exe="/opt/google/chrome/chrome" sig=0 arch=c000003e syscall=273 compat=0 ip=0x7f26b8828694 code=0x50000`, + AUDIT_AVC, + nil, + true, + AuditEvent{ + Serial: "3509", + Timestamp: "1464550921.784", + Type: "AVC", + Data: map[string]string{ + "syscall": "273", "compat": "0", "ip": "0x7f26b8828694", "code": "0x50000", "auid": "4294967295", "uid": "1000", "gid": "1000", "sig": "0", "arch": "c000003e", "ses": "4294967295", "pid": "14869", "comm": `"chrome"`, "exe": `"/opt/google/chrome/chrome"`}, + }, + }, + { + `audit(1170021493.977:293): avc: denied { read write } for pid=13010 comm="pickup" name="maildrop" dev=hda7 ino=14911367 scontext=system_u:system_r:postfix_pickup_t:s0 tcontext=system_u:object_r:postfix_spool_maildrop_t:s0 tclass=dir`, + AUDIT_AVC, + nil, + true, + AuditEvent{ + Serial: "293", + Timestamp: "1170021493.977", + Type: "AVC", + Data: map[string]string{ + "scontext": "system_u:system_r:postfix_pickup_t:s0", "seresult": "denied", "comm": `"pickup"`, "name": `"maildrop"`, "dev": "hda7", "ino": "14911367", "tcontext": "system_u:object_r:postfix_spool_maildrop_t:s0", "tclass": "dir", "seperms": "read,write", "pid": "13010"}, + }, + }, +} + +func TestMalformedPrefix(t *testing.T) { + tmsg := []struct { + msg string + msgType auditConstant + err string + }{ + {"xyzabc", AUDIT_AVC, "malformed, missing audit prefix"}, + {`audit(1464163771`, AUDIT_AVC, "malformed, can't locate start of fields"}, + {`audit(1464176620.068:1445`, AUDIT_AVC, "malformed, can't locate end of prefix"}, + } + for _, m := range tmsg { + _, err := ParseAuditEvent(m.msg, m.msgType, false) + if err == nil { + t.Fatalf("ParseAuditEvent should have failed on %q", m.msg) + } + if err.Error() != m.err { + t.Fatalf("ParseAuditEvent failed, but error %q was unexpected", err) + } + } +} + +func TestNativeParser(t *testing.T) { + for i, tt := range auditTests { + x, err := ParseAuditEvent(tt.msg, tt.msgType, false) + if err != tt.expected { + t.Fatalf("ParseAuditEvent: event %v had unexpected error value", i) + } + if tt.match { + checkEvent(i, &tt.event, x, t) + } + } +} + +func BenchmarkNativeParser(b *testing.B) { + for n := 0; n < b.N; n++ { + ParseAuditEvent(`audit(1226874073.147:96): avc: denied { getattr } for pid=2465 comm="httpd" path="/var/www/html/file1 space" dev=dm-0 ino=284133 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:samba_share_t:s0 tclass=file`, AUDIT_AVC, true) + } +} + +func BenchmarkNativeParserTable(b *testing.B) { + for n := 0; n < b.N; n++ { + for _, x := range auditTests { + ParseAuditEvent(x.msg, AUDIT_AVC, true) + } + } +} + +// checkEvent compares auditEvent a to b, ensuring they are identical. +func checkEvent(eventid int, a *AuditEvent, b *AuditEvent, t *testing.T) { + if a.Serial != b.Serial { + t.Fatalf("audit event %v serial did not match", eventid) + } + if a.Timestamp != b.Timestamp { + t.Fatalf("audit event %v timestamp did not match", eventid) + } + if a.Type != b.Type { + t.Fatalf("audit event %v type did not match", eventid) + } + if !reflect.DeepEqual(a.Data, b.Data) { + t.Fatalf("audit event %v data was not equal", eventid) + } +} diff --git a/vendor/github.com/mozilla/libaudit-go/rules.go b/vendor/github.com/mozilla/libaudit-go/rules.go new file mode 100644 index 00000000..abd68ace --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/rules.go @@ -0,0 +1,1131 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package libaudit + +import ( + "bytes" + "encoding/binary" + "encoding/json" + "errors" + "fmt" + "os" + "os/user" + "path" + "runtime" + "strconv" + "strings" + "syscall" + + "github.com/lunixbochs/struc" + "github.com/mozilla/libaudit-go/headers" +) + +// AuditRules describes a set of audit rules in JSON format +type AuditRules struct { + RawRules interface{} `json:"audit_rules"` + Delete bool `json:"delete"` + Enable string `json:"enable"` + Buffer string `json:"buffer"` + Rate string `json:"rate"` + + AuditRules []AuditRule +} + +// extractAuditRules populates the AuditRules field in the AuditRules type after data +// has been unmarshalled into this type. +// +// Since RawRules/audit_rules is of type interface and can contain either a watch or system call +// rule, this function identifies the correct type to allocate. +func (a *AuditRules) extractAuditRules() { + var ri []interface{} + + ri = a.RawRules.([]interface{}) + for _, x := range ri { + havepath := false + for k := range x.(map[string]interface{}) { + if k == "path" { + havepath = true + } + } + var nr interface{} + // If we found a path key, treat it as a file rule, otherwise treat it as a + // syscall rule. + if havepath { + afr := AuditFileRule{} + nr = &afr + } else { + afr := AuditSyscallRule{} + nr = &afr + } + buf, err := json.Marshal(x) + if err != nil { + return + } + err = json.Unmarshal(buf, &nr) + if err != nil { + return + } + a.AuditRules = append(a.AuditRules, nr.(AuditRule)) + } +} + +// AuditRule is an interface abstraction for file system and system call type audit +// rules +type AuditRule interface { + toKernelRule() (auditRuleData, int, int, error) +} + +// AuditFileRule describes the JSON format for a file type audit rule +// +// If StrictPathCheck is true and the path the watch is being added for does not exist, this +// cause SetRules to return an error. If false (default), the rule will just be ignored. +type AuditFileRule struct { + Path string `json:"path"` + Key string `json:"key"` + Permission string `json:"permission"` + StrictPathCheck bool `json:"strict_path_check"` +} + +// toKernelRule converts the JSON rule to a kernel audit rule structure. +func (a *AuditFileRule) toKernelRule() (ret auditRuleData, act int, filt int, err error) { + ret.Buf = make([]byte, 0) + + err = ret.addWatch(a.Path, a.StrictPathCheck) + if err != nil { + return + } + err = ret.addPerms(a.Permission) + if err != nil { + return + } + // The key value is optional for a file rule + if a.Key != "" { + fpd := fieldPairData{ + fieldval: a.Key, + opval: AUDIT_EQUAL, + fieldname: "key", + flags: AUDIT_FILTER_UNSET, + syscallAdded: true, + } + err = auditRuleFieldPairData(&ret, &fpd) + if err != nil { + return + } + } + act = AUDIT_ALWAYS + filt = AUDIT_FILTER_EXIT + return +} + +// AuditSyscallRule describes the JSON format for a syscall type audit rule +type AuditSyscallRule struct { + Key string `json:"key"` + Fields []struct { + Name string `json:"name"` + Value interface{} `json:"value"` // Can be a string or int + Op string `json:"op"` + } `json:"fields"` + Syscalls []string `json:"syscalls"` + Actions []string `json:"actions"` +} + +// toKernelRule converts the JSON rule to a kernel audit rule structure. +func (a *AuditSyscallRule) toKernelRule() (ret auditRuleData, act int, filt int, err error) { + var auditSyscallAdded bool + + ret.Buf = make([]byte, 0) + + syscallMap := headers.SysMapX64 + for _, y := range a.Syscalls { + ival, ok := syscallMap[y] + if !ok { + return ret, 0, 0, fmt.Errorf("invalid syscall %v", y) + } + err = auditRuleSyscallData(&ret, ival) + if err != nil { + return + } + auditSyscallAdded = true + } + + // Separate actions and filters + act, filt = parseActionAndFilters(a.Actions) + + for _, y := range a.Fields { + var opval uint32 + + switch y.Op { + case "nt_eq": + opval = AUDIT_NOT_EQUAL + case "gt_or_eq": + opval = AUDIT_GREATER_THAN_OR_EQUAL + case "lt_or_eq": + opval = AUDIT_LESS_THAN_OR_EQUAL + case "and_eq": + opval = AUDIT_BIT_TEST + case "eq": + opval = AUDIT_EQUAL + case "gt": + opval = AUDIT_GREATER_THAN + case "lt": + opval = AUDIT_LESS_THAN + case "and": + opval = AUDIT_BIT_MASK + } + + fpd := fieldPairData{ + fieldval: y.Value, + opval: opval, + fieldname: y.Name, + flags: filt, + syscallAdded: auditSyscallAdded, + } + err = auditRuleFieldPairData(&ret, &fpd) + if err != nil { + return + } + } + + if a.Key != "" { + fpd := fieldPairData{ + fieldval: a.Key, + opval: AUDIT_EQUAL, + fieldname: "key", + flags: AUDIT_FILTER_UNSET, + syscallAdded: auditSyscallAdded, + } + err = auditRuleFieldPairData(&ret, &fpd) + if err != nil { + return + } + } + return +} + +// Kernel representation of audit_rule_data +type auditRuleData struct { + Flags uint32 `struc:"uint32,little"` // AUDIT_PER_{TASK,CALL}, AUDIT_PREPEND + Action uint32 `struc:"uint32,little"` // AUDIT_NEVER, AUDIT_POSSIBLE, AUDIT_ALWAYS + FieldCount uint32 `struc:"uint32,little"` + Mask [AUDIT_BITMASK_SIZE]uint32 `struc:"[64]uint32,little"` // syscall(s) affected + Fields [AUDIT_MAX_FIELDS]uint32 `struc:"[64]uint32,little"` + Values [AUDIT_MAX_FIELDS]uint32 `struc:"[64]uint32,little"` + Fieldflags [AUDIT_MAX_FIELDS]uint32 `struc:"[64]uint32,little"` + Buflen uint32 `struc:"uint32,little,sizeof=Buf"` // total length of string fields + Buf []byte `struc:"[]byte,little"` // string fields buffer +} + +// Convert auditRuleData to a byte stream suitable for attachment in a netlink +// message +func (rule *auditRuleData) toWireFormat() []byte { + buf := new(bytes.Buffer) + err := binary.Write(buf, hostEndian, rule.Flags) + if err != nil { + return nil + } + err = binary.Write(buf, hostEndian, rule.Action) + if err != nil { + return nil + } + err = binary.Write(buf, hostEndian, rule.FieldCount) + if err != nil { + return nil + } + err = binary.Write(buf, hostEndian, rule.Mask) + if err != nil { + return nil + } + err = binary.Write(buf, hostEndian, rule.Fields) + if err != nil { + return nil + } + err = binary.Write(buf, hostEndian, rule.Values) + if err != nil { + return nil + } + err = binary.Write(buf, hostEndian, rule.Fieldflags) + if err != nil { + return nil + } + err = binary.Write(buf, hostEndian, rule.Buflen) + if err != nil { + return nil + } + err = binary.Write(buf, hostEndian, rule.Buf) + if err != nil { + return nil + } + return buf.Bytes() +} + +// DeleteAllRules removes all audit rules currently in use in the audit system +func DeleteAllRules(s Netlink) error { + wb := newNetlinkAuditRequest(uint16(AUDIT_LIST_RULES), syscall.AF_NETLINK, 0) + if err := s.Send(wb); err != nil { + return err + } + + msgs, err := auditGetReply(s, wb.Header.Seq, false) + if err != nil { + return err + } + for _, m := range msgs { + if m.Header.Type == uint16(AUDIT_LIST_RULES) { + delwb := newNetlinkAuditRequest(uint16(AUDIT_DEL_RULE), syscall.AF_NETLINK, len(m.Data)) + delwb.Data = m.Data + if err = s.Send(delwb); err != nil { + return err + } + _, err := auditGetReply(s, delwb.Header.Seq, true) // Drain ACK + if err != nil { + return err + } + } + } + return nil +} + +func auditWord(nr int) uint32 { + word := (uint32)((nr) / 32) + return (uint32)(word) +} + +func auditBit(nr int) uint32 { + bit := 1 << ((uint32)(nr) - auditWord(nr)*32) + return (uint32)(bit) +} + +// auditRuleSyscallData makes changes in the rule struct according to system call number +func auditRuleSyscallData(rule *auditRuleData, scall int) error { + word := auditWord(scall) + bit := auditBit(scall) + + if word >= AUDIT_BITMASK_SIZE-1 { + return fmt.Errorf("word size greater than AUDIT_BITMASK_SIZE") + } + rule.Mask[word] |= bit + return nil +} + +// auditNameToFtype converts string field names to integer values based on lookup table ftypeTab +func auditNameToFtype(name string, value *int) error { + for k, v := range headers.FtypeTab { + if k == name { + *value = v + return nil + } + } + return fmt.Errorf("filetype %v not found", name) +} + +var ( + errNoStr = errors.New("no support for string values") + errUnset = errors.New("unable to set value") + errNoSys = errors.New("no prior syscall added") + errMaxLen = errors.New("max Rule length exceeded") +) + +// Collection of values required for auditRuleFieldPairData() +type fieldPairData struct { + fieldval interface{} + opval uint32 + fieldname string + flags int + syscallAdded bool +} + +// auditRuleFieldPairData process the passed auditRuleData struct for passing to kernel +// according to passedfpd.fieldnames and flags +func auditRuleFieldPairData(rule *auditRuleData, fpd *fieldPairData) error { + var ( + auditPermAdded bool + ) + + if rule.FieldCount >= (AUDIT_MAX_FIELDS - 1) { + return fmt.Errorf("max fields for rule exceeded") + } + + var fieldid uint32 + for k, v := range headers.FieldMap { + if k == fpd.fieldname { + fieldid = uint32(v) + break + } + } + if fieldid == 0 { + return fmt.Errorf("unknown field %v", fpd.fieldname) + } + if fpd.flags == AUDIT_FILTER_EXCLUDE && fieldid != AUDIT_MSGTYPE { + return fmt.Errorf("exclude filter only valid with AUDIT_MSGTYPE") + } + rule.Fields[rule.FieldCount] = fieldid + rule.Fieldflags[rule.FieldCount] = fpd.opval + + switch fieldid { + case AUDIT_UID, AUDIT_EUID, AUDIT_SUID, AUDIT_FSUID, AUDIT_LOGINUID, AUDIT_OBJ_UID, AUDIT_OBJ_GID: + if val, isInt := fpd.fieldval.(float64); isInt { + rule.Values[rule.FieldCount] = (uint32)(val) + } else if val, isString := fpd.fieldval.(string); isString { + if val == "unset" { + rule.Values[rule.FieldCount] = 4294967295 + } else { + user, err := user.Lookup(val) + if err != nil { + return fmt.Errorf("bad user: %v: %v", user, err) + } + userID, err := strconv.Atoi(user.Uid) + if err != nil { + return fmt.Errorf("bad uid %v", userID) + } + rule.Values[rule.FieldCount] = (uint32)(userID) + } + } else { + return fmt.Errorf("field value has unusable type %v", fpd.fieldval) + } + case AUDIT_GID, AUDIT_EGID, AUDIT_SGID, AUDIT_FSGID: + if val, isInt := fpd.fieldval.(float64); isInt { + rule.Values[rule.FieldCount] = (uint32)(val) + } else if _, isString := fpd.fieldval.(string); isString { + // TODO: use of group names is unsupported + return fmt.Errorf("group name translation is unsupported %v", fpd.fieldval) + } else { + return fmt.Errorf("field value has unusable type %v", fpd.fieldval) + } + case AUDIT_EXIT: + if fpd.flags != AUDIT_FILTER_EXIT { + return fmt.Errorf("%v can only be used with exit filter list", fpd.fieldname) + } + if val, isInt := fpd.fieldval.(float64); isInt { + rule.Values[rule.FieldCount] = (uint32)(val) + } else if _, isString := fpd.fieldval.(string); isString { + return fmt.Errorf("string values unsupported for field type") + } else { + return fmt.Errorf("field value has unusable type %v", fpd.fieldval) + } + case AUDIT_MSGTYPE: + if fpd.flags != AUDIT_FILTER_EXCLUDE && fpd.flags != AUDIT_FILTER_USER { + return fmt.Errorf("msgtype field can only be used with exclude filter list") + } + if val, isInt := fpd.fieldval.(float64); isInt { + rule.Values[rule.FieldCount] = (uint32)(val) + } else if _, isString := fpd.fieldval.(string); isString { + return fmt.Errorf("string values unsupported for field type") + } else { + return fmt.Errorf("field value has unusable type %v", fpd.fieldval) + } + case AUDIT_OBJ_USER, AUDIT_OBJ_ROLE, AUDIT_OBJ_TYPE, AUDIT_OBJ_LEV_LOW, AUDIT_OBJ_LEV_HIGH, + AUDIT_WATCH, AUDIT_DIR: + // Watch & object filtering is invalid on anything but exit + if fpd.flags != AUDIT_FILTER_EXIT { + return fmt.Errorf("%v can only be used with exit filter list", fpd.fieldname) + } + if fieldid == AUDIT_WATCH || fieldid == AUDIT_DIR { + auditPermAdded = true + } + fallthrough + case AUDIT_SUBJ_USER, AUDIT_SUBJ_ROLE, AUDIT_SUBJ_TYPE, AUDIT_SUBJ_SEN, AUDIT_SUBJ_CLR, AUDIT_FILTERKEY: + // If and only if a syscall is added or a permission is added then this field should be set + if fieldid == AUDIT_FILTERKEY && !(fpd.syscallAdded || auditPermAdded) { + return fmt.Errorf("key field needs a watch or syscall given prior to it") + } + if val, isString := fpd.fieldval.(string); isString { + valbyte := []byte(val) + vlen := len(valbyte) + if fieldid == AUDIT_FILTERKEY && vlen > AUDIT_MAX_KEY_LEN { + return fmt.Errorf("max rule length exceeded") + } else if vlen > PATH_MAX { + return fmt.Errorf("max rule length exceeded") + } + rule.Values[rule.FieldCount] = (uint32)(vlen) + rule.Buflen = rule.Buflen + (uint32)(vlen) + rule.Buf = append(rule.Buf, valbyte[:]...) + } else { + return fmt.Errorf("field value has unusable type, %v", fpd.fieldval) + } + case AUDIT_ARCH: + if fpd.syscallAdded == false { + return fmt.Errorf("arch should be mentioned before syscall") + } + if !(fpd.opval == AUDIT_NOT_EQUAL || fpd.opval == AUDIT_EQUAL) { + return fmt.Errorf("arch must have = or != operator") + } + // XXX Considers X64 only + if _, isInt := fpd.fieldval.(float64); isInt { + rule.Values[rule.FieldCount] = AUDIT_ARCH_X86_64 + } else if _, isString := fpd.fieldval.(string); isString { + return fmt.Errorf("string values unsupported for field type") + } else { + return fmt.Errorf("field value has unusable type, %v", fpd.fieldval) + } + case AUDIT_PERM: + if fpd.flags != AUDIT_FILTER_EXIT { + return fmt.Errorf("%v can only be used with exit filter list", fpd.fieldname) + } else if fpd.opval != AUDIT_EQUAL { + return fmt.Errorf("%v only takes = or != operators", fpd.fieldname) + } else { + if val, isString := fpd.fieldval.(string); isString { + var ( + i, vallen int + permval uint32 + ) + vallen = len(val) + if vallen > 4 { + return fmt.Errorf("vallen too large") + } + lowerval := strings.ToLower(val) + for i = 0; i < vallen; i++ { + switch lowerval[i] { + case 'r': + permval |= AUDIT_PERM_READ + case 'w': + permval |= AUDIT_PERM_WRITE + case 'x': + permval |= AUDIT_PERM_EXEC + case 'a': + permval |= AUDIT_PERM_ATTR + default: + return fmt.Errorf("permission can only contain rwxa") + } + } + rule.Values[rule.FieldCount] = permval + auditPermAdded = true + } + } + case AUDIT_FILETYPE: + if val, isString := fpd.fieldval.(string); isString { + if !(fpd.flags == AUDIT_FILTER_EXIT) && fpd.flags == AUDIT_FILTER_ENTRY { + return fmt.Errorf("%v can only be used with exit and entry filter list", fpd.fieldname) + } + var fileval int + err := auditNameToFtype(val, &fileval) + if err != nil { + return err + } + rule.Values[rule.FieldCount] = uint32(fileval) + if (int)(rule.Values[rule.FieldCount]) < 0 { + return fmt.Errorf("unknown file type %v", fpd.fieldname) + } + } else { + return fmt.Errorf("expected string but filetype found %v", fpd.fieldval) + } + case AUDIT_ARG0, AUDIT_ARG1, AUDIT_ARG2, AUDIT_ARG3: + if val, isInt := fpd.fieldval.(float64); isInt { + rule.Values[rule.FieldCount] = (uint32)(val) + } else if _, isString := fpd.fieldval.(string); isString { + return fmt.Errorf("%v should be a number", fpd.fieldname) + } else { + return fmt.Errorf("field value has unusable type, %v", fpd.fieldval) + } + case AUDIT_DEVMAJOR, AUDIT_INODE, AUDIT_SUCCESS: + if fpd.flags != AUDIT_FILTER_EXIT { + return fmt.Errorf("%v can only be used with exit filter list", fpd.fieldname) + } + fallthrough + default: + if fieldid == AUDIT_INODE { + if !(fpd.opval == AUDIT_NOT_EQUAL || fpd.opval == AUDIT_EQUAL) { + return fmt.Errorf("%v only takes = or != operators", fpd.fieldname) + } + } + + if fieldid == AUDIT_PPID && !(fpd.flags == AUDIT_FILTER_EXIT || fpd.flags == AUDIT_FILTER_ENTRY) { + return fmt.Errorf("%v can only be used with exit and entry filter list", fpd.fieldname) + } + + if val, isInt := fpd.fieldval.(float64); isInt { + if fieldid == AUDIT_INODE { + // c version uses strtoul (in case of INODE) + rule.Values[rule.FieldCount] = (uint32)(val) + } else { + // c version uses strtol + rule.Values[rule.FieldCount] = (uint32)(val) + } + } else { + return fmt.Errorf("%v should be a number", fpd.fieldval) + } + } + rule.FieldCount++ + return nil +} + +// parseActionAndFilters parses a list of actions and filter keywords, returning the action +// and filter components as individual values +func parseActionAndFilters(actions []string) (action int, filter int) { + action = -1 + filter = AUDIT_FILTER_UNSET + + for _, value := range actions { + if value == "never" { + action = AUDIT_NEVER + } else if value == "possible" { + action = AUDIT_POSSIBLE + } else if value == "always" { + action = AUDIT_ALWAYS + } else if value == "task" { + filter = AUDIT_FILTER_TASK + } else if value == "entry" { + filter = AUDIT_FILTER_EXIT + } else if value == "exit" { + filter = AUDIT_FILTER_EXIT + } else if value == "user" { + filter = AUDIT_FILTER_USER + } else if value == "exclude" { + filter = AUDIT_FILTER_EXCLUDE + } + } + return +} + +// auditAddRuleData sends a prepared auditRuleData to be loaded by the kernel, this effectively +// installs the rule +func auditAddRuleData(s Netlink, rule *auditRuleData, flags int, action int) error { + if flags == AUDIT_FILTER_ENTRY { + return fmt.Errorf("use of entry filter is deprecated") + } + + rule.Flags = uint32(flags) + rule.Action = uint32(action) + buf := rule.toWireFormat() + + wb := newNetlinkAuditRequest(uint16(AUDIT_ADD_RULE), syscall.AF_NETLINK, len(buf)) + wb.Data = buf + err := s.Send(wb) + if err != nil { + return err + } + _, err = auditGetReply(s, wb.Header.Seq, true) // Drain ACK + if err != nil { + return err + } + return nil +} + +// SetRules sets the audit rule set in the kernel, based on the JSON audit rule data in content +// +// Any warnings which are non-fatal (e.g., attempting to set a watch rule on a nonexistent file) +// are included in the warnings slice which is returned. If a fatal error occurs, err will be +// non-nil. +func SetRules(s Netlink, content []byte) (warnings []string, err error) { + var rules AuditRules + err = json.Unmarshal(content, &rules) + if err != nil { + return + } + rules.extractAuditRules() + for _, x := range rules.AuditRules { + // Convert JSON rule to a kernel rule + kr, action, filter, err := x.toKernelRule() + if err != nil { + // See if the error indicates the rule was being skipped, if so we + // do not treat this as fatal and keep going. + if strings.HasPrefix(err.Error(), "skipping rule") { + warnings = append(warnings, err.Error()) + continue + } + return warnings, err + } + err = auditAddRuleData(s, &kr, filter, action) + if err != nil { + return warnings, err + } + } + return warnings, nil +} + +// checkPath checks the path which is being used in a watch rule to validate it is formatted +// correctly +func checkPath(pathName string) error { + if len(pathName) >= PATH_MAX { + return fmt.Errorf("path %q too large", pathName) + } + if pathName[0] != '/' { + return fmt.Errorf("path %q must be absolute") + } + if strings.Contains(pathName, "..") { + return fmt.Errorf("path %q cannot contain special directory values", pathName) + } + + base := path.Base(pathName) + if len(base) > syscall.NAME_MAX { + return fmt.Errorf("base name %q too large", base) + } + + return nil +} + +// addWatch adds AUDIT_WATCH/AUDIT_DIR values for path to an auditRuleData +func (rule *auditRuleData) addWatch(path string, strictPath bool) error { + typeName := uint16(AUDIT_WATCH) + + err := checkPath(path) + if err != nil { + return err + } + + // Trim any trailing slash if present + path = strings.TrimRight(path, "/") + + // Validate the path exists + fileInfo, err := os.Stat(path) + if err != nil { + if os.IsNotExist(err) && strictPath { + return err + } else if !os.IsNotExist(err) { + return err + } + // Otherwise the path did not exist, return an error indicating this rule + // is being skipped + return fmt.Errorf("skipping rule: %v", err) + } + if fileInfo.IsDir() { + typeName = uint16(AUDIT_DIR) + } + + // Verify the rule is empty + if rule.FieldCount != 0 { + return fmt.Errorf("rule is not empty") + } + + rule.Flags = uint32(AUDIT_FILTER_EXIT) + rule.Action = uint32(AUDIT_ALWAYS) + // mark all bits as would be done by audit_rule_syscallbyname_data(rule, "all") + for i := 0; i < AUDIT_BITMASK_SIZE-1; i++ { + rule.Mask[i] = 0xFFFFFFFF + } + + rule.FieldCount = uint32(2) + rule.Fields[0] = uint32(typeName) + + rule.Fieldflags[0] = uint32(AUDIT_EQUAL) + valbyte := []byte(path) + vlen := len(valbyte) + + rule.Values[0] = (uint32)(vlen) + rule.Buflen = (uint32)(vlen) + // Now write the key value in the rule buffer space + rule.Buf = append(rule.Buf, valbyte...) + + rule.Fields[1] = uint32(AUDIT_PERM) + rule.Fieldflags[1] = uint32(AUDIT_EQUAL) + rule.Values[1] = uint32(AUDIT_PERM_READ | AUDIT_PERM_WRITE | AUDIT_PERM_EXEC | AUDIT_PERM_ATTR) + + return nil +} + +// addPerms parses a permissions string and associated it with a watch rule +func (rule *auditRuleData) addPerms(perms string) error { + if len(perms) > 4 || len(perms) < 1 { + return fmt.Errorf("invalid permission string %q", perms) + } + perms = strings.ToLower(perms) + var permValue int + for _, val := range perms { + switch val { + case 'r': + permValue |= AUDIT_PERM_READ + case 'w': + permValue |= AUDIT_PERM_WRITE + case 'x': + permValue |= AUDIT_PERM_EXEC + case 'a': + permValue |= AUDIT_PERM_ATTR + default: + return fmt.Errorf("unknown permission %v", val) + } + } + + if rule.FieldCount < 1 { + return fmt.Errorf("rule is empty") + } + + // First see if we have an entry we are updating + for i := range rule.Fields { + if rule.Fields[i] == uint32(AUDIT_PERM) { + rule.Values[i] = uint32(permValue) + return nil + } + } + // If not check to see if we have room to add a field + if rule.FieldCount >= AUDIT_MAX_FIELDS-1 { + return fmt.Errorf("maximum field limit reached") + } + + rule.Fields[rule.FieldCount] = uint32(AUDIT_PERM) + rule.Values[rule.FieldCount] = uint32(permValue) + rule.Fieldflags[rule.FieldCount] = uint32(AUDIT_EQUAL) + rule.FieldCount++ + + return nil +} + +// ListAllRules returns a list of audit rules from the kernel. Note that the list is returned +// as a slice of strings, formatted in the way auditctl would display the audit rules. +// +// XXX Conversion back to an AuditRules type is not currently supported. This function should +// likely instead return an AuditRules type, which can then be translated into an auditctl style +// output if desired. +func ListAllRules(s Netlink) (ret []string, err error) { + var kernelRules []auditRuleData + + wb := newNetlinkAuditRequest(uint16(AUDIT_LIST_RULES), syscall.AF_NETLINK, 0) + if err = s.Send(wb); err != nil { + return + } + msgs, err := auditGetReply(s, wb.Header.Seq, false) + if err != nil { + return + } + for _, m := range msgs { + if m.Header.Type == uint16(AUDIT_LIST_RULES) { + var r auditRuleData + nbuf := bytes.NewBuffer(m.Data) + err = struc.Unpack(nbuf, &r) + if err != nil { + return + } + kernelRules = append(kernelRules, r) + } + } + // Now convert each of the rules returned by the kernel into a string. + for _, kr := range kernelRules { + r := kr.printRule() + ret = append(ret, r) + } + return +} + +// syscallToName takes syscall number and returns the syscall name. +func syscallToName(syscall string) (string, error) { + syscallMap := headers.ReverseSysMapX64 + if val, ok := syscallMap[syscall]; ok { + return val, nil + } + return "", fmt.Errorf("syscall %v not found", syscall) + +} + +// printRule returns the string representation of a given kernel audit rule as would be +// printed by the auditctl utility. +func (rule *auditRuleData) printRule() string { + var ( + watch = rule.isWatch() + result, n string + bufferOffset int + count int + sys int + printed bool + ) + + if !watch { + result = fmt.Sprintf("-a %v,%v", actionToName(rule.Action), flagToName(rule.Flags)) + for i := 0; i < int(rule.FieldCount); i++ { + field := rule.Fields[i] & (^uint32(AUDIT_OPERATORS)) + if field == AUDIT_ARCH { + op := rule.Fieldflags[i] & uint32(AUDIT_OPERATORS) + result += fmt.Sprintf("-F arch%v", operatorToSymbol(op)) + // Determine architecture from the runtime package rather than + // looking in a lookup table as auditd does + if runtime.GOARCH == "amd64" { + result += "b64" + } else if runtime.GOARCH == "386" { + result += "b32" + } else { + result += fmt.Sprintf("0x%X", field) + } + break + } + } + n, count, sys, printed = printSyscallRule(rule) + if printed { + result += n + } + + } + for i := 0; i < int(rule.FieldCount); i++ { + op := (rule.Fieldflags[i] & uint32(AUDIT_OPERATORS)) + field := (rule.Fields[i] & (^uint32(AUDIT_OPERATORS))) + if field == AUDIT_ARCH { + continue + } + fieldName := fieldToName(field) + if len(fieldName) == 0 { + // unknown field + result += fmt.Sprintf(" f%v%v%v", rule.Fields[i], operatorToSymbol(op), rule.Values[i]) + continue + } + // Special cases to print the different field types + if field == AUDIT_MSGTYPE { + if strings.HasPrefix(auditConstant(rule.Values[i]).String(), "auditConstant") { + result += fmt.Sprintf(" f%d%s%d", rule.Fields[i], operatorToSymbol(op), rule.Values[i]) + } else { + result += fmt.Sprintf(" -F %s%s%s", fieldName, operatorToSymbol(op), + auditConstant(rule.Values[i]).String()[6:]) + } + } else if (field >= AUDIT_SUBJ_USER && field <= AUDIT_OBJ_LEV_HIGH) && field != AUDIT_PPID { + // rule.Values[i] denotes the length of the buffer for the field + result += fmt.Sprintf(" -F %s%s%s", fieldName, operatorToSymbol(op), + string(rule.Buf[bufferOffset:bufferOffset+int(rule.Values[i])])) + } else if field == AUDIT_WATCH { + if watch { + result += fmt.Sprintf("-w %s", + string(rule.Buf[bufferOffset:bufferOffset+int(rule.Values[i])])) + } else { + result += fmt.Sprintf(" -F path=%s", + string(rule.Buf[bufferOffset:bufferOffset+int(rule.Values[i])])) + } + bufferOffset += int(rule.Values[i]) + } else if field == AUDIT_DIR { + if watch { + result += fmt.Sprintf("-w %s", + string(rule.Buf[bufferOffset:bufferOffset+int(rule.Values[i])])) + } else { + result += fmt.Sprintf(" -F dir=%s", + string(rule.Buf[bufferOffset:bufferOffset+int(rule.Values[i])])) + } + bufferOffset += int(rule.Values[i]) + } else if field == AUDIT_EXE { + result += fmt.Sprintf(" -F exe=%s", string(rule.Buf[bufferOffset:bufferOffset+int(rule.Values[i])])) + bufferOffset += int(rule.Values[i]) + } else if field == AUDIT_FILTERKEY { + key := fmt.Sprintf("%s", string(rule.Buf[bufferOffset:bufferOffset+int(rule.Values[i])])) + bufferOffset += int(rule.Values[i]) + // checking for multiple keys + keyList := strings.Split(key, `\0`) + for _, k := range keyList { + if watch { + result += fmt.Sprintf(" -k %s", k) + } else { + result += fmt.Sprintf(" -F key=%s", k) + } + } + } else if field == AUDIT_PERM { + var perms string + if (rule.Values[i] & uint32(AUDIT_PERM_READ)) > 0 { + perms += "r" + } + if (rule.Values[i] & uint32(AUDIT_PERM_WRITE)) > 0 { + perms += "w" + } + if (rule.Values[i] & uint32(AUDIT_PERM_EXEC)) > 0 { + perms += "x" + } + if (rule.Values[i] & uint32(AUDIT_PERM_ATTR)) > 0 { + perms += "a" + } + if watch { + result += fmt.Sprintf(" -p %s", perms) + } else { + result += fmt.Sprintf(" -F perm=%s", perms) + } + } else if field == AUDIT_INODE { + result += fmt.Sprintf(" -F %s%s%d", fieldName, operatorToSymbol(op), rule.Values[i]) + } else if field == AUDIT_FIELD_COMPARE { + result += printFieldCmp(rule.Values[i], op) + } else if field >= AUDIT_ARG0 && field <= AUDIT_ARG3 { + var a0, a1 int + if field == AUDIT_ARG0 { + a0 = int(rule.Values[i]) + } else if field == AUDIT_ARG1 { + a1 = int(rule.Values[i]) + } + if count > 1 { + result += fmt.Sprintf(" -F %s%s0x%X", fieldName, operatorToSymbol(op), rule.Values[i]) + } else { + // we try to parse the argument passed so we need the syscall found earlier + var r = record{syscallNum: fmt.Sprintf("%d", sys), a0: a0, a1: a1} + n, err := interpretField("syscall", fmt.Sprintf("%x", rule.Values[i]), AUDIT_SYSCALL, r) + if err != nil { + continue + } + result += fmt.Sprintf(" -F %s%s0x%X", fieldName, operatorToSymbol(op), n) + } + } else if field == AUDIT_EXIT { + // in this case rule.Values[i] holds the error code for EXIT + // therefore it will need a audit_errno_to_name() function that peeks on error codes + // but error codes are widely varied and printExit() function only matches 0 => success + // so we are directly printing the integer error code in the rule + // and not their string equivalents + result += fmt.Sprintf(" -F %s%s%d", fieldName, operatorToSymbol(op), int(rule.Values[i])) + } else { + result += fmt.Sprintf(" -F %s%s%d", fieldName, operatorToSymbol(op), rule.Values[i]) + } + + } + return result +} + +// isWatch returns true if a given kernel audit rule is a watch (file) rule. +func (rule *auditRuleData) isWatch() bool { + var ( + foundPerm bool + foundAll = true + ) + // Try to locate AUDIT_PERM in the field list + for i := 0; i < int(rule.FieldCount); i++ { + field := rule.Fields[i] & (^uint32(AUDIT_OPERATORS)) + if field == AUDIT_PERM { + foundPerm = true + continue + } + // Watch rules can only have 4 field types, if we see any others return false + if field != AUDIT_PERM && field != AUDIT_FILTERKEY && field != AUDIT_DIR && field != AUDIT_WATCH { + return false + } + } + if ((rule.Flags & AUDIT_FILTER_MASK) != AUDIT_FILTER_USER) && + ((rule.Flags & AUDIT_FILTER_MASK) != AUDIT_FILTER_TASK) && + ((rule.Flags & AUDIT_FILTER_MASK) != AUDIT_FILTER_EXCLUDE) { + for i := 0; i < int(AUDIT_BITMASK_SIZE-1); i++ { + if rule.Mask[i] != ^uint32(0) { + foundAll = false + break + } + } + } + + if foundPerm && foundAll { + return true + } + + return false +} + +// actionToName converts an integer action value to its string counterpart +func actionToName(action uint32) string { + return actionLookup[int(action)] +} + +// flagToName converts an integer flag value to its string counterpart +func flagToName(flag uint32) string { + return flagLookup[int(flag)] +} + +// operatorToSymbol converts integer operator value to its symbolic string +func operatorToSymbol(op uint32) string { + return opLookup[int(op)] +} + +// printSyscallRule returns syscall rule specific string output for rule +func printSyscallRule(rule *auditRuleData) (string, int, int, bool) { + var ( + name string + all = true + count int + syscall int + i int + ) + + /* Rules on the following filters do not take a syscall */ + if ((rule.Flags & AUDIT_FILTER_MASK) == AUDIT_FILTER_USER) || + ((rule.Flags & AUDIT_FILTER_MASK) == AUDIT_FILTER_TASK) || + ((rule.Flags & AUDIT_FILTER_MASK) == AUDIT_FILTER_EXCLUDE) { + return name, count, syscall, false + } + + /* See if its all or specific syscalls */ + for i = 0; i < (AUDIT_BITMASK_SIZE - 1); i++ { + if rule.Mask[i] != ^uint32(0) { + all = false + break + } + } + + if all { + name += fmt.Sprintf(" -S all") + count = i + return name, count, syscall, true + } + + for i = 0; i < AUDIT_BITMASK_SIZE*32; i++ { + word := auditWord(i) + bit := auditBit(i) + if (rule.Mask[word] & bit) > 0 { + n, err := syscallToName(fmt.Sprintf("%d", i)) + if len(name) == 0 { + name += fmt.Sprintf(" -S ") + } + if count > 0 { + name += "," + } + if err != nil { + name += fmt.Sprintf("%d", i) + } else { + name += n + } + count++ + // we set the syscall to the last occuring one + // behaviour is same as print_syscall() in auditctl-listing.c + syscall = i + } + } + return name, count, syscall, true +} + +// fieldToName returns a field string given its integer representation +func fieldToName(field uint32) string { + var name string + name = fieldLookup[int(field)] + return name +} + +// printFieldCmp returns a string denoting the comparison between the field values +func printFieldCmp(value, op uint32) string { + var result string + + switch auditConstant(value) { + case AUDIT_COMPARE_UID_TO_OBJ_UID: + result = fmt.Sprintf(" -C uid%sobj_uid", operatorToSymbol(op)) + case AUDIT_COMPARE_GID_TO_OBJ_GID: + result = fmt.Sprintf(" -C gid%sobj_gid", operatorToSymbol(op)) + case AUDIT_COMPARE_EUID_TO_OBJ_UID: + result = fmt.Sprintf(" -C euid%sobj_uid", operatorToSymbol(op)) + case AUDIT_COMPARE_EGID_TO_OBJ_GID: + result = fmt.Sprintf(" -C egid%sobj_gid", operatorToSymbol(op)) + case AUDIT_COMPARE_AUID_TO_OBJ_UID: + result = fmt.Sprintf(" -C auid%sobj_uid", operatorToSymbol(op)) + case AUDIT_COMPARE_SUID_TO_OBJ_UID: + result = fmt.Sprintf(" -C suid%sobj_uid", operatorToSymbol(op)) + case AUDIT_COMPARE_SGID_TO_OBJ_GID: + result = fmt.Sprintf(" -C sgid%sobj_gid", operatorToSymbol(op)) + case AUDIT_COMPARE_FSUID_TO_OBJ_UID: + result = fmt.Sprintf(" -C fsuid%sobj_uid", operatorToSymbol(op)) + case AUDIT_COMPARE_FSGID_TO_OBJ_GID: + result = fmt.Sprintf(" -C fsgid%sobj_gid", operatorToSymbol(op)) + case AUDIT_COMPARE_UID_TO_AUID: + result = fmt.Sprintf(" -C uid%sauid", operatorToSymbol(op)) + case AUDIT_COMPARE_UID_TO_EUID: + result = fmt.Sprintf(" -C uid%seuid", operatorToSymbol(op)) + case AUDIT_COMPARE_UID_TO_FSUID: + result = fmt.Sprintf(" -C uid%sfsuid", operatorToSymbol(op)) + case AUDIT_COMPARE_UID_TO_SUID: + result = fmt.Sprintf(" -C uid%ssuid", operatorToSymbol(op)) + case AUDIT_COMPARE_AUID_TO_FSUID: + result = fmt.Sprintf(" -C auid%sfsuid", operatorToSymbol(op)) + case AUDIT_COMPARE_AUID_TO_SUID: + result = fmt.Sprintf(" -C auid%ssuid", operatorToSymbol(op)) + case AUDIT_COMPARE_AUID_TO_EUID: + result = fmt.Sprintf(" -C auid%seuid", operatorToSymbol(op)) + case AUDIT_COMPARE_EUID_TO_SUID: + result = fmt.Sprintf(" -C euid%ssuid", operatorToSymbol(op)) + case AUDIT_COMPARE_EUID_TO_FSUID: + result = fmt.Sprintf(" -C euid%sfsuid", operatorToSymbol(op)) + case AUDIT_COMPARE_SUID_TO_FSUID: + result = fmt.Sprintf(" -C suid%sfsuid", operatorToSymbol(op)) + case AUDIT_COMPARE_GID_TO_EGID: + result = fmt.Sprintf(" -C gid%segid", operatorToSymbol(op)) + case AUDIT_COMPARE_GID_TO_FSGID: + result = fmt.Sprintf(" -C gid%sfsgid", operatorToSymbol(op)) + case AUDIT_COMPARE_GID_TO_SGID: + result = fmt.Sprintf(" -C gid%ssgid", operatorToSymbol(op)) + case AUDIT_COMPARE_EGID_TO_FSGID: + result = fmt.Sprintf(" -C egid%sfsgid", operatorToSymbol(op)) + case AUDIT_COMPARE_EGID_TO_SGID: + result = fmt.Sprintf(" -C egid%ssgid", operatorToSymbol(op)) + case AUDIT_COMPARE_SGID_TO_FSGID: + result = fmt.Sprintf(" -C sgid%sfsgid", operatorToSymbol(op)) + } + + return result +} diff --git a/vendor/github.com/mozilla/libaudit-go/rules_test.go b/vendor/github.com/mozilla/libaudit-go/rules_test.go new file mode 100644 index 00000000..adca337e --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/rules_test.go @@ -0,0 +1,148 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package libaudit + +import ( + "io/ioutil" + "os" + "testing" +) + +var expectedRules = []string{ + "-w /etc/libaudit.conf -p wa -k audit", + "-w /etc/rsyslog.conf -p wa -k syslog", + "-a always,exit-F arch=b64 -S personality -F key=bypass", + "-a never,exit -F path=/bin/ls -F perm=x", + "-a always,exit-F arch=b64 -S execve -F key=exec", + "-a always,exit -S clone,fork,vfork", + "-a always,exit -S adjtimex,settimeofday -F key=time-change", + "-a always,exit-F arch=b64 -S rename,renameat -F auid>=1000 -F key=rename", +} + +func TestSetRules(t *testing.T) { + if os.Getuid() != 0 { + t.Skipf("skipping test, not root user") + } + + jsonRules, err := ioutil.ReadFile("./testdata/rules.json") + if err != nil { + t.Fatalf("ioutil.ReadFile: %v", err) + } + + s, err := NewNetlinkConnection() + if err != nil { + t.Fatalf("NewNetlinkConnection: %v", err) + } + err = DeleteAllRules(s) + if err != nil { + t.Fatalf("DeleteAllRules: %v", err) + } + + _, err = SetRules(s, jsonRules) + if err != nil { + t.Fatalf("SetRules: %v", err) + } + s.Close() + + // Open up a new connection before we list the rules + x, err := NewNetlinkConnection() + if err != nil { + t.Fatalf("NewNetlinkConnection: %v", err) + } + + setRules, err := ListAllRules(x) + if err != nil { + t.Fatalf("ListAllRules: %v", err) + } + if len(setRules) != len(expectedRules) { + t.Fatalf("number of set rules unexpected, wanted %v got %v", len(expectedRules), + len(setRules)) + } + for i := range setRules { + if setRules[i] != expectedRules[i] { + t.Fatalf("expected rule %q, got rule %q", expectedRules[i], setRules[i]) + } + } + x.Close() +} + +// Try to load a rule set with strict path checking enabled, where the path in a watch rule is +// nonexistent; should fail. +func TestSetRulesStrictPathFail(t *testing.T) { + if os.Getuid() != 0 { + t.Skipf("skipping test, not root user") + } + + jsonRules, err := ioutil.ReadFile("./testdata/strictpathfail.json") + if err != nil { + t.Fatalf("ioutil.ReadFile: %v", err) + } + + s, err := NewNetlinkConnection() + if err != nil { + t.Fatalf("NewNetlinkConnection: %v", err) + } + err = DeleteAllRules(s) + if err != nil { + t.Fatalf("DeleteAllRules: %v", err) + } + + _, err = SetRules(s, jsonRules) + if err == nil { + t.Fatalf("SetRules should have failed on nonexistent path") + } + s.Close() +} + +// Try to load a rule set with strict path checking disabled, where the path in a watch rule is +// nonexistent; should succeed but ignore the invalid rule. +func TestSetRulesNoStrictPath(t *testing.T) { + if os.Getuid() != 0 { + t.Skipf("skipping test, not root user") + } + + jsonRules, err := ioutil.ReadFile("./testdata/badpathnostrictpath.json") + if err != nil { + t.Fatalf("ioutil.ReadFile: %v", err) + } + + s, err := NewNetlinkConnection() + if err != nil { + t.Fatalf("NewNetlinkConnection: %v", err) + } + err = DeleteAllRules(s) + if err != nil { + t.Fatalf("DeleteAllRules: %v", err) + } + + warnings, err := SetRules(s, jsonRules) + if err != nil { + t.Fatalf("SetRules: %v", err) + } + + // We should have gotten one warning back + if len(warnings) != 1 { + t.Fatalf("SetRules: should have returned 1 warning") + } + + // Open up a new connection before we list the rules + x, err := NewNetlinkConnection() + if err != nil { + t.Fatalf("NewNetlinkConnection: %v", err) + } + + setRules, err := ListAllRules(x) + if err != nil { + t.Fatalf("ListAllRules: %v", err) + } + // We should have 1 rule here, since the test data set contains 2 rules, one of which + // should have been ignored. + expectedRules := 1 + if len(setRules) != expectedRules { + t.Fatalf("number of set rules unexpected, wanted %v got %v", expectedRules, + len(setRules)) + } + s.Close() +} diff --git a/vendor/github.com/mozilla/libaudit-go/s2i_type_conversion.json b/vendor/github.com/mozilla/libaudit-go/s2i_type_conversion.json new file mode 100644 index 00000000..67deea60 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/s2i_type_conversion.json @@ -0,0 +1,244 @@ +{ + "machine" : [ + { + "string": "armeb", + "s2iS" : 0, + "s2iI" : 8 + }, + { + "name": "armv5tejl", + "s2iS" : 6, + "s2iI" : 8 + }, + { + "name": "armv7l", + "s2iS" : 16, + "s2iI" : 8 + }, + { + "name": "i386", + "s2iS" : 23, + "s2iI" : 0 + }, + { + "name": "i486", + "s2iS" : 28, + "s2iI" : 0 + }, + { + "name": "i586", + "s2iS" : 33, + "s2iI" : 0 + }, + { + "name": "i686", + "s2iS" : 38, + "s2iI" : 0 + }, + { + "name": "ia64", + "s2iS" : 43, + "s2iI" : 2 + }, + { + "name": "ppc", + "s2iS" : 48, + "s2iI" : 4 + }, + { + "name": "ppc64", + "s2iS" : 52, + "s2iI" : 3 + }, + { + "name": "s390", + "s2iS" : 58, + "s2iI" : 6 + }, + { + "name": "s390x", + "s2iS" : 63, + "s2iI" : 5 + }, + { + "name": "x86_64", + "s2iS" : 69, + "s2iI" : 1 + } + ], + + "errStrings" : [ + { + "string": "E2BIG",, + "s2iS" : 0, + "s2iI" : 8 + }, + { + "name": "EACCES", + "s2iS" : 6, + "s2iI" : 8 + }, + { + "name": "EADDRINUSE", + "s2iS" : 16, + "s2iI" : 8 + }, + { + "name": ,"EADDRNOTAVAIL", + "s2iS" : 23, + "s2iI" : 0 + }, + { + "name": ,"EADV", + "s2iS" : 28, + "s2iI" : 0 + }, + { + "name": ,"EAFNOSUPPORT", + "s2iS" : 33, + "s2iI" : 0 + }, + { + "name": ,"EAGAIN", + "s2iS" : 38, + "s2iI" : 0 + }, + { + "name": ,"EALREADY", + "s2iS" : 43, + "s2iI" : 0 + }, + { + "name": ,"EBADE", + "s2iS" : 48, + "s2iI" : 0 + }, + { + "name": ,"EBADF", + "s2iS" : 52, + "s2iI" : 0 + }, + { + "name": "EBADFD", + "s2iS" : 58, + "s2iI" : 0 + }, + { + "name": "EBADMSG", + "s2iS" : 63, + "s2iI" : 0 + }, + { + "name": "EBADR", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": "EBADRQC", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": ,"EBADSLT", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": ,"EBFONT", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": "EBUSY", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": "ECANCELED", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": "ECHILD", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": "ECHRNG", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": "ECOMM", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": "ECONNABORTED", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": "ECONNREFUSED", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": "ECONNRESET", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": "EDEADLK", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": "EDEADLOCK", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": "EDESTADDRREQ", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": "EDOM", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": "EDOTDOT", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": "EDQUOT", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": "EEXIST", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": "EFAULT", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": "EFBIG", + "s2iS" : 69, + "s2iI" : 0 + }, + { + "name": "EHOSTDOWN", + "s2iS" : 69, + "s2iI" : 0 + } + ] +} + +////////// Need to make message type follow http://www.filewatcher.com/p/audit-debuginfo-1.7.7-6.el5.ia64.rpm.955920/usr/src/debug/audit-1.7.7/lib/msg_typetabs.h.html to make it diff --git a/vendor/github.com/mozilla/libaudit-go/testdata/badpathnostrictpath.json b/vendor/github.com/mozilla/libaudit-go/testdata/badpathnostrictpath.json new file mode 100644 index 00000000..afc0077f --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/testdata/badpathnostrictpath.json @@ -0,0 +1,27 @@ +{ + "audit_rules": [ + { + "key": "nonexist", + "path": "/non/existent/path", + "permission": "wa", + "strict_path_check": false + }, + { + "actions": [ + "always", + "exit" + ], + "fields": [ + { + "name": "arch", + "op": "eq", + "value": 64 + } + ], + "key": "bypass", + "syscalls": [ + "personality" + ] + } + ] +} diff --git a/vendor/github.com/mozilla/libaudit-go/testdata/rules.json b/vendor/github.com/mozilla/libaudit-go/testdata/rules.json new file mode 100644 index 00000000..4eb44a0d --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/testdata/rules.json @@ -0,0 +1,111 @@ +{ + "audit_rules": [ + { + "key": "audit", + "path": "/etc/libaudit.conf", + "permission": "wa" + }, + { + "key": "syslog", + "path": "/etc/rsyslog.conf", + "permission": "wa" + }, + { + "actions": [ + "always", + "exit" + ], + "fields": [ + { + "name": "arch", + "op": "eq", + "value": 64 + } + ], + "key": "bypass", + "syscalls": [ + "personality" + ] + }, + { + "actions": [ + "exit", + "never" + ], + "fields": [ + { + "name": "path", + "op": "eq", + "value": "/bin/ls" + }, + { + "name": "perm", + "op": "eq", + "value": "x" + } + ] + }, + { + "actions": [ + "exit", + "always" + ], + "fields": [ + { + "name": "arch", + "op": "eq", + "value": 64 + } + ], + "key": "exec", + "syscalls": [ + "execve" + ] + }, + { + "actions": [ + "entry", + "always" + ], + "syscalls": [ + "clone", + "fork", + "vfork" + ] + }, + { + "actions": [ + "always", + "exit" + ], + "syscalls": [ + "settimeofday", + "adjtimex" + ], + "key": "time-change" + }, + { + "actions": [ + "always", + "exit" + ], + "fields": [ + { + "name": "arch", + "op": "eq", + "value": 64 + }, + { + "name": "auid", + "op": "gt_or_eq", + "value": 1000 + } + ], + "key": "rename", + "syscalls": [ + "rename", + "renameat" + ] + } + ] +} diff --git a/vendor/github.com/mozilla/libaudit-go/testdata/strictpathfail.json b/vendor/github.com/mozilla/libaudit-go/testdata/strictpathfail.json new file mode 100644 index 00000000..6625d503 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/testdata/strictpathfail.json @@ -0,0 +1,10 @@ +{ + "audit_rules": [ + { + "key": "nonexist", + "path": "/non/existent/path", + "permission": "wa", + "strict_path_check": true + } + ] +} diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/.travis.yml b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/.travis.yml new file mode 100644 index 00000000..8316e895 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/.travis.yml @@ -0,0 +1,10 @@ +language: go +sudo: false + +script: go test -v + +go: + - 1.2 + - 1.3 + - 1.4 + - tip diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/LICENSE b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/LICENSE new file mode 100644 index 00000000..42e82633 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015 Ryan Hileman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/README.md b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/README.md new file mode 100644 index 00000000..c8134971 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/README.md @@ -0,0 +1,103 @@ +[![Build Status](https://travis-ci.org/lunixbochs/struc.svg?branch=master)](https://travis-ci.org/lunixbochs/struc) + +struc +==== + +Struc exists to pack and unpack C-style structures from bytes, which is useful for binary files and network protocols. It could be considered an alternative to `encoding/binary`, which requires massive boilerplate for some similar operations. + +Take a look at an [example comparing `struc` and `encoding/binary`](https://bochs.info/p/cxvm9) + +Struc considers usability first. That said, it does cache reflection data and aims to be competitive with `encoding/binary` struct packing in every way, including performance. + +Example struct +---- + +```Go +type Example struct { + Var int `struc:"int32,sizeof=Str"` + Str string + Weird []byte `struc:"[8]int64"` + Var []int `struc:"[]int32,little"` +} +``` + +Struct tag format +---- + + - ```Var []int `struc:"[]int32,little,sizeof=StringField"` ``` will pack Var as a slice of little-endian int32, and link it as the size of `StringField`. + - `sizeof=`: Indicates this field is a number used to track the length of a another field. `sizeof` fields are automatically updated on `Pack()` based on the current length of the tracked field, and are used to size the target field during `Unpack()`. + - Bare values will be parsed as type and endianness. + +Endian formats +---- + + - `big` (default) + - `little` + +Recognized types +---- + + - `pad` - this type ignores field contents and is backed by a `[length]byte` containing nulls + - `bool` + - `byte` + - `int8`, `uint8` + - `int16`, `uint16` + - `int32`, `uint32` + - `int64`, `uint64` + - `float32` + - `float64` + +Types can be indicated as arrays/slices using `[]` syntax. Example: `[]int64`, `[8]int32`. + +Bare slice types (those with no `[size]`) must have a linked `Sizeof` field. + +Private fields are ignored when packing and unpacking. + +Example code +---- + +```Go +package main + +import ( + "bytes" + "github.com/lunixbochs/struc" +) + +type Example struct { + A int `struc:"big"` + + // B will be encoded/decoded as a 16-bit int (a "short") + // but is stored as a native int in the struct + B int `struc:"int16"` + + // the sizeof key links a buffer's size to any int field + Size int `struc:"int8,little,sizeof=Str"` + Str string + + // you can get freaky if you want + Str2 string `struc:"[5]int64"` +} + +func main() { + var buf bytes.Buffer + t := &Example{1, 2, 0, "test", "test2"} + err := struc.Pack(&buf, t) + o := &Example{} + err = struc.Unpack(&buf, o) +} +``` + +Benchmark +---- + +`BenchmarkEncode` uses struc. `Stdlib` benchmarks use equivalent `encoding/binary` code. `Manual` encodes without any reflection, and should be considered an upper bound on performance (which generated code based on struc definitions should be able to achieve). + +``` +BenchmarkEncode 1000000 1265 ns/op +BenchmarkStdlibEncode 1000000 1855 ns/op +BenchmarkManualEncode 5000000 284 ns/op +BenchmarkDecode 1000000 1259 ns/op +BenchmarkStdlibDecode 1000000 1656 ns/op +BenchmarkManualDecode 20000000 89.0 ns/op +``` diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/bench_test.go b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/bench_test.go new file mode 100644 index 00000000..d73c110f --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/bench_test.go @@ -0,0 +1,165 @@ +package struc + +import ( + "bytes" + "encoding/binary" + "testing" +) + +type BenchExample struct { + Test [5]byte + A int32 + B, C, D int16 + Test2 [4]byte + Length int32 +} + +type BenchStrucExample struct { + Test [5]byte `struc:"[5]byte"` + A int `struc:"int32"` + B, C, D int `struc:"int16"` + Test2 [4]byte `struc:"[4]byte"` + Length int `struc:"int32,sizeof=Data"` + Data []byte +} + +var benchRef = &BenchExample{ + [5]byte{1, 2, 3, 4, 5}, + 1, 2, 3, 4, + [4]byte{1, 2, 3, 4}, + 8, +} + +var eightBytes = []byte("8bytestr") + +var benchStrucRef = &BenchStrucExample{ + [5]byte{1, 2, 3, 4, 5}, + 1, 2, 3, 4, + [4]byte{1, 2, 3, 4}, + 8, eightBytes, +} + +func BenchmarkEncode(b *testing.B) { + for i := 0; i < b.N; i++ { + var buf bytes.Buffer + err := Pack(&buf, benchStrucRef) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkStdlibEncode(b *testing.B) { + for i := 0; i < b.N; i++ { + var buf bytes.Buffer + err := binary.Write(&buf, binary.BigEndian, benchRef) + if err != nil { + b.Fatal(err) + } + _, err = buf.Write(eightBytes) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkManualEncode(b *testing.B) { + order := binary.BigEndian + s := benchStrucRef + for i := 0; i < b.N; i++ { + var buf bytes.Buffer + tmp := make([]byte, 29) + copy(tmp[0:5], s.Test[:]) + order.PutUint32(tmp[5:9], uint32(s.A)) + order.PutUint16(tmp[9:11], uint16(s.B)) + order.PutUint16(tmp[11:13], uint16(s.C)) + order.PutUint16(tmp[13:15], uint16(s.D)) + copy(tmp[15:19], s.Test2[:]) + order.PutUint32(tmp[19:23], uint32(s.Length)) + copy(tmp[23:], s.Data) + _, err := buf.Write(tmp) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkDecode(b *testing.B) { + var out BenchStrucExample + var buf bytes.Buffer + if err := Pack(&buf, benchStrucRef); err != nil { + b.Fatal(err) + } + bufBytes := buf.Bytes() + for i := 0; i < b.N; i++ { + buf := bytes.NewReader(bufBytes) + err := Unpack(buf, &out) + if err != nil { + b.Fatal(err) + } + out.Data = nil + } +} + +func BenchmarkStdlibDecode(b *testing.B) { + var out BenchExample + var buf bytes.Buffer + binary.Write(&buf, binary.BigEndian, *benchRef) + _, err := buf.Write(eightBytes) + if err != nil { + b.Fatal(err) + } + bufBytes := buf.Bytes() + for i := 0; i < b.N; i++ { + buf := bytes.NewReader(bufBytes) + err := binary.Read(buf, binary.BigEndian, &out) + if err != nil { + b.Fatal(err) + } + tmp := make([]byte, out.Length) + _, err = buf.Read(tmp) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkManualDecode(b *testing.B) { + var o BenchStrucExample + var buf bytes.Buffer + if err := Pack(&buf, benchStrucRef); err != nil { + b.Fatal(err) + } + tmp := buf.Bytes() + order := binary.BigEndian + for i := 0; i < b.N; i++ { + copy(o.Test[:], tmp[0:5]) + o.A = int(order.Uint32(tmp[5:9])) + o.B = int(order.Uint16(tmp[9:11])) + o.C = int(order.Uint16(tmp[11:13])) + o.D = int(order.Uint16(tmp[13:15])) + copy(o.Test2[:], tmp[15:19]) + o.Length = int(order.Uint32(tmp[19:23])) + o.Data = make([]byte, o.Length) + copy(o.Data, tmp[23:]) + } +} + +func BenchmarkFullEncode(b *testing.B) { + for i := 0; i < b.N; i++ { + var buf bytes.Buffer + if err := Pack(&buf, reference); err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkFullDecode(b *testing.B) { + var out Example + for i := 0; i < b.N; i++ { + buf := bytes.NewBuffer(referenceBytes) + if err := Unpack(buf, &out); err != nil { + b.Fatal(err) + } + } +} diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/binary.go b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/binary.go new file mode 100644 index 00000000..4899d08f --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/binary.go @@ -0,0 +1,52 @@ +package struc + +import ( + "encoding/binary" + "io" + "reflect" +) + +type byteWriter struct { + buf []byte + pos int +} + +func (b byteWriter) Write(p []byte) (int, error) { + capacity := len(b.buf) - b.pos + if capacity < len(p) { + p = p[:capacity] + } + if len(p) > 0 { + copy(b.buf[b.pos:], p) + b.pos += len(p) + } + return len(p), nil +} + +type binaryFallback reflect.Value + +func (b binaryFallback) String() string { + return b.String() +} + +func (b binaryFallback) Sizeof(val reflect.Value, options *Options) int { + return binary.Size(val.Interface()) +} + +func (b binaryFallback) Pack(buf []byte, val reflect.Value, options *Options) (int, error) { + tmp := byteWriter{buf: buf} + var order binary.ByteOrder = binary.BigEndian + if options.Order != nil { + order = options.Order + } + err := binary.Write(tmp, order, val.Interface()) + return tmp.pos, err +} + +func (b binaryFallback) Unpack(r io.Reader, val reflect.Value, options *Options) error { + var order binary.ByteOrder = binary.BigEndian + if options.Order != nil { + order = options.Order + } + return binary.Read(r, order, val.Interface()) +} diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/custom.go b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/custom.go new file mode 100644 index 00000000..c468dce5 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/custom.go @@ -0,0 +1,33 @@ +package struc + +import ( + "io" + "reflect" +) + +type Custom interface { + Pack(p []byte, opt *Options) (int, error) + Unpack(r io.Reader, length int, opt *Options) error + Size(opt *Options) int + String() string +} + +type customFallback struct { + custom Custom +} + +func (c customFallback) Pack(p []byte, val reflect.Value, opt *Options) (int, error) { + return c.custom.Pack(p, opt) +} + +func (c customFallback) Unpack(r io.Reader, val reflect.Value, opt *Options) error { + return c.custom.Unpack(r, 1, opt) +} + +func (c customFallback) Sizeof(val reflect.Value, opt *Options) int { + return c.custom.Size(opt) +} + +func (c customFallback) String() string { + return c.custom.String() +} diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/custom_float16.go b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/custom_float16.go new file mode 100644 index 00000000..722be765 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/custom_float16.go @@ -0,0 +1,78 @@ +package struc + +import ( + "encoding/binary" + "io" + "math" + "strconv" +) + +type Float16 float64 + +func (f *Float16) Pack(p []byte, opt *Options) (int, error) { + order := opt.Order + if order == nil { + order = binary.BigEndian + } + sign := uint16(0) + if *f < 0 { + sign = 1 + } + var frac, exp uint16 + if math.IsInf(float64(*f), 0) { + exp = 0x1f + frac = 0 + } else if math.IsNaN(float64(*f)) { + exp = 0x1f + frac = 1 + } else { + bits := math.Float64bits(float64(*f)) + exp64 := (bits >> 52) & 0x7ff + if exp64 != 0 { + exp = uint16((exp64 - 1023 + 15) & 0x1f) + } + frac = uint16((bits >> 42) & 0x3ff) + } + var out uint16 + out |= sign << 15 + out |= exp << 10 + out |= frac & 0x3ff + order.PutUint16(p, out) + return 2, nil +} +func (f *Float16) Unpack(r io.Reader, length int, opt *Options) error { + order := opt.Order + if order == nil { + order = binary.BigEndian + } + var tmp [2]byte + if _, err := r.Read(tmp[:]); err != nil { + return err + } + val := order.Uint16(tmp[:2]) + sign := (val >> 15) & 1 + exp := int16((val >> 10) & 0x1f) + frac := val & 0x3ff + if exp == 0x1f { + if frac != 0 { + *f = Float16(math.NaN()) + } else { + *f = Float16(math.Inf(int(sign)*-2 + 1)) + } + } else { + var bits uint64 + bits |= uint64(sign) << 63 + bits |= uint64(frac) << 42 + if exp > 0 { + bits |= uint64(exp-15+1023) << 52 + } + *f = Float16(math.Float64frombits(bits)) + } + return nil +} +func (f *Float16) Size(opt *Options) int { + return 2 +} +func (f *Float16) String() string { + return strconv.FormatFloat(float64(*f), 'g', -1, 32) +} diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/custom_float16_test.go b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/custom_float16_test.go new file mode 100644 index 00000000..11f73cbc --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/custom_float16_test.go @@ -0,0 +1,56 @@ +package struc + +import ( + "bytes" + "encoding/binary" + "fmt" + "math" + "strconv" + "strings" + "testing" +) + +func TestFloat16(t *testing.T) { + // test cases from https://en.wikipedia.org/wiki/Half-precision_floating-point_format#Half_precision_examples + tests := []struct { + B string + F float64 + }{ + //s expnt significand + {"0 01111 0000000000", 1}, + {"0 01111 0000000001", 1.0009765625}, + {"1 10000 0000000000", -2}, + {"0 11110 1111111111", 65504}, + // {"0 00001 0000000000", 0.0000610352}, + // {"0 00000 1111111111", 0.0000609756}, + // {"0 00000 0000000001", 0.0000000596046}, + {"0 00000 0000000000", 0}, + // {"1 00000 0000000000", -0}, + {"0 11111 0000000000", math.Inf(1)}, + {"1 11111 0000000000", math.Inf(-1)}, + {"0 01101 0101010101", 0.333251953125}, + } + for _, test := range tests { + var buf bytes.Buffer + f := Float16(test.F) + if err := Pack(&buf, &f); err != nil { + t.Error("pack failed:", err) + continue + } + bitval, _ := strconv.ParseUint(strings.Replace(test.B, " ", "", -1), 2, 16) + tmp := binary.BigEndian.Uint16(buf.Bytes()) + if tmp != uint16(bitval) { + t.Errorf("incorrect pack: %s != %016b (%f)", test.B, tmp, test.F) + continue + } + var f2 Float16 + if err := Unpack(&buf, &f2); err != nil { + t.Error("unpack failed:", err) + continue + } + // let sprintf deal with (im)precision for me here + if fmt.Sprintf("%f", f) != fmt.Sprintf("%f", f2) { + t.Errorf("incorrect unpack: %016b %f != %f", bitval, f, f2) + } + } +} diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/custom_test.go b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/custom_test.go new file mode 100644 index 00000000..e601166d --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/custom_test.go @@ -0,0 +1,97 @@ +package struc + +import ( + "bytes" + "encoding/binary" + "io" + "strconv" + "testing" +) + +type Int3 uint32 + +func (i *Int3) Pack(p []byte, opt *Options) (int, error) { + var tmp [4]byte + binary.BigEndian.PutUint32(tmp[:], uint32(*i)) + copy(p, tmp[1:]) + return 3, nil +} +func (i *Int3) Unpack(r io.Reader, length int, opt *Options) error { + var tmp [4]byte + if _, err := r.Read(tmp[1:]); err != nil { + return err + } + *i = Int3(binary.BigEndian.Uint32(tmp[:])) + return nil +} +func (i *Int3) Size(opt *Options) int { + return 3 +} +func (i *Int3) String() string { + return strconv.FormatUint(uint64(*i), 10) +} + +func TestCustom(t *testing.T) { + var buf bytes.Buffer + var i Int3 = 3 + if err := Pack(&buf, &i); err != nil { + t.Fatal(err) + } + if !bytes.Equal(buf.Bytes(), []byte{0, 0, 3}) { + t.Fatal("error packing custom int") + } + var i2 Int3 + if err := Unpack(&buf, &i2); err != nil { + t.Fatal(err) + } + if i2 != 3 { + t.Fatal("error unpacking custom int") + } +} + +type Int3Struct struct { + I Int3 +} + +func TestCustomStruct(t *testing.T) { + var buf bytes.Buffer + i := Int3Struct{3} + if err := Pack(&buf, &i); err != nil { + t.Fatal(err) + } + if !bytes.Equal(buf.Bytes(), []byte{0, 0, 3}) { + t.Fatal("error packing custom int struct") + } + var i2 Int3Struct + if err := Unpack(&buf, &i2); err != nil { + t.Fatal(err) + } + if i2.I != 3 { + t.Fatal("error unpacking custom int struct") + } +} + +// TODO: slices of custom types don't work yet +/* +type Int3SliceStruct struct { + I [2]Int3 +} + +func TestCustomSliceStruct(t *testing.T) { + var buf bytes.Buffer + i := Int3SliceStruct{[2]Int3{3, 4}} + if err := Pack(&buf, &i); err != nil { + t.Fatal(err) + } + if !bytes.Equal(buf.Bytes(), []byte{0, 0, 3}) { + t.Fatal("error packing custom int struct") + } + var i2 Int3SliceStruct + if err := Unpack(&buf, &i2); err != nil { + t.Fatal(err) + } + if i2.I[0] != 3 && i2.I[1] != 4 { + t.Fatal("error unpacking custom int struct") + } +} +*/ diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/field.go b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/field.go new file mode 100644 index 00000000..4af10a71 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/field.go @@ -0,0 +1,281 @@ +package struc + +import ( + "bytes" + "encoding/binary" + "fmt" + "math" + "reflect" +) + +type Field struct { + Name string + CanSet bool + Ptr bool + Index int + Type Type + defType Type + Array bool + Slice bool + Len int + Order binary.ByteOrder + Sizeof []int + Sizefrom []int + Fields Fields + kind reflect.Kind +} + +func (f *Field) String() string { + var out string + if f.Type == Pad { + return fmt.Sprintf("{type: Pad, len: %d}", f.Len) + } else { + out = fmt.Sprintf("type: %s, order: %v", f.Type.String(), f.Order) + } + if f.Sizefrom != nil { + out += fmt.Sprintf(", sizefrom: %v", f.Sizefrom) + } else if f.Len > 0 { + out += fmt.Sprintf(", len: %d", f.Len) + } + if f.Sizeof != nil { + out += fmt.Sprintf(", sizeof: %v", f.Sizeof) + } + return "{" + out + "}" +} + +func (f *Field) Size(val reflect.Value, options *Options) int { + typ := f.Type.Resolve(options) + size := 0 + if typ == Struct { + vals := []reflect.Value{val} + if f.Slice { + vals = make([]reflect.Value, val.Len()) + for i := 0; i < val.Len(); i++ { + vals[i] = val.Index(i) + } + } + for _, val := range vals { + size += f.Fields.Sizeof(val, options) + } + } else if typ == Pad { + size = f.Len + } else if f.Slice || f.kind == reflect.String { + length := val.Len() + if f.Len > 1 { + length = f.Len + } + size = length * typ.Size() + } else if typ == CustomType { + return val.Addr().Interface().(Custom).Size(options) + } else { + size = typ.Size() + } + align := options.ByteAlign + if align > 0 && size < align { + size = align + } + return size +} + +func (f *Field) packVal(buf []byte, val reflect.Value, length int, options *Options) (size int, err error) { + order := f.Order + if options.Order != nil { + order = options.Order + } + if f.Ptr { + val = val.Elem() + } + typ := f.Type.Resolve(options) + switch typ { + case Struct: + return f.Fields.Pack(buf, val, options) + case Bool, Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64: + size = typ.Size() + var n uint64 + switch f.kind { + case reflect.Bool: + if val.Bool() { + n = 1 + } else { + n = 0 + } + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n = uint64(val.Int()) + default: + n = val.Uint() + } + switch typ { + case Bool: + if n != 0 { + buf[0] = 1 + } else { + buf[0] = 0 + } + case Int8, Uint8: + buf[0] = byte(n) + case Int16, Uint16: + order.PutUint16(buf, uint16(n)) + case Int32, Uint32: + order.PutUint32(buf, uint32(n)) + case Int64, Uint64: + order.PutUint64(buf, uint64(n)) + } + case Float32, Float64: + size = typ.Size() + n := val.Float() + switch typ { + case Float32: + order.PutUint32(buf, math.Float32bits(float32(n))) + case Float64: + order.PutUint64(buf, math.Float64bits(n)) + } + case String: + switch f.kind { + case reflect.String: + size = val.Len() + copy(buf, []byte(val.String())) + default: + // TODO: handle kind != bytes here + size = val.Len() + copy(buf, val.Bytes()) + } + case CustomType: + return val.Addr().Interface().(Custom).Pack(buf, options) + default: + panic(fmt.Sprintf("no pack handler for type: %s", typ)) + } + return +} + +func (f *Field) Pack(buf []byte, val reflect.Value, length int, options *Options) (int, error) { + typ := f.Type.Resolve(options) + if typ == Pad { + for i := 0; i < length; i++ { + buf[i] = 0 + } + return length, nil + } + if f.Slice { + // special case strings and byte slices for performance + end := val.Len() + if !f.Array && typ == Uint8 && (f.defType == Uint8 || f.kind == reflect.String) { + var tmp []byte + if f.kind == reflect.String { + tmp = []byte(val.String()) + } else { + tmp = val.Bytes() + } + copy(buf, tmp) + if end < length { + // TODO: allow configuring pad byte? + rep := bytes.Repeat([]byte{0}, length-end) + copy(buf[end:], rep) + return length, nil + } + return val.Len(), nil + } + pos := 0 + var zero reflect.Value + if end < length { + zero = reflect.Zero(val.Type().Elem()) + } + for i := 0; i < length; i++ { + cur := zero + if i < end { + cur = val.Index(i) + } + if n, err := f.packVal(buf[pos:], cur, 1, options); err != nil { + return pos, err + } else { + pos += n + } + } + return pos, nil + } else { + return f.packVal(buf, val, length, options) + } +} + +func (f *Field) unpackVal(buf []byte, val reflect.Value, length int, options *Options) error { + order := f.Order + if options.Order != nil { + order = options.Order + } + if f.Ptr { + val = val.Elem() + } + typ := f.Type.Resolve(options) + switch typ { + case Float32, Float64: + var n float64 + switch typ { + case Float32: + n = float64(math.Float32frombits(order.Uint32(buf))) + case Float64: + n = math.Float64frombits(order.Uint64(buf)) + } + switch f.kind { + case reflect.Float32, reflect.Float64: + val.SetFloat(n) + default: + return fmt.Errorf("struc: refusing to unpack float into field %s of type %s", f.Name, f.kind.String()) + } + case Bool, Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64: + var n uint64 + switch typ { + case Bool, Int8, Uint8: + n = uint64(buf[0]) + case Int16, Uint16: + n = uint64(order.Uint16(buf)) + case Int32, Uint32: + n = uint64(order.Uint32(buf)) + case Int64, Uint64: + n = uint64(order.Uint64(buf)) + } + switch f.kind { + case reflect.Bool: + val.SetBool(n != 0) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + val.SetInt(int64(n)) + default: + val.SetUint(n) + } + default: + panic(fmt.Sprintf("no unpack handler for type: %s", typ)) + } + return nil +} + +func (f *Field) Unpack(buf []byte, val reflect.Value, length int, options *Options) error { + typ := f.Type.Resolve(options) + if typ == Pad || f.kind == reflect.String { + if typ == Pad { + return nil + } else { + val.SetString(string(buf)) + return nil + } + } else if f.Slice { + if val.Cap() < length { + val.Set(reflect.MakeSlice(val.Type(), length, length)) + } else if val.Len() < length { + val.Set(val.Slice(0, length)) + } + // special case byte slices for performance + if !f.Array && typ == Uint8 && f.defType == Uint8 { + copy(val.Bytes(), buf[:length]) + return nil + } + pos := 0 + size := typ.Size() + for i := 0; i < length; i++ { + if err := f.unpackVal(buf[pos:pos+size], val.Index(i), 1, options); err != nil { + return err + } + pos += size + } + return nil + } else { + return f.unpackVal(buf, val, length, options) + } +} diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/field_test.go b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/field_test.go new file mode 100644 index 00000000..45a07b21 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/field_test.go @@ -0,0 +1,77 @@ +package struc + +import ( + "bytes" + "testing" +) + +type badFloat struct { + BadFloat int `struc:"float64"` +} + +func TestBadFloatField(t *testing.T) { + buf := bytes.NewReader([]byte("00000000")) + err := Unpack(buf, &badFloat{}) + if err == nil { + t.Fatal("failed to error on bad float unpack") + } +} + +type emptyLengthField struct { + Strlen int `struc:"sizeof=Str"` + Str []byte +} + +func TestEmptyLengthField(t *testing.T) { + var buf bytes.Buffer + s := &emptyLengthField{0, []byte("test")} + o := &emptyLengthField{} + if err := Pack(&buf, s); err != nil { + t.Fatal(err) + } + if err := Unpack(&buf, o); err != nil { + t.Fatal(err) + } + if !bytes.Equal(s.Str, o.Str) { + t.Fatal("empty length field encode failed") + } +} + +type fixedSlicePad struct { + Field []byte `struc:"[4]byte"` +} + +func TestFixedSlicePad(t *testing.T) { + var buf bytes.Buffer + ref := []byte{0, 0, 0, 0} + s := &fixedSlicePad{} + if err := Pack(&buf, s); err != nil { + t.Fatal(err) + } + if !bytes.Equal(buf.Bytes(), ref) { + t.Fatal("implicit fixed slice pack failed") + } + if err := Unpack(&buf, s); err != nil { + t.Fatal(err) + } + if !bytes.Equal(s.Field, ref) { + t.Fatal("implicit fixed slice unpack failed") + } +} + +type sliceCap struct { + Len int `struc:"sizeof=Field"` + Field []byte +} + +func TestSliceCap(t *testing.T) { + var buf bytes.Buffer + tmp := &sliceCap{0, []byte("1234")} + if err := Pack(&buf, tmp); err != nil { + t.Fatal(err) + } + tmp.Field = make([]byte, 0, 4) + if err := Unpack(&buf, tmp); err != nil { + t.Fatal(err) + } +} diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/fields.go b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/fields.go new file mode 100644 index 00000000..80e20459 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/fields.go @@ -0,0 +1,169 @@ +package struc + +import ( + "encoding/binary" + "fmt" + "io" + "reflect" + "strings" +) + +type Fields []*Field + +func (f Fields) SetByteOrder(order binary.ByteOrder) { + for _, field := range f { + field.Order = order + } +} + +func (f Fields) String() string { + fields := make([]string, len(f)) + for i, field := range f { + fields[i] = field.String() + } + return "{" + strings.Join(fields, ", ") + "}" +} + +func (f Fields) Sizeof(val reflect.Value, options *Options) int { + for val.Kind() == reflect.Ptr { + val = val.Elem() + } + size := 0 + for i, field := range f { + v := val.Field(i) + if v.CanSet() { + size += field.Size(v, options) + } + } + return size +} + +func (f Fields) sizefrom(val reflect.Value, index []int) int { + field := val.FieldByIndex(index) + switch field.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return int(field.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + n := int(field.Uint()) + // all the builtin array length types are native int + // so this guards against weird truncation + if n < 0 { + return 0 + } + return n + default: + name := val.Type().FieldByIndex(index).Name + panic(fmt.Sprintf("sizeof field %T.%s not an integer type", val.Interface(), name)) + } +} + +func (f Fields) Pack(buf []byte, val reflect.Value, options *Options) (int, error) { + for val.Kind() == reflect.Ptr { + val = val.Elem() + } + pos := 0 + for i, field := range f { + if !field.CanSet { + continue + } + v := val.Field(i) + length := field.Len + if field.Sizefrom != nil { + length = f.sizefrom(val, field.Sizefrom) + } + if length <= 0 && field.Slice { + length = v.Len() + } + if field.Sizeof != nil { + length := val.FieldByIndex(field.Sizeof).Len() + switch field.kind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + // allocating a new int here has fewer side effects (doesn't update the original struct) + // but it's a wasteful allocation + // the old method might work if we just cast the temporary int/uint to the target type + v = reflect.New(v.Type()).Elem() + v.SetInt(int64(length)) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + v = reflect.New(v.Type()).Elem() + v.SetUint(uint64(length)) + default: + panic(fmt.Sprintf("sizeof field is not int or uint type: %s, %s", field.Name, v.Type())) + } + } + if n, err := field.Pack(buf[pos:], v, length, options); err != nil { + return n, err + } else { + pos += n + } + } + return pos, nil +} + +func (f Fields) Unpack(r io.Reader, val reflect.Value, options *Options) error { + for val.Kind() == reflect.Ptr { + val = val.Elem() + } + var tmp [8]byte + var buf []byte + for i, field := range f { + if !field.CanSet { + continue + } + v := val.Field(i) + length := field.Len + if field.Sizefrom != nil { + length = f.sizefrom(val, field.Sizefrom) + } + if v.Kind() == reflect.Ptr && !v.Elem().IsValid() { + v.Set(reflect.New(v.Type().Elem())) + } + if field.Type == Struct { + if field.Slice { + vals := reflect.MakeSlice(v.Type(), length, length) + for i := 0; i < length; i++ { + v := vals.Index(i) + fields, err := parseFields(v) + if err != nil { + return err + } + if err := fields.Unpack(r, v, options); err != nil { + return err + } + } + v.Set(vals) + } else { + // TODO: DRY (we repeat the inner loop above) + fields, err := parseFields(v) + if err != nil { + return err + } + if err := fields.Unpack(r, v, options); err != nil { + return err + } + } + continue + } else { + typ := field.Type.Resolve(options) + if typ == CustomType { + if err := v.Addr().Interface().(Custom).Unpack(r, length, options); err != nil { + return err + } + } else { + size := length * field.Type.Resolve(options).Size() + if size < 8 { + buf = tmp[:size] + } else { + buf = make([]byte, size) + } + if _, err := io.ReadFull(r, buf); err != nil { + return err + } + err := field.Unpack(buf[:size], v, length, options) + if err != nil { + return err + } + } + } + } + return nil +} diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/fields_test.go b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/fields_test.go new file mode 100644 index 00000000..850e3775 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/fields_test.go @@ -0,0 +1,59 @@ +package struc + +import ( + "bytes" + "reflect" + "testing" +) + +var refVal = reflect.ValueOf(reference) + +func TestFieldsParse(t *testing.T) { + if _, err := parseFields(refVal); err != nil { + t.Fatal(err) + } +} + +func TestFieldsString(t *testing.T) { + fields, _ := parseFields(refVal) + fields.String() +} + +type sizefromStruct struct { + Size1 uint `struc:"sizeof=Var1"` + Var1 []byte + Size2 int `struc:"sizeof=Var2"` + Var2 []byte +} + +func TestFieldsSizefrom(t *testing.T) { + var test = sizefromStruct{ + Var1: []byte{1, 2, 3}, + Var2: []byte{4, 5, 6}, + } + var buf bytes.Buffer + err := Pack(&buf, &test) + if err != nil { + t.Fatal(err) + } + err = Unpack(&buf, &test) + if err != nil { + t.Fatal(err) + } +} + +type sizefromStructBad struct { + Size1 string `struc:"sizeof=Var1"` + Var1 []byte +} + +func TestFieldsSizefromBad(t *testing.T) { + var test = &sizefromStructBad{Var1: []byte{1, 2, 3}} + var buf bytes.Buffer + defer func() { + if err := recover(); err == nil { + t.Fatal("failed to panic on bad sizeof type") + } + }() + Pack(&buf, &test) +} diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/legacy.go b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/legacy.go new file mode 100644 index 00000000..5baf70d9 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/legacy.go @@ -0,0 +1,16 @@ +package struc + +import ( + "encoding/binary" + "io" +) + +// Deprecated. Use PackWithOptions. +func PackWithOrder(w io.Writer, data interface{}, order binary.ByteOrder) error { + return PackWithOptions(w, data, &Options{Order: order}) +} + +// Deprecated. Use UnpackWithOptions. +func UnpackWithOrder(r io.Reader, data interface{}, order binary.ByteOrder) error { + return UnpackWithOptions(r, data, &Options{Order: order}) +} diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/packable_test.go b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/packable_test.go new file mode 100644 index 00000000..ec2bed9b --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/packable_test.go @@ -0,0 +1,123 @@ +package struc + +import ( + "bytes" + "fmt" + "testing" +) + +var packableReference = []byte{ + 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 5, 0, 6, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, +} + +func TestPackable(t *testing.T) { + var ( + buf bytes.Buffer + + i8 int8 = 1 + i16 int16 = 2 + i32 int32 = 3 + i64 int64 = 4 + u8 uint8 = 5 + u16 uint16 = 6 + u32 uint32 = 7 + u64 uint64 = 8 + + u8a = [8]uint8{9, 10, 11, 12, 13, 14, 15, 16} + u16a = [8]uint16{17, 18, 19, 20, 21, 22, 23, 24} + ) + // pack tests + if err := Pack(&buf, i8); err != nil { + t.Fatal(err) + } + if err := Pack(&buf, i16); err != nil { + t.Fatal(err) + } + if err := Pack(&buf, i32); err != nil { + t.Fatal(err) + } + if err := Pack(&buf, i64); err != nil { + t.Fatal(err) + } + if err := Pack(&buf, u8); err != nil { + t.Fatal(err) + } + if err := Pack(&buf, u16); err != nil { + t.Fatal(err) + } + if err := Pack(&buf, u32); err != nil { + t.Fatal(err) + } + if err := Pack(&buf, u64); err != nil { + t.Fatal(err) + } + if err := Pack(&buf, u8a[:]); err != nil { + t.Fatal(err) + } + if err := Pack(&buf, u16a[:]); err != nil { + t.Fatal(err) + } + if !bytes.Equal(buf.Bytes(), packableReference) { + fmt.Println(buf.Bytes()) + fmt.Println(packableReference) + t.Fatal("Packable Pack() did not match reference.") + } + // unpack tests + i8 = 0 + i16 = 0 + i32 = 0 + i64 = 0 + u8 = 0 + u16 = 0 + u32 = 0 + u64 = 0 + if err := Unpack(&buf, &i8); err != nil { + t.Fatal(err) + } + if err := Unpack(&buf, &i16); err != nil { + t.Fatal(err) + } + if err := Unpack(&buf, &i32); err != nil { + t.Fatal(err) + } + if err := Unpack(&buf, &i64); err != nil { + t.Fatal(err) + } + if err := Unpack(&buf, &u8); err != nil { + t.Fatal(err) + } + if err := Unpack(&buf, &u16); err != nil { + t.Fatal(err) + } + if err := Unpack(&buf, &u32); err != nil { + t.Fatal(err) + } + if err := Unpack(&buf, &u64); err != nil { + t.Fatal(err) + } + if err := Unpack(&buf, u8a[:]); err != nil { + t.Fatal(err) + } + if err := Unpack(&buf, u16a[:]); err != nil { + t.Fatal(err) + } + // unpack checks + if i8 != 1 || i16 != 2 || i32 != 3 || i64 != 4 { + t.Fatal("Signed integer unpack failed.") + } + if u8 != 5 || u16 != 6 || u32 != 7 || u64 != 8 { + t.Fatal("Unsigned integer unpack failed.") + } + for i := 0; i < 8; i++ { + if u8a[i] != uint8(i+9) { + t.Fatal("uint8 array unpack failed.") + } + } + for i := 0; i < 8; i++ { + if u16a[i] != uint16(i+17) { + t.Fatal("uint16 array unpack failed.") + } + } +} diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/packer.go b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/packer.go new file mode 100644 index 00000000..a3a91a22 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/packer.go @@ -0,0 +1,13 @@ +package struc + +import ( + "io" + "reflect" +) + +type Packer interface { + Pack(buf []byte, val reflect.Value, options *Options) (int, error) + Unpack(r io.Reader, val reflect.Value, options *Options) error + Sizeof(val reflect.Value, options *Options) int + String() string +} diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/parse.go b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/parse.go new file mode 100644 index 00000000..5a30d535 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/parse.go @@ -0,0 +1,217 @@ +package struc + +import ( + "encoding/binary" + "errors" + "fmt" + "reflect" + "regexp" + "strconv" + "strings" + "sync" +) + +// struc:"int32,big,sizeof=Data" + +var tagWordsRe = regexp.MustCompile(`(\[|\b)[^"]+\b+$`) + +type strucTag struct { + Type string + Order binary.ByteOrder + Sizeof string +} + +func parseStrucTag(tag reflect.StructTag) *strucTag { + t := &strucTag{ + Order: binary.BigEndian, + } + tagStr := tag.Get("struc") + if tagStr == "" { + // someone's going to typo this (I already did once) + // sorry if you made a module actually using this tag + // and you're mad at me now + tagStr = tag.Get("struct") + } + for _, s := range strings.Split(tagStr, ",") { + if strings.HasPrefix(s, "sizeof=") { + tmp := strings.SplitN(s, "=", 2) + t.Sizeof = tmp[1] + } else if s == "big" { + t.Order = binary.BigEndian + } else if s == "little" { + t.Order = binary.LittleEndian + } else { + t.Type = s + } + } + return t +} + +var typeLenRe = regexp.MustCompile(`^\[(\d*)\]`) + +func parseField(f reflect.StructField) (fd *Field, err error) { + tag := parseStrucTag(f.Tag) + var ok bool + fd = &Field{ + Name: f.Name, + Len: 1, + Order: tag.Order, + Slice: false, + kind: f.Type.Kind(), + } + switch fd.kind { + case reflect.Array: + fd.Slice = true + fd.Array = true + fd.Len = f.Type.Len() + fd.kind = f.Type.Elem().Kind() + case reflect.Slice: + fd.Slice = true + fd.Len = -1 + fd.kind = f.Type.Elem().Kind() + case reflect.Ptr: + fd.Ptr = true + fd.kind = f.Type.Elem().Kind() + } + // check for custom types + tmp := reflect.New(f.Type) + if _, ok := tmp.Interface().(Custom); ok { + fd.Type = CustomType + return + } + var defTypeOk bool + fd.defType, defTypeOk = reflectTypeMap[fd.kind] + // find a type in the struct tag + pureType := typeLenRe.ReplaceAllLiteralString(tag.Type, "") + if fd.Type, ok = typeLookup[pureType]; ok { + fd.Len = 1 + match := typeLenRe.FindAllStringSubmatch(tag.Type, -1) + if len(match) > 0 && len(match[0]) > 1 { + fd.Slice = true + first := match[0][1] + // Field.Len = -1 indicates a []slice + if first == "" { + fd.Len = -1 + } else { + fd.Len, err = strconv.Atoi(first) + } + } + return + } + // the user didn't specify a type + switch f.Type { + case reflect.TypeOf(Size_t(0)): + fd.Type = SizeType + case reflect.TypeOf(Off_t(0)): + fd.Type = OffType + default: + if defTypeOk { + fd.Type = fd.defType + } else { + err = errors.New("struc: Could not find field type.") + } + } + return +} + +func parseFieldsLocked(v reflect.Value) (Fields, error) { + // we need to repeat this logic because parseFields() below can't be recursively called due to locking + for v.Kind() == reflect.Ptr { + v = v.Elem() + } + t := v.Type() + if v.NumField() < 1 { + return nil, errors.New("struc: Struct has no fields.") + } + sizeofMap := make(map[string][]int) + fields := make(Fields, 0, v.NumField()) + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + f, err := parseField(field) + if err != nil { + return nil, err + } + f.CanSet = v.Field(i).CanSet() + if !f.CanSet { + continue + } + f.Index = i + tag := parseStrucTag(field.Tag) + if tag.Sizeof != "" { + target, ok := t.FieldByName(tag.Sizeof) + if !ok { + return nil, fmt.Errorf("struc: `sizeof=%s` field does not exist", tag.Sizeof) + } + f.Sizeof = target.Index + sizeofMap[tag.Sizeof] = field.Index + } + if sizefrom, ok := sizeofMap[field.Name]; ok { + f.Sizefrom = sizefrom + } + if f.Len == -1 && f.Sizefrom == nil { + return nil, fmt.Errorf("struc: field `%s` is a slice with no length or sizeof field", field.Name) + } + // recurse into nested structs + // TODO: handle loops (probably by indirecting the []Field and putting pointer in cache) + if f.Type == Struct { + typ := field.Type + if f.Ptr { + typ = typ.Elem() + } + if f.Slice { + typ = typ.Elem() + } + f.Fields, err = parseFieldsLocked(reflect.New(typ)) + if err != nil { + return nil, err + } + } + fields = append(fields, f) + } + return fields, nil +} + +var fieldCache = make(map[reflect.Type]Fields) +var fieldCacheLock sync.RWMutex +var parseLock sync.Mutex + +func fieldCacheLookup(t reflect.Type) Fields { + fieldCacheLock.RLock() + defer fieldCacheLock.RUnlock() + if cached, ok := fieldCache[t]; ok { + return cached + } + return nil +} + +func parseFields(v reflect.Value) (Fields, error) { + for v.Kind() == reflect.Ptr { + v = v.Elem() + } + t := v.Type() + + // fast path: hopefully the field parsing is already cached + if cached := fieldCacheLookup(t); cached != nil { + return cached, nil + } + + // hold a global lock so multiple goroutines can't parse (the same) fields at once + parseLock.Lock() + defer parseLock.Unlock() + + // check cache a second time, in case parseLock was just released by + // another thread who filled the cache for us + if cached := fieldCacheLookup(t); cached != nil { + return cached, nil + } + + // no luck, time to parse and fill the cache ourselves + fields, err := parseFieldsLocked(v) + if err != nil { + return nil, err + } + fieldCacheLock.Lock() + fieldCache[t] = fields + fieldCacheLock.Unlock() + return fields, nil +} diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/parse_test.go b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/parse_test.go new file mode 100644 index 00000000..861fdd19 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/parse_test.go @@ -0,0 +1,62 @@ +package struc + +import ( + "bytes" + "reflect" + "testing" +) + +func parseTest(data interface{}) error { + _, err := parseFields(reflect.ValueOf(data)) + return err +} + +type empty struct{} + +func TestEmptyStruc(t *testing.T) { + if err := parseTest(&empty{}); err == nil { + t.Fatal("failed to error on empty struct") + } +} + +type chanStruct struct { + Test chan int +} + +func TestChanError(t *testing.T) { + if err := parseTest(&chanStruct{}); err == nil { + // TODO: should probably ignore channel fields + t.Fatal("failed to error on struct containing channel") + } +} + +type badSizeof struct { + Size int `struc:"sizeof=Bad"` +} + +func TestBadSizeof(t *testing.T) { + if err := parseTest(&badSizeof{}); err == nil { + t.Fatal("failed to error on missing Sizeof target") + } +} + +type missingSize struct { + Test []byte +} + +func TestMissingSize(t *testing.T) { + if err := parseTest(&missingSize{}); err == nil { + t.Fatal("failed to error on missing field size") + } +} + +type badNested struct { + Empty empty +} + +func TestNestedParseError(t *testing.T) { + var buf bytes.Buffer + if err := Pack(&buf, &badNested{}); err == nil { + t.Fatal("failed to error on bad nested struct") + } +} diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/struc.go b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/struc.go new file mode 100644 index 00000000..3d85fe32 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/struc.go @@ -0,0 +1,117 @@ +package struc + +import ( + "encoding/binary" + "fmt" + "io" + "reflect" +) + +type Options struct { + ByteAlign int + PtrSize int + Order binary.ByteOrder +} + +func (o *Options) Validate() error { + if o.PtrSize == 0 { + o.PtrSize = 32 + } else { + switch o.PtrSize { + case 8, 16, 32, 64: + default: + return fmt.Errorf("Invalid Options.PtrSize: %d. Must be in (8, 16, 32, 64)", o.PtrSize) + } + } + return nil +} + +var emptyOptions = &Options{} + +func prep(data interface{}) (reflect.Value, Packer, error) { + value := reflect.ValueOf(data) + for value.Kind() == reflect.Ptr { + next := value.Elem().Kind() + if next == reflect.Struct || next == reflect.Ptr { + value = value.Elem() + } else { + break + } + } + switch value.Kind() { + case reflect.Struct: + fields, err := parseFields(value) + return value, fields, err + default: + if !value.IsValid() { + return reflect.Value{}, nil, fmt.Errorf("Invalid reflect.Value for %+v", data) + } + if c, ok := data.(Custom); ok { + return value, customFallback{c}, nil + } + return value, binaryFallback(value), nil + } +} + +func Pack(w io.Writer, data interface{}) error { + return PackWithOptions(w, data, nil) +} + +func PackWithOptions(w io.Writer, data interface{}, options *Options) error { + if options == nil { + options = emptyOptions + } + if err := options.Validate(); err != nil { + return err + } + val, packer, err := prep(data) + if err != nil { + return err + } + if val.Type().Kind() == reflect.String { + val = val.Convert(reflect.TypeOf([]byte{})) + } + size := packer.Sizeof(val, options) + buf := make([]byte, size) + if _, err := packer.Pack(buf, val, options); err != nil { + return err + } + _, err = w.Write(buf) + return err +} + +func Unpack(r io.Reader, data interface{}) error { + return UnpackWithOptions(r, data, nil) +} + +func UnpackWithOptions(r io.Reader, data interface{}, options *Options) error { + if options == nil { + options = emptyOptions + } + if err := options.Validate(); err != nil { + return err + } + val, packer, err := prep(data) + if err != nil { + return err + } + return packer.Unpack(r, val, options) +} + +func Sizeof(data interface{}) (int, error) { + return SizeofWithOptions(data, nil) +} + +func SizeofWithOptions(data interface{}, options *Options) (int, error) { + if options == nil { + options = emptyOptions + } + if err := options.Validate(); err != nil { + return 0, err + } + val, packer, err := prep(data) + if err != nil { + return 0, err + } + return packer.Sizeof(val, options), nil +} diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/struc_test.go b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/struc_test.go new file mode 100644 index 00000000..939c3e36 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/struc_test.go @@ -0,0 +1,197 @@ +package struc + +import ( + "bytes" + "encoding/binary" + "reflect" + "testing" +) + +type Nested struct { + Test2 int `struc:"int8"` +} + +type Example struct { + Pad []byte `struc:"[5]pad"` // 00 00 00 00 00 + I8f int `struc:"int8"` // 01 + I16f int `struc:"int16"` // 00 02 + I32f int `struc:"int32"` // 00 00 00 03 + I64f int `struc:"int64"` // 00 00 00 00 00 00 00 04 + U8f int `struc:"uint8,little"` // 05 + U16f int `struc:"uint16,little"` // 06 00 + U32f int `struc:"uint32,little"` // 07 00 00 00 + U64f int `struc:"uint64,little"` // 08 00 00 00 00 00 00 00 + Boolf int `struc:"bool"` // 01 + Byte4f []byte `struc:"[4]byte"` // "abcd" + + I8 int8 // 09 + I16 int16 // 00 0a + I32 int32 // 00 00 00 0b + I64 int64 // 00 00 00 00 00 00 00 0c + U8 uint8 `struc:"little"` // 0d + U16 uint16 `struc:"little"` // 0e 00 + U32 uint32 `struc:"little"` // 0f 00 00 00 + U64 uint64 `struc:"little"` // 10 00 00 00 00 00 00 00 + BoolT bool // 01 + BoolF bool // 00 + Byte4 [4]byte // "efgh" + Float1 float32 // 41 a0 00 00 + Float2 float64 // 41 35 00 00 00 00 00 00 + + Size int `struc:"sizeof=Str,little"` // 0a 00 00 00 + Str string `struc:"[]byte"` // "ijklmnopqr" + Strb string `struc:"[4]byte"` // "stuv" + + Size2 int `struc:"uint8,sizeof=Str2"` // 04 + Str2 string // "1234" + + Size3 int `struc:"uint8,sizeof=Bstr"` // 04 + Bstr []byte // "5678" + + Nested Nested // 00 00 00 01 + NestedP *Nested // 00 00 00 02 + TestP64 *int `struc:"int64"` // 00 00 00 05 + + NestedSize int `struc:"sizeof=NestedA"` // 00 00 00 02 + NestedA []Nested // [00 00 00 03, 00 00 00 04] + + CustomTypeSize Int3 `struc:"sizeof=CustomTypeSizeArr"` // 00 00 00 04 + CustomTypeSizeArr []byte // "ABCD" +} + +var five = 5 + +var reference = &Example{ + nil, + 1, 2, 3, 4, 5, 6, 7, 8, 0, []byte{'a', 'b', 'c', 'd'}, + 9, 10, 11, 12, 13, 14, 15, 16, true, false, [4]byte{'e', 'f', 'g', 'h'}, + 20, 21, + 10, "ijklmnopqr", "stuv", + 4, "1234", + 4, []byte("5678"), + Nested{1}, &Nested{2}, &five, + 6, []Nested{{3}, {4}, {5}, {6}, {7}, {8}}, + Int3(4), []byte("ABCD"), +} + +var referenceBytes = []byte{ + 0, 0, 0, 0, 0, // pad(5) + 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, // fake int8-int64(1-4) + 5, 6, 0, 7, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, // fake little-endian uint8-uint64(5-8) + 0, // fake bool(0) + 'a', 'b', 'c', 'd', // fake [4]byte + + 9, 0, 10, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 12, // real int8-int64(9-12) + 13, 14, 0, 15, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, // real little-endian uint8-uint64(13-16) + 1, 0, // real bool(1), bool(0) + 'e', 'f', 'g', 'h', // real [4]byte + 65, 160, 0, 0, // real float32(20) + 64, 53, 0, 0, 0, 0, 0, 0, // real float64(21) + + 10, 0, 0, 0, // little-endian int32(10) sizeof=Str + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', // Str + 's', 't', 'u', 'v', // fake string([4]byte) + 04, '1', '2', '3', '4', // real string + 04, '5', '6', '7', '8', // fake []byte(string) + + 1, 2, // Nested{1}, Nested{2} + 0, 0, 0, 0, 0, 0, 0, 5, // &five + + 0, 0, 0, 6, // int32(6) + 3, 4, 5, 6, 7, 8, // [Nested{3}, ...Nested{8}] + + 0, 0, 4, 'A', 'B', 'C', 'D', // Int3(4), []byte("ABCD") +} + +func TestCodec(t *testing.T) { + var buf bytes.Buffer + if err := Pack(&buf, reference); err != nil { + t.Fatal(err) + } + out := &Example{} + if err := Unpack(&buf, out); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(reference, out) { + t.Fatal("encode/decode failed") + } +} + +func TestEncode(t *testing.T) { + var buf bytes.Buffer + if err := Pack(&buf, reference); err != nil { + t.Fatal(err) + } + if !bytes.Equal(buf.Bytes(), referenceBytes) { + t.Fatal("encode failed") + } +} + +func TestDecode(t *testing.T) { + buf := bytes.NewReader(referenceBytes) + out := &Example{} + if err := Unpack(buf, out); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(reference, out) { + t.Fatal("decode failed") + } +} + +func TestSizeof(t *testing.T) { + size, err := Sizeof(reference) + if err != nil { + t.Fatal(err) + } + if size != len(referenceBytes) { + t.Fatal("sizeof failed") + } +} + +type ExampleEndian struct { + T int `struc:"int16,big"` +} + +func TestEndianSwap(t *testing.T) { + var buf bytes.Buffer + big := &ExampleEndian{1} + if err := PackWithOrder(&buf, big, binary.BigEndian); err != nil { + t.Fatal(err) + } + little := &ExampleEndian{} + if err := UnpackWithOrder(&buf, little, binary.LittleEndian); err != nil { + t.Fatal(err) + } + if little.T != 256 { + t.Fatal("big -> little conversion failed") + } +} + +func TestNilValue(t *testing.T) { + var buf bytes.Buffer + if err := Pack(&buf, nil); err == nil { + t.Fatal("failed throw error for bad struct value") + } + if err := Unpack(&buf, nil); err == nil { + t.Fatal("failed throw error for bad struct value") + } + if _, err := Sizeof(nil); err == nil { + t.Fatal("failed to throw error for bad struct value") + } +} + +type sliceUnderrun struct { + Str string `struc:"[10]byte"` + Arr []uint16 `struc:"[10]uint16"` +} + +func TestSliceUnderrun(t *testing.T) { + var buf bytes.Buffer + v := sliceUnderrun{ + Str: "foo", + Arr: []uint16{1, 2, 3}, + } + if err := Pack(&buf, &v); err != nil { + t.Fatal(err) + } +} diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/types.go b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/types.go new file mode 100644 index 00000000..6ca97f48 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/types.go @@ -0,0 +1,136 @@ +package struc + +import ( + "fmt" + "reflect" +) + +type Type int + +const ( + Invalid Type = iota + Pad + Bool + Int + Int8 + Uint8 + Int16 + Uint16 + Int32 + Uint32 + Int64 + Uint64 + Float32 + Float64 + String + Struct + Ptr + + SizeType + OffType + CustomType +) + +func (t Type) Resolve(options *Options) Type { + switch t { + case OffType: + switch options.PtrSize { + case 8: + return Int8 + case 16: + return Int16 + case 32: + return Int32 + case 64: + return Int64 + default: + panic(fmt.Sprintf("unsupported ptr bits: %d", options.PtrSize)) + } + case SizeType: + switch options.PtrSize { + case 8: + return Uint8 + case 16: + return Uint16 + case 32: + return Uint32 + case 64: + return Uint64 + default: + panic(fmt.Sprintf("unsupported ptr bits: %d", options.PtrSize)) + } + } + return t +} + +func (t Type) String() string { + return typeNames[t] +} + +func (t Type) Size() int { + switch t { + case SizeType, OffType: + panic("Size_t/Off_t types must be converted to another type using options.PtrSize") + case Pad, String, Int8, Uint8, Bool: + return 1 + case Int16, Uint16: + return 2 + case Int32, Uint32, Float32: + return 4 + case Int64, Uint64, Float64: + return 8 + default: + panic("Cannot resolve size of type:" + t.String()) + } +} + +var typeLookup = map[string]Type{ + "pad": Pad, + "bool": Bool, + "byte": Uint8, + "int8": Int8, + "uint8": Uint8, + "int16": Int16, + "uint16": Uint16, + "int32": Int32, + "uint32": Uint32, + "int64": Int64, + "uint64": Uint64, + "float32": Float32, + "float64": Float64, + + "size_t": SizeType, + "off_t": OffType, +} + +var typeNames = map[Type]string{ + CustomType: "Custom", +} + +func init() { + for name, enum := range typeLookup { + typeNames[enum] = name + } +} + +type Size_t uint64 +type Off_t int64 + +var reflectTypeMap = map[reflect.Kind]Type{ + reflect.Bool: Bool, + reflect.Int8: Int8, + reflect.Int16: Int16, + reflect.Int: Int32, + reflect.Int32: Int32, + reflect.Int64: Int64, + reflect.Uint8: Uint8, + reflect.Uint16: Uint16, + reflect.Uint: Uint32, + reflect.Uint32: Uint32, + reflect.Uint64: Uint64, + reflect.Float32: Float32, + reflect.Float64: Float64, + reflect.String: String, + reflect.Struct: Struct, + reflect.Ptr: Ptr, +} diff --git a/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/types_test.go b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/types_test.go new file mode 100644 index 00000000..3b33e8f5 --- /dev/null +++ b/vendor/github.com/mozilla/libaudit-go/vendor/github.com/lunixbochs/struc/types_test.go @@ -0,0 +1,53 @@ +package struc + +import ( + "bytes" + "testing" +) + +func TestBadType(t *testing.T) { + defer func() { recover() }() + Type(-1).Size() + t.Fatal("failed to panic for invalid Type.Size()") +} + +func TestTypeString(t *testing.T) { + if Pad.String() != "pad" { + t.Fatal("type string representation failed") + } +} + +type sizeOffTest struct { + Size Size_t + Off Off_t +} + +func TestSizeOffTypes(t *testing.T) { + bits := []int{8, 16, 32, 64} + var buf bytes.Buffer + test := &sizeOffTest{1, 2} + for _, b := range bits { + if err := PackWithOptions(&buf, test, &Options{PtrSize: b}); err != nil { + t.Fatal(err) + } + } + reference := []byte{ + 1, 2, + 0, 1, 0, 2, + 0, 0, 0, 1, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, + } + if !bytes.Equal(reference, buf.Bytes()) { + t.Errorf("reference != bytes: %v", reference, buf.Bytes()) + } + reader := bytes.NewReader(buf.Bytes()) + for _, b := range bits { + out := &sizeOffTest{} + if err := UnpackWithOptions(reader, out, &Options{PtrSize: b}); err != nil { + t.Fatal(err) + } + if out.Size != 1 || out.Off != 2 { + t.Errorf("Size_t/Off_t mismatch: {%d, %d}\n%v", out.Size, out.Off, buf.Bytes()) + } + } +}