mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Adding /proc/[pid]/task/[tid]/children
PiperOrigin-RevId: 557888186
This commit is contained in:
committed by
gVisor bot
parent
8b9208aaa8
commit
3657484eee
@@ -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))
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user