The trouble with symbolic links
The trouble with symbolic links
Posted Jul 11, 2022 20:00 UTC (Mon) by ma4ris5 (guest, #151140)Parent article: The trouble with symbolic links
Here is one conceptual way to _open up a file for read_ in a safe way
It is possible to validate a path with file descriptors,
using openat() family of functions, to open folders starting from root into the actual file,
and then _from the directory_, that contains the file, back to root folder with ".." traversal.
The inode numbers should match this validation.
"_from the directory_" can be checked this way:
Somehow discover the folder that contains the non-soft linked file.
Both directory and file must be fd-opened, and directory must contain that non-soft link file.
"_from the directory_" physical path can be discovered in a way "pwd -P" does it:
Fork, forked program must set working directory as the directory fd.
Then forked program can read /proc/self/cwd and print it for the caller process.
There are some other details that must be taken care too (signal handling, unrelated file descriptors),
to make fork work robustly, but that is out of scope for now.
For opening file for write can be done with the above elements too: grab a validated folder,
open non-soft linked file there.
Posted Jul 12, 2022 3:26 UTC (Tue)
by neilbrown (subscriber, #359)
[Link] (1 responses)
Or you could use realpath() to expand all the symlinks, validate the path in whatever way you care about, and then use openat2() with RESOLVE_NO_SYMLINKS.
(requires Linux 5.6 or later, glibc doesn't have a wrapper)
Posted Jul 15, 2022 6:10 UTC (Fri)
by ma4ris5 (guest, #151140)
[Link]
With all uncertainty, the approach that I mentioned, is to first hold file descriptor to something
After gaining trust for a folder file descriptor, use it in safe ways (for example create a file with symbolic links turned off).
So from Samba developer, /proc/self approach works for solving the real path for validation:
fd = openat(-1, "/bin", O_DIRECTORY); /* fd = 3 */
"/usr/bin" is safe, so fd 3 can be used for following operations.
The trouble with symbolic links
If any symlinks have been inserted into the path, the open will fail.
The trouble with symbolic links
that is nearest of the goal operation.
File descriptor is stable (Kernel guarantees that), so holding it prevents many kinds of race conditions.
Then validate the opened file descriptor based on trusted sources for security reasons.
resolved_path = realpath("/proc/self/fd/3", NULL); /* resolved_path="/usr/bin" */