Skip to content

Commit

Permalink
Add parsing function for mmap flags argument (#267)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlonZivony authored Nov 9, 2022
1 parent 9ba4e04 commit 6070c0d
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 5 deletions.
121 changes: 119 additions & 2 deletions helpers/argumentParsers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ package helpers
import (
"encoding/binary"
"fmt"
"golang.org/x/sys/unix"
"net"
"strconv"
"strings"

"golang.org/x/sys/unix"
)

type SystemFunctionArgument interface {
Expand Down Expand Up @@ -1833,3 +1832,121 @@ func ParseBPFProgType(rawValue uint64) (BPFProgType, error) {
}
return v, nil
}

type MmapFlagArgument struct {
rawValue uint32
stringValue string
}

const (
HugetlbFlagEncodeShift = 26
MapHugeSizeMask = ((1 << 6) - 1) << HugetlbFlagEncodeShift
)

var (
MapShared MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_SHARED, stringValue: "MAP_SHARED"}
MapPrivate MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_PRIVATE, stringValue: "MAP_PRIVATE"}
MapSharedValidate MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_SHARED_VALIDATE, stringValue: "MAP_SHARED_VALIDATE"}
Map32bit MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_32BIT, stringValue: "MAP_32BIT"}
MapType MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_TYPE, stringValue: "MAP_TYPE"}
MapFixed MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_FIXED, stringValue: "MAP_FIXED"}
MapAnonymous MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_ANONYMOUS, stringValue: "MAP_ANONYMOUS"}
MapPopulate MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_POPULATE, stringValue: "MAP_POPULATE"}
MapNonblock MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_NONBLOCK, stringValue: "MAP_NONBLOCK"}
MapStack MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_STACK, stringValue: "MAP_STACK"}
MapHugetlb MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_HUGETLB, stringValue: "MAP_HUGETLB"}
MapSync MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_SYNC, stringValue: "MAP_SYNC"}
MapFixedNoreplace MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_FIXED_NOREPLACE, stringValue: "MAP_FIXED_NOREPLACE"}
MapGrowsdown MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_GROWSDOWN, stringValue: "MAP_GROWSDOWN"}
MapDenywrite MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_DENYWRITE, stringValue: "MAP_DENYWRITE"}
MapExecutable MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_EXECUTABLE, stringValue: "MAP_EXECUTABLE"}
MapLocked MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_LOCKED, stringValue: "MAP_LOCKED"}
MapNoreserve MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_NORESERVE, stringValue: "MAP_NORESERVE"}
MapFile MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_FILE, stringValue: "MAP_FILE"}
MapHuge2MB MmapFlagArgument = MmapFlagArgument{rawValue: 21 << HugetlbFlagEncodeShift, stringValue: "MAP_HUGE_2MB"}
MapHuge1GB MmapFlagArgument = MmapFlagArgument{rawValue: 30 << HugetlbFlagEncodeShift, stringValue: "MAP_HUGE_1GB"}
MapSYNC MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_SYNC, stringValue: "MAP_SYNC"}
// TODO: Add support for MAP_UNINITIALIZED which collide with Huge TLB size bits
)

var mmapFlagMap = map[uint64]MmapFlagArgument{
MapShared.Value(): MapShared,
MapPrivate.Value(): MapPrivate,
MapSharedValidate.Value(): MapSharedValidate,
Map32bit.Value(): Map32bit,
MapType.Value(): MapType,
MapFixed.Value(): MapFixed,
MapAnonymous.Value(): MapAnonymous,
MapPopulate.Value(): MapPopulate,
MapNonblock.Value(): MapNonblock,
MapStack.Value(): MapStack,
MapHugetlb.Value(): MapHugetlb,
MapSync.Value(): MapSync,
MapFixedNoreplace.Value(): MapFixedNoreplace,
MapGrowsdown.Value(): MapGrowsdown,
MapDenywrite.Value(): MapDenywrite,
MapExecutable.Value(): MapExecutable,
MapLocked.Value(): MapLocked,
MapNoreserve.Value(): MapNoreserve,
MapFile.Value(): MapFile,
MapHuge2MB.Value(): MapHuge2MB,
MapHuge1GB.Value(): MapHuge1GB,
MapSYNC.Value(): MapSYNC,
}

func (mf MmapFlagArgument) Value() uint64 {
return uint64(mf.rawValue)
}

func (mf MmapFlagArgument) String() string {
return mf.stringValue
}

// getHugeMapSizeFlagString extract the huge flag size flag from the mmap flags.
// This flag is special, because it is 6-bits representation of the log2 of the size.
// For more information - https://elixir.bootlin.com/linux/latest/source/include/uapi/asm-generic/hugetlb_encode.h
func getHugeMapSizeFlagString(flags uint32) MmapFlagArgument {
hugeSizeFlagVal := flags & MapHugeSizeMask
// The size given in the flags is log2 of the size of the pages
mapHugeSizePower := hugeSizeFlagVal >> HugetlbFlagEncodeShift

// Create a name of a flag matching given huge page size
// The size is 6 bits, so maximum value is 16EB
unitsPrefix := []string{"", "K", "M", "G", "T", "P", "E"}
var unitPrefix string
var inUnitSize uint
for i, prefix := range unitsPrefix {
if mapHugeSizePower < ((uint32(i) + 1) * 10) {
unitPrefix = prefix
inUnitSize = 1 << (mapHugeSizePower % 10)
break
}
}
return MmapFlagArgument{rawValue: hugeSizeFlagVal, stringValue: fmt.Sprintf("MAP_HUGE_%d%sB", inUnitSize, unitPrefix)}
}

// ParseMmapFlags parses the `flags` bitmask argument of the `mmap` syscall
// http://man7.org/linux/man-pages/man2/mmap.2.html
// https://elixir.bootlin.com/linux/v5.5.3/source/include/uapi/asm-generic/mman-common.h#L19
func ParseMmapFlags(rawValue uint64) MmapFlagArgument {
var f []string
for i := 0; i < HugetlbFlagEncodeShift; i++ {
flagMask := 1 << i

if (rawValue & uint64(flagMask)) != 0 {
flag, ok := mmapFlagMap[1<<i]
if ok {
f = append(f, flag.String())
} else {
f = append(f, fmt.Sprintf("UNKNOWN_FLAG_0X%s", strings.ToUpper(strconv.FormatUint(flag.Value(), 16))))
}
}
}

if (rawValue & MapHugeSizeMask) != 0 {
hugeMapFlag := getHugeMapSizeFlagString(uint32(rawValue))
f = append(f, hugeMapFlag.String())
}

return MmapFlagArgument{stringValue: strings.Join(f, "|"), rawValue: uint32(rawValue)}
}
41 changes: 41 additions & 0 deletions helpers/argumentParsers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,44 @@ func TestParseBPFProgType(t *testing.T) {
})
}
}

func TestParseMmapFlags(t *testing.T) {
testCases := []struct {
name string
parseValue uint64
expectedSting string
}{
{
name: "Single value",
parseValue: MapGrowsdown.Value(),
expectedSting: "MAP_GROWSDOWN",
},
{
name: "Multiple values",
parseValue: MapGrowsdown.Value() | MapStack.Value() | MapExecutable.Value(),
expectedSting: "MAP_GROWSDOWN|MAP_EXECUTABLE|MAP_STACK",
},
{
name: "Huge table size flag",
parseValue: MapHuge2MB.Value(),
expectedSting: "MAP_HUGE_2MB",
},
{
name: "Huge table custom size flag",
parseValue: 19 << HugetlbFlagEncodeShift,
expectedSting: "MAP_HUGE_512KB",
},
{
name: "Huge table custom size flag with normal flags",
parseValue: (19 << HugetlbFlagEncodeShift) | MapHugetlb.Value() | MapExecutable.Value(),
expectedSting: "MAP_EXECUTABLE|MAP_HUGETLB|MAP_HUGE_512KB",
},
}

for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
flags := ParseMmapFlags(testCase.parseValue)
assert.Equal(t, testCase.expectedSting, flags.String())
})
}
}
2 changes: 1 addition & 1 deletion helpers/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.18

require (
github.com/stretchr/testify v1.8.0
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec
golang.org/x/sys v0.1.0
)

require (
Expand Down
4 changes: 2 additions & 2 deletions helpers/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Expand Down

0 comments on commit 6070c0d

Please sign in to comment.