Add /proc/[pid]/cwd

PiperOrigin-RevId: 334478850
This commit is contained in:
Fabricio Voznika
2020-09-29 15:49:27 -07:00
committed by gVisor bot
parent 7fbb45e8ed
commit 4a428b13b2
5 changed files with 145 additions and 26 deletions
+44
View File
@@ -84,6 +84,7 @@ func (p *proc) newTaskDir(t *kernel.Task, msrc *fs.MountSource, isThreadGroup bo
"auxv": newAuxvec(t, msrc),
"cmdline": newExecArgInode(t, msrc, cmdlineExecArg),
"comm": newComm(t, msrc),
"cwd": newCwd(t, msrc),
"environ": newExecArgInode(t, msrc, environExecArg),
"exe": newExe(t, msrc),
"fd": newFdDir(t, msrc),
@@ -300,6 +301,49 @@ func (e *exe) Readlink(ctx context.Context, inode *fs.Inode) (string, error) {
return exec.PathnameWithDeleted(ctx), nil
}
// cwd is an fs.InodeOperations symlink for the /proc/PID/cwd file.
//
// +stateify savable
type cwd struct {
ramfs.Symlink
t *kernel.Task
}
func newCwd(t *kernel.Task, msrc *fs.MountSource) *fs.Inode {
cwdSymlink := &cwd{
Symlink: *ramfs.NewSymlink(t, fs.RootOwner, ""),
t: t,
}
return newProcInode(t, cwdSymlink, msrc, fs.Symlink, t)
}
// Readlink implements fs.InodeOperations.
func (e *cwd) Readlink(ctx context.Context, inode *fs.Inode) (string, error) {
if !kernel.ContextCanTrace(ctx, e.t, false) {
return "", syserror.EACCES
}
if err := checkTaskState(e.t); err != nil {
return "", err
}
cwd := e.t.FSContext().WorkingDirectory()
if cwd == nil {
// It could have raced with process deletion.
return "", syserror.ESRCH
}
defer cwd.DecRef(ctx)
root := fs.RootFromContext(ctx)
if root == nil {
// It could have raced with process deletion.
return "", syserror.ESRCH
}
defer root.DecRef(ctx)
name, _ := cwd.FullName(root)
return name, nil
}
// namespaceSymlink represents a symlink in the namespacefs, such as the files
// in /proc/<pid>/ns.
//
+1
View File
@@ -53,6 +53,7 @@ func (fs *filesystem) newTaskInode(task *kernel.Task, pidns *kernel.PIDNamespace
"auxv": fs.newTaskOwnedFile(task, fs.NextIno(), 0444, &auxvData{task: task}),
"cmdline": fs.newTaskOwnedFile(task, fs.NextIno(), 0444, &cmdlineData{task: task, arg: cmdlineDataArg}),
"comm": fs.newComm(task, fs.NextIno(), 0444),
"cwd": fs.newCwdSymlink(task, fs.NextIno()),
"environ": fs.newTaskOwnedFile(task, fs.NextIno(), 0444, &cmdlineData{task: task, arg: environDataArg}),
"exe": fs.newExeSymlink(task, fs.NextIno()),
"fd": fs.newFDDirInode(task),
+83 -24
View File
@@ -669,18 +669,22 @@ func (fs *filesystem) newExeSymlink(task *kernel.Task, ino uint64) *kernfs.Dentr
// Readlink implements kernfs.Inode.Readlink.
func (s *exeSymlink) Readlink(ctx context.Context, _ *vfs.Mount) (string, error) {
if !kernel.ContextCanTrace(ctx, s.task, false) {
return "", syserror.EACCES
}
// Pull out the executable for /proc/[pid]/exe.
exec, err := s.executable()
exec, _, err := s.Getlink(ctx, nil)
if err != nil {
return "", err
}
defer exec.DecRef(ctx)
return exec.PathnameWithDeleted(ctx), nil
root := vfs.RootFromContext(ctx)
if !root.Ok() {
// It could have raced with process deletion.
return "", syserror.ESRCH
}
defer root.DecRef(ctx)
vfsObj := exec.Mount().Filesystem().VirtualFilesystem()
name, _ := vfsObj.PathnameWithDeleted(ctx, root, exec)
return name, nil
}
// Getlink implements kernfs.Inode.Getlink.
@@ -688,23 +692,12 @@ func (s *exeSymlink) Getlink(ctx context.Context, _ *vfs.Mount) (vfs.VirtualDent
if !kernel.ContextCanTrace(ctx, s.task, false) {
return vfs.VirtualDentry{}, "", syserror.EACCES
}
exec, err := s.executable()
if err != nil {
if err := checkTaskState(s.task); err != nil {
return vfs.VirtualDentry{}, "", err
}
defer exec.DecRef(ctx)
vd := exec.(*fsbridge.VFSFile).FileDescription().VirtualDentry()
vd.IncRef()
return vd, "", nil
}
func (s *exeSymlink) executable() (file fsbridge.File, err error) {
if err := checkTaskState(s.task); err != nil {
return nil, err
}
var err error
var exec fsbridge.File
s.task.WithMuLocked(func(t *kernel.Task) {
mm := t.MemoryManager()
if mm == nil {
@@ -715,12 +708,78 @@ func (s *exeSymlink) executable() (file fsbridge.File, err error) {
// The MemoryManager may be destroyed, in which case
// MemoryManager.destroy will simply set the executable to nil
// (with locks held).
file = mm.Executable()
if file == nil {
exec = mm.Executable()
if exec == nil {
err = syserror.ESRCH
}
})
return
if err != nil {
return vfs.VirtualDentry{}, "", err
}
defer exec.DecRef(ctx)
vd := exec.(*fsbridge.VFSFile).FileDescription().VirtualDentry()
vd.IncRef()
return vd, "", nil
}
// cwdSymlink is an symlink for the /proc/[pid]/cwd file.
//
// +stateify savable
type cwdSymlink struct {
implStatFS
kernfs.InodeAttrs
kernfs.InodeNoopRefCount
kernfs.InodeSymlink
task *kernel.Task
}
var _ kernfs.Inode = (*cwdSymlink)(nil)
func (fs *filesystem) newCwdSymlink(task *kernel.Task, ino uint64) *kernfs.Dentry {
inode := &cwdSymlink{task: task}
inode.Init(task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, ino, linux.ModeSymlink|0777)
d := &kernfs.Dentry{}
d.Init(inode)
return d
}
// Readlink implements kernfs.Inode.Readlink.
func (s *cwdSymlink) Readlink(ctx context.Context, _ *vfs.Mount) (string, error) {
cwd, _, err := s.Getlink(ctx, nil)
if err != nil {
return "", err
}
defer cwd.DecRef(ctx)
root := vfs.RootFromContext(ctx)
if !root.Ok() {
// It could have raced with process deletion.
return "", syserror.ESRCH
}
defer root.DecRef(ctx)
vfsObj := cwd.Mount().Filesystem().VirtualFilesystem()
name, _ := vfsObj.PathnameWithDeleted(ctx, root, cwd)
return name, nil
}
// Getlink implements kernfs.Inode.Getlink.
func (s *cwdSymlink) Getlink(ctx context.Context, _ *vfs.Mount) (vfs.VirtualDentry, string, error) {
if !kernel.ContextCanTrace(ctx, s.task, false) {
return vfs.VirtualDentry{}, "", syserror.EACCES
}
if err := checkTaskState(s.task); err != nil {
return vfs.VirtualDentry{}, "", err
}
cwd := s.task.FSContext().WorkingDirectoryVFS2()
if !cwd.Ok() {
// It could have raced with process deletion.
return vfs.VirtualDentry{}, "", syserror.ESRCH
}
return cwd, "", nil
}
// mountInfoData is used to implement /proc/[pid]/mountinfo.
+1
View File
@@ -67,6 +67,7 @@ var (
taskStaticFiles = map[string]testutil.DirentType{
"auxv": linux.DT_REG,
"cgroup": linux.DT_REG,
"cwd": linux.DT_LNK,
"cmdline": linux.DT_REG,
"comm": linux.DT_REG,
"environ": linux.DT_REG,
+16 -2
View File
@@ -780,8 +780,12 @@ TEST(ProcSelfFdInfo, Flags) {
}
TEST(ProcSelfExe, Absolute) {
auto exe = ASSERT_NO_ERRNO_AND_VALUE(
ReadLink(absl::StrCat("/proc/", getpid(), "/exe")));
auto exe = ASSERT_NO_ERRNO_AND_VALUE(ReadLink("/proc/self/exe"));
EXPECT_EQ(exe[0], '/');
}
TEST(ProcSelfCwd, Absolute) {
auto exe = ASSERT_NO_ERRNO_AND_VALUE(ReadLink("/proc/self/cwd"));
EXPECT_EQ(exe[0], '/');
}
@@ -1473,6 +1477,16 @@ TEST(ProcPidExe, Subprocess) {
EXPECT_EQ(actual, expected_absolute_path);
}
// /proc/PID/cwd points to the correct directory.
TEST(ProcPidCwd, Subprocess) {
auto want = ASSERT_NO_ERRNO_AND_VALUE(GetCWD());
char got[PATH_MAX + 1] = {};
ASSERT_THAT(ReadlinkWhileRunning("cwd", got, sizeof(got)),
SyscallSucceedsWithValue(Gt(0)));
EXPECT_EQ(got, want);
}
// Test whether /proc/PID/ files can be read for a running process.
TEST(ProcPidFile, SubprocessRunning) {
char buf[1];