Return ENOENT when reading /proc/{pid}/task of an exited process

There will be a deadloop when we use getdents to read /proc/{pid}/task
of an exited process

Like this:

Process A is running
                         Process B: open /proc/{pid of A}/task
Process A exits
                         Process B: getdents /proc/{pid of A}/task

Then, process B will fall into deadloop, and return "." and ".."
in loops and never ends.

This patch returns ENOENT when use getdents to read /proc/{pid}/task
if the process is just exited.

Signed-off-by: chris.zn <chris.zn@antfin.com>
This commit is contained in:
chris.zn
2019-06-24 15:49:53 +08:00
parent 7e49515696
commit f957fb23cf
2 changed files with 25 additions and 1 deletions
+6 -1
View File
@@ -20,6 +20,7 @@ import (
"io"
"sort"
"strconv"
"syscall"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/sentry/context"
@@ -162,6 +163,11 @@ func (f *subtasksFile) Readdir(ctx context.Context, file *fs.File, ser fs.Dentry
// subtask to emit.
offset := file.Offset()
tasks := f.t.ThreadGroup().MemberIDs(f.pidns)
if len(tasks) == 0 {
return offset, syscall.ENOENT
}
if offset == 0 {
// Serialize "." and "..".
root := fs.RootFromContext(ctx)
@@ -178,7 +184,6 @@ func (f *subtasksFile) Readdir(ctx context.Context, file *fs.File, ser fs.Dentry
}
// Serialize tasks.
tasks := f.t.ThreadGroup().MemberIDs(f.pidns)
taskInts := make([]int, 0, len(tasks))
for _, tid := range tasks {
taskInts = append(taskInts, int(tid))
+19
View File
@@ -1908,6 +1908,25 @@ void CheckDuplicatesRecursively(std::string path) {
TEST(Proc, NoDuplicates) { CheckDuplicatesRecursively("/proc"); }
TEST(Proc, Getdents) {
int child_pid = fork();
ASSERT_GE(child_pid, 0);
if (child_pid == 0) {
while(1){
sleep(100);
}
}
ASSERT_THAT(child_pid, SyscallSucceeds());
char name[100];
char buf[1024];
int fd;
sprintf(name, "/proc/%d/task", child_pid);
fd = open(name, O_RDONLY | O_DIRECTORY);
ASSERT_THAT(kill(child_pid, SIGKILL), SyscallSucceeds());
ASSERT_THAT(waitpid(child_pid, NULL, 0), SyscallSucceedsWithValue(child_pid));
ASSERT_THAT(syscall(SYS_getdents, fd, buf, 1024), SyscallFailsWithErrno(ENOENT));
}
// Most /proc/PID files are owned by the task user with SUID_DUMP_USER.
TEST(ProcPid, UserDumpableOwner) {
int before;