0

On Linux, I'm looking at /proc/1/cwd. This symlink is not readable as a normal user:

$ ls /proc/1/cwd ls: cannot access '/proc/1/cwd': Permission denied 

But /proc/1 is accessible:

$ ls /proc/1 <output> 

After becoming root, you see that /proc/1/cwd points to / (filesystem root):

$ sudo ls -l /proc/1/cwd lrwxrwxrwx 1 root root 0 Feb 21 12:56 /proc/1/cwd -> / 

And of course the filesystem root is readable, as a normal user:

$ ls / <output> 

If symbolic links don't have any permissions on Linux, then why is such a symbolic link not readable, when its target (the filesystem root) is readable?

1
  • 2
    It's important to understand that directories and files under /proc are not normal filesystems. They are data structures in the kernel that are exposed to regular commands/processes through an interface that makes them look like filesystems with directories, files, and symbolic links. So the rules that apply to normal filesystems may not apply in the same ways to things under /proc. Commented Feb 22 at 4:55

2 Answers 2

5

Reading / is typically not privileged, but knowing the current working directory of another user’s processes is. /proc adds additional checks before allowing readlink:

Permission to dereference or read (readlink(2)) this symbolic link is governed by a ptrace access mode PTRACE_MODE_READ_FSCREDS check; see ptrace(2).

This applies to other links inside /proc, in particular exe and root. The reasoning is similar: a process’ executable is typically readable by everyone, but knowing a given process’ executable is sensitive information.

0
2

That's the current work directory of the process, which is considered private and possibly sensitive.

See man 5 proc_pid_cwd:

Permission to dereference or read (readlink(2)) this symbolic link is governed by a ptrace access mode PTRACE_MODE_READ_FSCREDS check; see ptrace(2)

With [man 2 ptrace] having:

Ptrace access mode checking

Various parts of the kernel-user-space API (not just ptrace() operations), require so-called "ptrace access mode" checks, whose outcome determines whether an operation is permitted (or, in a few cases, causes a "read" operation to return sanitized data). These checks are performed in cases where one process can inspect sensitive information about, or in some cases modify the state of, another process. The checks are based on factors such as the credentials and capabilities of the two processes, whether or not the "target" process is dumpable, and the results of checks performed by any enabled Linux Security Module (LSM)—for example, SELinux, Yama, or Smack—and by the commoncap LSM (which is always invoked).

Prior to Linux 2.6.27, all access checks were of a single type. Since Linux 2.6.27, two access mode levels are distinguished:

PTRACE_MODE_READ

For "read" operations or other operations that are less dangerous, such as: get_robust_list(2); kcmp(2); reading /proc/pid/auxv, /proc/pid/environ, or /proc/pid/stat; or readlink(2) of a /proc/pid/ns/* file.
[...]

PTRACE_MODE_FSCREDS

Use the caller's filesystem UID and GID (see credentials(7)) or effective capabilities for LSM checks.
[...]
Because combining one of the credential modifiers with one of the aforementioned access modes is typical, some macros are defined in the kernel sources for the combinations:

PTRACE_MODE_READ_FSCREDS

Defined as PTRACE_MODE_READ | PTRACE_MODE_FSCREDS.

And man 7 credentials having:

  • Filesystem user ID and filesystem group ID (Linux-specific). These IDs, in conjunction with the supplementary group IDs described below, are used to determine permissions for accessing files; see path_resolution(7) for details. Whenever a process's effective user (group) ID is changed, the kernel also automatically changes the filesystem user (group) ID to the same value. Consequently, the filesystem IDs normally have the same values as the corresponding effective ID, and the semantics for file-permission checks are thus the same on Linux as on other UNIX systems. The filesystem IDs can be made to differ from the effective IDs by calling setfsuid(2) and setfsgid(2).

(essentially the same as effective ids, those Linux-specific FS ids are being deprecated as no longer necessary according to setfsgid()'s man page).

So basically, to be able to do a readlink() or dereference /proc/$pid/cwd, the calling process (if it's not related to $pid) must have the same credentials as those of $pid. Note that it checks the calling process filesystem (effective) ids against all the effective, real and saved IDs of $pid. So if that $pid has different effective and real gid for instance (like when a process executes a file that has the sgid bit set in its permissions), only root (or a process with appropriate capabilities) can get that information.

In the case of pid 1, typically running as root and that has no parent, only root can get that info.

As a side note, note that ls behaves differently with and without -l.

With -l (or some other options that report some attributes of the target file such as -F), ls does a lstat() on the file and so for a symlink returns information about the symlink itself, but without, it does a stat() so dereferences the symlink (and if the stat() succeeded, ls /proc/1/cwd would list the contents of pid 1's current working directory).

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.