Howdy coreutils, I would like to add a O_NOFOLLOW flag to cat so that users can specify if cat should follow a symlink at the final file in a path. This is motivated by the need to atomically read a file while ensuring it is not a symlink. This functionality is absent from coreutils, as far as I am aware.
I’d be grateful for any feedback, criticism, ideas on this proposed change. Is this something coreutils would be interested in merging if I wrote code + tests. Rationale ==== Without this functionality in cat, users are likely to do the next easiest option which is to use two separate commands to first check if the file is a symlink and then read the file. This can be a source of bugs and harm security because using two commands introduces a TOCTOU (Time-of-Check to Time-of-Use) issue. This is because it is always possible after the symlink check has occurred, but before cat is run the file is replaced with symlink. Such race condition bugs are especially dangerous because the harmful behavior is triggered only in rare circumstances, allowing them to enter production and be hard to debug. When might one encounter this: 1. Having privileged services or sudoer commands where a symlink be might be maliciously or accidentally substituted as the final file in the path (often called the confused deputy problem[0]). `serviceuser ALL=(ALL) NOPASSWD: cat /home/[0-9a-z_-]/file123` 2. Different scripts or users reading and writing to a shared directory. This need not be a security issue. If files are being created and destroyed frequently, a user may just wish to ensure they don’t accidentally read from a symlink when they don’t expect the file to be a symlink. For instance ensuring that a read does not leave the current directory. This is not a problem for directories because one can check if a directory is a symlink safely with any later action because you can compare the expected file path after traversing into that directory but before taking the action. This is safe because someone can’t change the directory you are already in into a symlink after you have transverse it. Thus, this change would strictly maintain the behavior of the O_NOFOLLOW flag in following directory symlinks prior to the last part of a path. While this can be solved by creating a binary or using python, I believe enabling reads to be atomic with symlink checks is an important building block that should be available at the level of coreutils. Allowing cat to support O_NOFOLLOW via a flag would be a simple way to add this functionality. Thanks for taking the time to read this, Ethan [0]: https://en.wikipedia.org/wiki/Confused_deputy_problem