Skip to content

Commit 6b5bf02

Browse files
xinzhonggvisor-bot
authored andcommitted
Add seccheck point for mmap.
This change introduces a new seccheck point, "sentry/mmap", which is triggered when a memory mapping is created. The seccheck event includes information about the mapped file, such as its path, inode, mode, UID, and GID, as well as a timestamp. It also indicates if the mapping corresponds to the initial executable. This allows for monitoring of potential code injection or execution from unexpected sources. PiperOrigin-RevId: 915566174
1 parent abf5927 commit 6b5bf02

8 files changed

Lines changed: 102 additions & 0 deletions

File tree

examples/seccheck/server.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ std::vector<Callback> dispatchers = {
125125
unpackSyscall<::gvisor::syscall::InotifyRmWatch>,
126126
unpackSyscall<::gvisor::syscall::SocketPair>,
127127
unpackSyscall<::gvisor::syscall::Write>,
128+
unpack<::gvisor::sentry::MmapInfo>,
128129
};
129130

130131
void unpack(absl::string_view buf) {

pkg/sentry/seccheck/metadata.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const (
3030
PointExecve
3131
PointExitNotifyParent
3232
PointTaskExit
33+
PointMmap
3334

3435
// Add new Points above this line.
3536
pointLengthBeforeSyscalls
@@ -303,6 +304,11 @@ func genericInit() {
303304
Name: "sentry/task_exit",
304305
ContextFields: defaultContextFields,
305306
})
307+
registerPoint(PointDesc{
308+
ID: PointMmap,
309+
Name: "sentry/mmap",
310+
ContextFields: defaultContextFields,
311+
})
306312
}
307313

308314
var initOnce sync.Once

pkg/sentry/seccheck/points/common.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,5 +134,6 @@ enum MessageType {
134134
MESSAGE_SYSCALL_INOTIFY_RM_WATCH = 32;
135135
MESSAGE_SYSCALL_SOCKETPAIR = 33;
136136
MESSAGE_SYSCALL_WRITE = 34;
137+
MESSAGE_SENTRY_MMAP = 35;
137138
}
138139
// LINT.ThenChange(../../../../examples/seccheck/server.cc)

pkg/sentry/seccheck/points/sentry.proto

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,15 @@ message TaskExit {
7676
// by wait*().
7777
int32 exit_status = 2;
7878
}
79+
80+
message MmapInfo {
81+
gvisor.common.ContextData context_data = 1;
82+
83+
string mapped_path = 2;
84+
uint64 mapped_ino = 3;
85+
uint32 mapped_mode = 4;
86+
uint32 mapped_uid = 5;
87+
uint32 mapped_gid = 6;
88+
89+
bool is_initial_mmap = 7;
90+
}

pkg/sentry/seccheck/seccheck.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ type Sink interface {
108108
Execve(ctx context.Context, fields FieldSet, info *pb.ExecveInfo) error
109109
ExitNotifyParent(ctx context.Context, fields FieldSet, info *pb.ExitNotifyParentInfo) error
110110
TaskExit(context.Context, FieldSet, *pb.TaskExit) error
111+
Mmap(context.Context, FieldSet, *pb.MmapInfo) error
111112

112113
ContainerStart(context.Context, FieldSet, *pb.Start) error
113114

@@ -169,6 +170,11 @@ func (SinkDefaults) TaskExit(context.Context, FieldSet, *pb.TaskExit) error {
169170
return nil
170171
}
171172

173+
// Mmap implements Sink.Mmap.
174+
func (SinkDefaults) Mmap(context.Context, FieldSet, *pb.MmapInfo) error {
175+
return nil
176+
}
177+
172178
// RawSyscall implements Sink.RawSyscall.
173179
func (SinkDefaults) RawSyscall(context.Context, FieldSet, *pb.Syscall) error {
174180
return nil

pkg/sentry/seccheck/sinks/remote/remote.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,12 @@ func (r *remote) TaskExit(_ context.Context, _ seccheck.FieldSet, info *pb.TaskE
265265
return nil
266266
}
267267

268+
// Mmap implements seccheck.Sink.
269+
func (r *remote) Mmap(_ context.Context, _ seccheck.FieldSet, info *pb.MmapInfo) error {
270+
r.write(info, pb.MessageType_MESSAGE_SENTRY_MMAP)
271+
return nil
272+
}
273+
268274
// ContainerStart implements seccheck.Sink.
269275
func (r *remote) ContainerStart(_ context.Context, _ seccheck.FieldSet, info *pb.Start) error {
270276
r.write(info, pb.MessageType_MESSAGE_CONTAINER_START)

pkg/sentry/syscalls/linux/sys_mmap.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ import (
2525
"gvisor.dev/gvisor/pkg/sentry/kernel"
2626
"gvisor.dev/gvisor/pkg/sentry/memmap"
2727
"gvisor.dev/gvisor/pkg/sentry/mm"
28+
"gvisor.dev/gvisor/pkg/sentry/seccheck"
29+
pb "gvisor.dev/gvisor/pkg/sentry/seccheck/points/points_go_proto"
30+
"gvisor.dev/gvisor/pkg/sentry/vfs"
2831
)
2932

3033
// Brk implements linux syscall brk(2).
@@ -81,6 +84,7 @@ func Mmap(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *
8184
}
8285
}()
8386

87+
var mappedFile *vfs.FileDescription
8488
if !anon {
8589
// Convert the passed FD to a file reference.
8690
file := t.GetFile(fd)
@@ -122,6 +126,7 @@ func Mmap(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *
122126
if err := file.ConfigureMMap(t, &opts); err != nil {
123127
return 0, nil, err
124128
}
129+
mappedFile = file
125130
} else if shared {
126131
// Back shared anonymous mappings with an anonymous tmpfs file.
127132
opts.Offset = 0
@@ -133,10 +138,17 @@ func Mmap(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *
133138
if err := file.ConfigureMMap(t, &opts); err != nil {
134139
return 0, nil, err
135140
}
141+
mappedFile = file
136142
} else {
137143
opts.NameMut = memmap.NameMutAnon
138144
}
139145

146+
if opts.Perms.Execute {
147+
if err := traceMmap(t, mappedFile); err != nil {
148+
return 0, nil, err
149+
}
150+
}
151+
140152
rv, err := t.MemoryManager().MMap(t, opts)
141153
return uintptr(rv), nil, err
142154
}
@@ -349,3 +361,49 @@ func Munlockall(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uint
349361
Mode: memmap.MLockNone,
350362
})
351363
}
364+
365+
func traceMmap(t *kernel.Task, file *vfs.FileDescription) error {
366+
if !seccheck.Global.Enabled(seccheck.PointMmap) {
367+
return nil
368+
}
369+
fields := seccheck.Global.GetFieldSet(seccheck.PointMmap)
370+
info := &pb.MmapInfo{}
371+
if file != nil {
372+
info.MappedPath = file.MappedName(t)
373+
statOpts := vfs.StatOptions{
374+
Mask: linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_UID | linux.STATX_GID | linux.STATX_INO,
375+
}
376+
if stat, err := file.Stat(t, statOpts); err == nil {
377+
if stat.Mask&(linux.STATX_TYPE|linux.STATX_MODE) == (linux.STATX_TYPE | linux.STATX_MODE) {
378+
info.MappedMode = uint32(stat.Mode)
379+
}
380+
if stat.Mask&linux.STATX_UID != 0 {
381+
info.MappedUid = stat.UID
382+
}
383+
if stat.Mask&linux.STATX_GID != 0 {
384+
info.MappedGid = stat.GID
385+
}
386+
if stat.Mask&linux.STATX_INO != 0 {
387+
info.MappedIno = stat.Ino
388+
}
389+
}
390+
}
391+
if exe := t.MemoryManager().Executable(); exe != nil {
392+
if exe == file {
393+
info.IsInitialMmap = true
394+
} else {
395+
statOpts := vfs.StatOptions{Mask: linux.STATX_INO}
396+
if exeStat, err := exe.Stat(t, statOpts); err == nil && info.MappedIno != 0 && exeStat.Ino == info.MappedIno {
397+
info.IsInitialMmap = true
398+
}
399+
}
400+
exe.DecRef(t)
401+
}
402+
if !fields.Context.Empty() {
403+
info.ContextData = &pb.ContextData{}
404+
kernel.LoadSeccheckData(t, fields.Context, info.ContextData)
405+
}
406+
return seccheck.Global.SentToSinks(func(c seccheck.Sink) error {
407+
return c.Mmap(t, fields, info)
408+
})
409+
}

test/trace/trace_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ func matchPoints(t *testing.T, msgs []test.Message) map[pb.MessageType]*checkers
106106
pb.MessageType_MESSAGE_SENTRY_EXEC: {checker: checkSentryExec},
107107
pb.MessageType_MESSAGE_SENTRY_EXIT_NOTIFY_PARENT: {checker: checkSentryExitNotifyParent},
108108
pb.MessageType_MESSAGE_SENTRY_TASK_EXIT: {checker: checkSentryTaskExit},
109+
pb.MessageType_MESSAGE_SENTRY_MMAP: {checker: checkSentryMmap},
109110
pb.MessageType_MESSAGE_SYSCALL_CLOSE: {checker: checkSyscallClose},
110111
pb.MessageType_MESSAGE_SYSCALL_CONNECT: {checker: checkSyscallConnect},
111112
pb.MessageType_MESSAGE_SYSCALL_EXECVE: {checker: checkSyscallExecve},
@@ -263,6 +264,17 @@ func checkSentryTaskExit(msg test.Message) error {
263264
return nil
264265
}
265266

267+
func checkSentryMmap(msg test.Message) error {
268+
p := pb.MmapInfo{}
269+
if err := proto.Unmarshal(msg.Msg, &p); err != nil {
270+
return err
271+
}
272+
if err := checkContextData(p.ContextData); err != nil {
273+
return err
274+
}
275+
return nil
276+
}
277+
266278
func checkSyscallRaw(msg test.Message) error {
267279
p := pb.Syscall{}
268280
if err := proto.Unmarshal(msg.Msg, &p); err != nil {

0 commit comments

Comments
 (0)