Fix reference counting bug in /proc/PID/fdinfo/.

PiperOrigin-RevId: 245452217
Change-Id: I7164d8f57fe34c17e601079eb9410a6d95af1869
This commit is contained in:
Kevin Krakauer 2019-04-26 11:08:37 -07:00 committed by Shentubot
parent f4d34b420b
commit 5f13338d30
2 changed files with 19 additions and 34 deletions

View File

@ -236,24 +236,6 @@ func (f *fdDirFile) Readdir(ctx context.Context, file *fs.File, ser fs.DentrySer
})
}
// fdInfoInode is a single file in /proc/TID/fdinfo/.
//
// +stateify savable
type fdInfoInode struct {
staticFileInodeOps
file *fs.File
flags fs.FileFlags
fdFlags kernel.FDFlags
}
var _ fs.InodeOperations = (*fdInfoInode)(nil)
// Release implements fs.InodeOperations.Release.
func (f *fdInfoInode) Release(ctx context.Context) {
f.file.DecRef()
}
// fdInfoDir implements /proc/TID/fdinfo. It embeds an fdDir, but overrides
// Lookup and Readdir.
//
@ -283,6 +265,7 @@ func (fdid *fdInfoDir) Lookup(ctx context.Context, dir *fs.Inode, p string) (*fs
// locks, and other data. For now we only have flags.
// See https://www.kernel.org/doc/Documentation/filesystems/proc.txt
flags := file.Flags().ToLinux() | fdFlags.ToLinuxFileFlags()
file.DecRef()
contents := []byte(fmt.Sprintf("flags:\t0%o\n", flags))
return newStaticProcInode(ctx, dir.MountSource, contents)
})

View File

@ -455,24 +455,26 @@ TEST_F(PipeTest, LargeFile) {
EXPECT_EQ(rflags, 0);
}
// Test that accessing /proc/<PID>/fd/<FD> correctly decrements the refcount of
// that file descriptor.
// Test that accesses of /proc/<PID>/fd/<FD> and /proc/<PID>/fdinfo/<FD>
// correctly decrement the refcount of that file descriptor.
TEST_F(PipeTest, ProcFDReleasesFile) {
int fds[2];
ASSERT_THAT(pipe(fds), SyscallSucceeds());
FileDescriptor rfd(fds[0]);
FileDescriptor wfd(fds[1]);
std::vector<std::string> paths = {"/proc/self/fd/", "/proc/self/fdinfo/"};
for (const std::string& path : paths) {
int fds[2];
ASSERT_THAT(pipe(fds), SyscallSucceeds());
FileDescriptor rfd(fds[0]);
FileDescriptor wfd(fds[1]);
// Stat the pipe FD, which shouldn't alter the refcount of the write end of
// the pipe.
struct stat wst;
ASSERT_THAT(lstat(absl::StrCat("/proc/self/fd/", wfd.get()).c_str(), &wst),
SyscallSucceeds());
// Close the write end of the pipe and ensure that read indicates EOF.
wfd.reset();
char buf;
ASSERT_THAT(read(rfd.get(), &buf, 1), SyscallSucceedsWithValue(0));
// Stat the pipe FD, which shouldn't alter the refcount of the write end of
// the pipe.
struct stat wst;
ASSERT_THAT(lstat(absl::StrCat(path.c_str(), wfd.get()).c_str(), &wst),
SyscallSucceeds());
// Close the write end of the pipe and ensure that read indicates EOF.
wfd.reset();
char buf;
ASSERT_THAT(read(rfd.get(), &buf, 1), SyscallSucceedsWithValue(0));
}
}
} // namespace