Adding /proc/[pid]/task/[tid]/children

PiperOrigin-RevId: 557888186
This commit is contained in:
Shambhavi Srivastava
2023-08-17 11:41:48 -07:00
committed by gVisor bot
parent 8b9208aaa8
commit 3657484eee
4 changed files with 81 additions and 0 deletions
+2
View File
@@ -90,6 +90,8 @@ func (fs *filesystem) newTaskInode(ctx context.Context, task *kernel.Task, pidns
}
if isThreadGroup {
contents["task"] = fs.newSubtasks(ctx, task, pidns, fakeCgroupControllers)
} else {
contents["children"] = fs.newTaskOwnedInode(ctx, task, fs.NextIno(), 0644, &childrenData{task: task, pidns: pidns})
}
if len(fakeCgroupControllers) > 0 {
contents["cgroup"] = fs.newTaskOwnedInode(ctx, task, fs.NextIno(), 0444, newFakeCgroupData(fakeCgroupControllers))
+34
View File
@@ -18,6 +18,7 @@ import (
"bytes"
"fmt"
"io"
"sort"
"strconv"
"strings"
@@ -1440,3 +1441,36 @@ func (d *taskCgroupData) Generate(ctx context.Context, buf *bytes.Buffer) error
d.task.GenerateProcTaskCgroup(buf)
return nil
}
// childrenData implements vfs.DynamicBytesSource for /proc/[pid]/task/[tid]/children.
//
// +stateify savable
type childrenData struct {
kernfs.DynamicBytesFile
task *kernel.Task
// pidns is the PID namespace associated with the proc filesystem that
// includes the file using this childrenData.
pidns *kernel.PIDNamespace
}
// Generate implements vfs.DynamicBytesSource.Generate.
func (d *childrenData) Generate(ctx context.Context, buf *bytes.Buffer) error {
children := d.task.Children()
var childrenTIDs []int
for childTask := range children {
childrenTIDs = append(childrenTIDs, int(d.pidns.IDOfTask(childTask)))
}
// The TIDs need to be in sorted order in accordance with the Linux implementation.
sort.Ints(childrenTIDs)
for _, childrenTID := range childrenTIDs {
// It contains a space-separated list of child tasks of the `task`.
// Each task is represented by its TID.
fmt.Fprintf(buf, "%d ", childrenTID)
}
return nil
}
+13
View File
@@ -545,3 +545,16 @@ func (t *Task) ThreadID() ThreadID {
func (t *Task) TGIDInRoot() ThreadID {
return t.tg.pidns.owner.Root.IDOfThreadGroup(t.tg)
}
// Children returns children of this task.
func (t *Task) Children() map[*Task]struct{} {
t.tg.pidns.owner.mu.RLock()
defer t.tg.pidns.owner.mu.RUnlock()
children := make(map[*Task]struct{}, len(t.children))
for child, val := range t.children {
children[child] = val
}
return children
}
+32
View File
@@ -2390,6 +2390,38 @@ TEST(ProcTask, VerifyTaskDir) {
DirContains(absl::StrCat("/proc/self/task/", getpid()), {}, {"task"}));
}
TEST(ProcTask, VerifyTaskChildren) {
auto path = JoinPath("/proc", absl::StrCat(getpid()), "task",
absl::StrCat(gettid()), "children");
EXPECT_THAT(access(path.c_str(), F_OK), SyscallSucceeds());
int pid1 = -1, status1 = -1;
auto cleanup1 =
ForkAndExec("/bin/sleep", {"sleep", "100"}, {}, nullptr, &pid1, &status1);
ASSERT_GT(pid1, 0);
ASSERT_EQ(status1, 0);
auto proc_children_file = ASSERT_NO_ERRNO_AND_VALUE(GetContents(path));
EXPECT_EQ(absl::StrCat(pid1, " "), proc_children_file);
int pid2 = -1, status2 = -1;
auto cleanup2 =
ForkAndExec("/bin/sleep", {"sleep", "100"}, {}, nullptr, &pid2, &status2);
ASSERT_GT(pid2, 0);
ASSERT_EQ(status2, 0);
proc_children_file = ASSERT_NO_ERRNO_AND_VALUE(GetContents(path));
// /children contains space-separated sorted list of thread Ids of children.
std::string expectedContent;
if (pid1 < pid2) {
expectedContent = absl::StrCat(pid1, " ", pid2, " ");
} else {
expectedContent = absl::StrCat(pid2, " ", pid1, " ");
}
EXPECT_EQ(expectedContent, proc_children_file);
}
TEST(ProcTask, TaskDirCannotBeDeleted) {
// Drop capabilities that allow us to override file and directory permissions.
AutoCapability cap(CAP_DAC_OVERRIDE, false);