Fix circular lock between filesystemRWMutex and taskSetRWMutex.

PiperOrigin-RevId: 500747195
This commit is contained in:
Lucas Manning
2023-01-09 10:24:35 -08:00
committed by gVisor bot
parent a17ad261d6
commit a248c63cd5
4 changed files with 74 additions and 16 deletions
+30 -10
View File
@@ -19,17 +19,44 @@ import (
pb "gvisor.dev/gvisor/pkg/sentry/seccheck/points/points_go_proto"
)
func getTaskCurrentWorkingDirectory(t *Task) string {
// Grab the filesystem context first since it needs tasks.mu to be locked.
// It's safe to unlock and use the values obtained here as long as there's
// no way to modify root and wd from a separate task.
t.k.tasks.mu.RLock()
root := t.FSContext().RootDirectory()
wd := t.FSContext().WorkingDirectory()
t.k.tasks.mu.RUnlock()
// Perform VFS operations outside of task mutex to avoid circular locking with
// filesystem mutexes.
var cwd string
if root.Ok() {
defer root.DecRef(t)
if wd.Ok() {
defer wd.DecRef(t)
vfsObj := root.Mount().Filesystem().VirtualFilesystem()
cwd, _ = vfsObj.PathnameWithDeleted(t, root, wd)
}
}
return cwd
}
// LoadSeccheckData sets info from the task based on mask.
func LoadSeccheckData(t *Task, mask seccheck.FieldMask, info *pb.ContextData) {
var cwd string
if mask.Contains(seccheck.FieldCtxtCwd) {
cwd = getTaskCurrentWorkingDirectory(t)
}
t.k.tasks.mu.RLock()
defer t.k.tasks.mu.RUnlock()
LoadSeccheckDataLocked(t, mask, info)
LoadSeccheckDataLocked(t, mask, info, cwd)
}
// LoadSeccheckDataLocked sets info from the task based on mask.
//
// Preconditions: The TaskSet mutex must be locked.
func LoadSeccheckDataLocked(t *Task, mask seccheck.FieldMask, info *pb.ContextData) {
func LoadSeccheckDataLocked(t *Task, mask seccheck.FieldMask, info *pb.ContextData, cwd string) {
if mask.Contains(seccheck.FieldCtxtTime) {
info.TimeNs = t.k.RealtimeClock().Now().Nanoseconds()
}
@@ -49,14 +76,7 @@ func LoadSeccheckDataLocked(t *Task, mask seccheck.FieldMask, info *pb.ContextDa
info.ContainerId = t.tg.leader.ContainerID()
}
if mask.Contains(seccheck.FieldCtxtCwd) {
if root := t.FSContext().RootDirectory(); root.Ok() {
defer root.DecRef(t)
if wd := t.FSContext().WorkingDirectory(); wd.Ok() {
defer wd.DecRef(t)
vfsObj := root.Mount().Filesystem().VirtualFilesystem()
info.Cwd, _ = vfsObj.PathnameWithDeleted(t, root, wd)
}
}
info.Cwd = cwd
}
if mask.Contains(seccheck.FieldCtxtProcessName) {
info.ProcessName = t.Name()
+5 -2
View File
@@ -310,7 +310,10 @@ func (t *Task) Clone(args *linux.CloneArgs) (ThreadID, *SyscallControl, error) {
func getCloneSeccheckInfo(t, nt *Task, flags uint64) (seccheck.FieldSet, *pb.CloneInfo) {
fields := seccheck.Global.GetFieldSet(seccheck.PointClone)
var cwd string
if fields.Context.Contains(seccheck.FieldCtxtCwd) {
cwd = getTaskCurrentWorkingDirectory(t)
}
t.k.tasks.mu.RLock()
defer t.k.tasks.mu.RUnlock()
info := &pb.CloneInfo{
@@ -322,7 +325,7 @@ func getCloneSeccheckInfo(t, nt *Task, flags uint64) (seccheck.FieldSet, *pb.Clo
if !fields.Context.Empty() {
info.ContextData = &pb.ContextData{}
LoadSeccheckDataLocked(t, fields.Context, info.ContextData)
LoadSeccheckDataLocked(t, fields.Context, info.ContextData, cwd)
}
return fields, info
+3 -1
View File
@@ -748,7 +748,9 @@ func getExitNotifyParentSeccheckInfo(t *Task) (seccheck.FieldSet, *pb.ExitNotify
}
if !fields.Context.Empty() {
info.ContextData = &pb.ContextData{}
LoadSeccheckDataLocked(t, fields.Context, info.ContextData)
// cwd isn't used for notifyExit seccheck so it's ok to pass an empty
// string.
LoadSeccheckDataLocked(t, fields.Context, info.ContextData, "")
}
return fields, info
+36 -3
View File
@@ -243,9 +243,42 @@ func init() {
ContextFields: defaultContextFields,
})
registerPoint(PointDesc{
ID: PointExitNotifyParent,
Name: "sentry/exit_notify_parent",
ContextFields: defaultContextFields,
ID: PointExitNotifyParent,
Name: "sentry/exit_notify_parent",
ContextFields: []FieldDesc{
{
ID: FieldCtxtTime,
Name: "time",
},
{
ID: FieldCtxtThreadID,
Name: "thread_id",
},
{
ID: FieldCtxtThreadStartTime,
Name: "task_start_time",
},
{
ID: FieldCtxtThreadGroupID,
Name: "group_id",
},
{
ID: FieldCtxtThreadGroupStartTime,
Name: "thread_group_start_time",
},
{
ID: FieldCtxtContainerID,
Name: "container_id",
},
{
ID: FieldCtxtCredentials,
Name: "credentials",
},
{
ID: FieldCtxtProcessName,
Name: "process_name",
},
},
})
registerPoint(PointDesc{
ID: PointTaskExit,