diff --git a/examples/seccheck/server.cc b/examples/seccheck/server.cc index 0da082bd74..dce0da38d1 100644 --- a/examples/seccheck/server.cc +++ b/examples/seccheck/server.cc @@ -125,6 +125,7 @@ std::vector dispatchers = { unpackSyscall<::gvisor::syscall::InotifyRmWatch>, unpackSyscall<::gvisor::syscall::SocketPair>, unpackSyscall<::gvisor::syscall::Write>, + unpack<::gvisor::sentry::MmapInfo>, }; void unpack(absl::string_view buf) { diff --git a/pkg/sentry/seccheck/metadata.go b/pkg/sentry/seccheck/metadata.go index 9152aa5177..b3c09d43d5 100644 --- a/pkg/sentry/seccheck/metadata.go +++ b/pkg/sentry/seccheck/metadata.go @@ -30,6 +30,7 @@ const ( PointExecve PointExitNotifyParent PointTaskExit + PointMmap // Add new Points above this line. pointLengthBeforeSyscalls @@ -303,6 +304,11 @@ func genericInit() { Name: "sentry/task_exit", ContextFields: defaultContextFields, }) + registerPoint(PointDesc{ + ID: PointMmap, + Name: "sentry/mmap", + ContextFields: defaultContextFields, + }) } var initOnce sync.Once diff --git a/pkg/sentry/seccheck/points/common.proto b/pkg/sentry/seccheck/points/common.proto index 7e99ee81b5..0c90823ff1 100644 --- a/pkg/sentry/seccheck/points/common.proto +++ b/pkg/sentry/seccheck/points/common.proto @@ -134,5 +134,6 @@ enum MessageType { MESSAGE_SYSCALL_INOTIFY_RM_WATCH = 32; MESSAGE_SYSCALL_SOCKETPAIR = 33; MESSAGE_SYSCALL_WRITE = 34; + MESSAGE_SENTRY_MMAP = 35; } // LINT.ThenChange(../../../../examples/seccheck/server.cc) diff --git a/pkg/sentry/seccheck/points/sentry.proto b/pkg/sentry/seccheck/points/sentry.proto index 313856d2e3..6a67580540 100644 --- a/pkg/sentry/seccheck/points/sentry.proto +++ b/pkg/sentry/seccheck/points/sentry.proto @@ -76,3 +76,15 @@ message TaskExit { // by wait*(). int32 exit_status = 2; } + +message MmapInfo { + gvisor.common.ContextData context_data = 1; + + string mapped_path = 2; + uint64 mapped_ino = 3; + uint32 mapped_mode = 4; + uint32 mapped_uid = 5; + uint32 mapped_gid = 6; + + bool is_initial_mmap = 7; +} diff --git a/pkg/sentry/seccheck/seccheck.go b/pkg/sentry/seccheck/seccheck.go index 784ac3652e..79b196f969 100644 --- a/pkg/sentry/seccheck/seccheck.go +++ b/pkg/sentry/seccheck/seccheck.go @@ -108,6 +108,7 @@ type Sink interface { Execve(ctx context.Context, fields FieldSet, info *pb.ExecveInfo) error ExitNotifyParent(ctx context.Context, fields FieldSet, info *pb.ExitNotifyParentInfo) error TaskExit(context.Context, FieldSet, *pb.TaskExit) error + Mmap(context.Context, FieldSet, *pb.MmapInfo) error ContainerStart(context.Context, FieldSet, *pb.Start) error @@ -169,6 +170,11 @@ func (SinkDefaults) TaskExit(context.Context, FieldSet, *pb.TaskExit) error { return nil } +// Mmap implements Sink.Mmap. +func (SinkDefaults) Mmap(context.Context, FieldSet, *pb.MmapInfo) error { + return nil +} + // RawSyscall implements Sink.RawSyscall. func (SinkDefaults) RawSyscall(context.Context, FieldSet, *pb.Syscall) error { return nil diff --git a/pkg/sentry/seccheck/sinks/remote/remote.go b/pkg/sentry/seccheck/sinks/remote/remote.go index 0d1806dc78..b05cc263ad 100644 --- a/pkg/sentry/seccheck/sinks/remote/remote.go +++ b/pkg/sentry/seccheck/sinks/remote/remote.go @@ -265,6 +265,12 @@ func (r *remote) TaskExit(_ context.Context, _ seccheck.FieldSet, info *pb.TaskE return nil } +// Mmap implements seccheck.Sink. +func (r *remote) Mmap(_ context.Context, _ seccheck.FieldSet, info *pb.MmapInfo) error { + r.write(info, pb.MessageType_MESSAGE_SENTRY_MMAP) + return nil +} + // ContainerStart implements seccheck.Sink. func (r *remote) ContainerStart(_ context.Context, _ seccheck.FieldSet, info *pb.Start) error { r.write(info, pb.MessageType_MESSAGE_CONTAINER_START) diff --git a/pkg/sentry/syscalls/linux/sys_mmap.go b/pkg/sentry/syscalls/linux/sys_mmap.go index 5bf743ab57..6364e52de8 100644 --- a/pkg/sentry/syscalls/linux/sys_mmap.go +++ b/pkg/sentry/syscalls/linux/sys_mmap.go @@ -25,6 +25,9 @@ import ( "gvisor.dev/gvisor/pkg/sentry/kernel" "gvisor.dev/gvisor/pkg/sentry/memmap" "gvisor.dev/gvisor/pkg/sentry/mm" + "gvisor.dev/gvisor/pkg/sentry/seccheck" + pb "gvisor.dev/gvisor/pkg/sentry/seccheck/points/points_go_proto" + "gvisor.dev/gvisor/pkg/sentry/vfs" ) // Brk implements linux syscall brk(2). @@ -81,6 +84,7 @@ func Mmap(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, * } }() + var mappedFile *vfs.FileDescription if !anon { // Convert the passed FD to a file reference. file := t.GetFile(fd) @@ -122,6 +126,7 @@ func Mmap(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, * if err := file.ConfigureMMap(t, &opts); err != nil { return 0, nil, err } + mappedFile = file } else if shared { // Back shared anonymous mappings with an anonymous tmpfs file. opts.Offset = 0 @@ -133,10 +138,17 @@ func Mmap(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, * if err := file.ConfigureMMap(t, &opts); err != nil { return 0, nil, err } + mappedFile = file } else { opts.NameMut = memmap.NameMutAnon } + if opts.Perms.Execute { + if err := traceMmap(t, mappedFile); err != nil { + return 0, nil, err + } + } + rv, err := t.MemoryManager().MMap(t, opts) return uintptr(rv), nil, err } @@ -349,3 +361,49 @@ func Munlockall(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uint Mode: memmap.MLockNone, }) } + +func traceMmap(t *kernel.Task, file *vfs.FileDescription) error { + if !seccheck.Global.Enabled(seccheck.PointMmap) { + return nil + } + fields := seccheck.Global.GetFieldSet(seccheck.PointMmap) + info := &pb.MmapInfo{} + if file != nil { + info.MappedPath = file.MappedName(t) + statOpts := vfs.StatOptions{ + Mask: linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_UID | linux.STATX_GID | linux.STATX_INO, + } + if stat, err := file.Stat(t, statOpts); err == nil { + if stat.Mask&(linux.STATX_TYPE|linux.STATX_MODE) == (linux.STATX_TYPE | linux.STATX_MODE) { + info.MappedMode = uint32(stat.Mode) + } + if stat.Mask&linux.STATX_UID != 0 { + info.MappedUid = stat.UID + } + if stat.Mask&linux.STATX_GID != 0 { + info.MappedGid = stat.GID + } + if stat.Mask&linux.STATX_INO != 0 { + info.MappedIno = stat.Ino + } + } + } + if exe := t.MemoryManager().Executable(); exe != nil { + if exe == file { + info.IsInitialMmap = true + } else { + statOpts := vfs.StatOptions{Mask: linux.STATX_INO} + if exeStat, err := exe.Stat(t, statOpts); err == nil && info.MappedIno != 0 && exeStat.Ino == info.MappedIno { + info.IsInitialMmap = true + } + } + exe.DecRef(t) + } + if !fields.Context.Empty() { + info.ContextData = &pb.ContextData{} + kernel.LoadSeccheckData(t, fields.Context, info.ContextData) + } + return seccheck.Global.SentToSinks(func(c seccheck.Sink) error { + return c.Mmap(t, fields, info) + }) +} diff --git a/test/trace/trace_test.go b/test/trace/trace_test.go index ee921eeb24..7a40e77258 100644 --- a/test/trace/trace_test.go +++ b/test/trace/trace_test.go @@ -106,6 +106,7 @@ func matchPoints(t *testing.T, msgs []test.Message) map[pb.MessageType]*checkers pb.MessageType_MESSAGE_SENTRY_EXEC: {checker: checkSentryExec}, pb.MessageType_MESSAGE_SENTRY_EXIT_NOTIFY_PARENT: {checker: checkSentryExitNotifyParent}, pb.MessageType_MESSAGE_SENTRY_TASK_EXIT: {checker: checkSentryTaskExit}, + pb.MessageType_MESSAGE_SENTRY_MMAP: {checker: checkSentryMmap}, pb.MessageType_MESSAGE_SYSCALL_CLOSE: {checker: checkSyscallClose}, pb.MessageType_MESSAGE_SYSCALL_CONNECT: {checker: checkSyscallConnect}, pb.MessageType_MESSAGE_SYSCALL_EXECVE: {checker: checkSyscallExecve}, @@ -263,6 +264,17 @@ func checkSentryTaskExit(msg test.Message) error { return nil } +func checkSentryMmap(msg test.Message) error { + p := pb.MmapInfo{} + if err := proto.Unmarshal(msg.Msg, &p); err != nil { + return err + } + if err := checkContextData(p.ContextData); err != nil { + return err + } + return nil +} + func checkSyscallRaw(msg test.Message) error { p := pb.Syscall{} if err := proto.Unmarshal(msg.Msg, &p); err != nil {