Understanding Linux directory permissions reasoning
Execute bit: The execute bit is needed to traverse a directory. Permission to read a directory is controlled by the read bit.
See this shell dialogue for an example of this difference:
As root:
# find foo/ -ls
drwxr-xr-- 3 root root 4096 Apr 27 12:57 foo/
drwxr-xr-x 2 root root 4096 Apr 27 12:57 foo/bar
-rw-r--r-- 1 root root 0 Apr 27 12:57 foo/bar/file
as user:
$ ls foo/
bar
$ find foo/ -ls
drwxr-xr-- 3 root root 4096 Apr 27 12:57 foo/
find: foo/: Permission denied
$
The usual usage is the other way round though: removing read permissions but allowing traversal, e.g. to allow a web server into ~/public_html but not letting it do the default index listing by setting --x
.
Sticky bit: This was invented exactly to avoid the default rules about deletion within a directory so /tmp
works. /tmp
might reside on a different volume than /home
and/or be governed by different quotas.
The FHS codifies /tmp "for programs that require temporary files" while "[they] must not assume that any files or directories in /tmp are preserved between invocations".
Personally, I consider /tmp to be legacy from the heathen days when vi globals.h && make install
was considered an installation procedure. Nowadays programs should honour $TMPDIR
, which should point to a user-private system-managed directory, which should be cleaned at least on reboot. Even standardised functions like tmpfile(3) do not prescribe the actual path. Although there seem to be important compatibility and security concerns speaking for /tmp. Note though, that the last mail is from 1999, so things might have change since then.
Should POSIX sticky bit deny appending by root?
Answer found
The behavior you are showing seems to depend on the fs.protected_regular
Linux kernel parameter, introduced along with fs.protected_fifos
by this commit, with the aim to fix security vulnerabilities.
Solution:
sudo sysctl fs.protected_regular=0
Resources:
Since it is a patch, it probably won't be documented in more detail.
https://askubuntu.com/questions/1250974/user-root-cant-write-to-file-in-tmp-owned-by-someone-else-in-20-04-but-can-in/1251030#1251030
https://unix.stackexchange.com/questions/503111/group-permissions-for-root-not-working-in-tmp
NFS mount using CHEF on LINUX | permissions of directory not getting changed
As mentioned in the comment, this is not something Chef controls per se. After the mount, the folder will be owned by whatever the NFS server says. You can try to chmod the folder after mounting but that's up to your NFS configuration and whatnot as to if it will be allowed.
If I want to empty a directory, is there any reason I shouldn't remove it and recreate It?
The rm -fr /some/directory
command has to do the recursive work for you. Using the command is a lot simpler than writing your own code to do the same job — it embodies the virtue of laziness and exploits code reuse on the program scale. (You can't use the rmdir()
system call on a directory unless it is already empty.). So that's not wholly unreasonable.
One issue is security: can someone place an alternative to the system's rm
command on your path? On Unix, are /bin
and /usr/bin
first in your path, or do other directories come first?
If you decide that using /bin/rm
(or /usr/bin/rm
) is safe enough, that might be a better choice than an unadorned rm
, but overall, that isn't too bad.
Another issue is a different aspect of security — can you actually remove and create the directory? Can you write in /some
or not? And should you keep the current owner, group, permissions of /some/directory
if you remove and recreate it? After those operations, the directory will be owned by the effective UID of the process; if will belong to group with the effective GID of the process (unless there's a sticky bit set on the /some
directory — or unless you're on macOS); and the permissions will be 0777
as modified by the current setting of umask()
.
If these issues are not important, or are circumventable, then remove and recreate is plausible.
Expanding on the comments above:
When you mentioned the
system()
call in your comment, I had no idea what you were talking about.
The system()
function executes the string passed as an argument via a command interpreter. When you write code, you have to think about how it could go wrong when someone malicious is trying to get you run it. When you write "rm -fr /some/directory"
, you are relying on the shell finding the normal rm
command and working properly. However, if your PATH
has a value such as $HOME/bin:/bin:/usr/bin
(so that commands in your own private bin
directory are used in preference to those provided by the system), then if the user can install their own script as $HOME/bin/rm
, they can execute arbitrary code with your privileges — which could allow them to leave a way of breaking into your system later keeping all the privileges you have. They might even clean up (most of) the evidence that there was once a $HOME/bin/rm
script.
One way to avoid such a problem is to request "/bin/rm -fr /some/directory"
(unless rm
is /usr/bin
and not in /bin
, of course). This is arguably safer. There used to be attacks available via the IFS
environment variable; these are neutered by modern shells which do not use any inherited value for IFS
.
Note that one problem will be interpreting whether the rm
command was successful. The -fr
option means it will report success under almost all circumstances — but if the directory didn't vanish, your mkdir("/some/directory", 0777)
call will fail.
As for the security of the
/some/directory
, my understanding of what you're trying to say, is that the wrong directory could be selected. I just can't imagine how that would occur.
Assuming that you did have permission to modify the /some
directory (you need that to be able to remove /some/directory
), and that you could modify all the sub-directories of the old version of /some/directory
, then you might start off with /some/directory
owned by user victim
, group witless
and with permission 775, whereas after the command and system call (note that system()
is a function rather than a system call; mkdir()
is a system call) are successful, the directory might be owned by user victor
, group mischief
and with permission 0777. This might be less than ideal. If you don't want to break such permission settings, you probably don't want to use the remove and recreate technique — or, not such a simple-minded one as this example shows. You would then have to work a bit harder to remove the contents of the directory without modifying those attributes. You might scan the directory (opendir()
, readdir()
, closedir()
and invoke rm
on each name — or sets of names — to clean up thoroughly without removing the directory itself. This is of hybrid complexity. It is more fiddly than simply removing and recreating, but far less fiddly than dealing with full recursive delete over multiple levels.
As I said before, you have to decide whether these issues matter or not. It is important that you're aware that the issues exist, and that you have made a conscious (and informed) decision about whether to handle the issues, and how to handle the issues.
Remember that if your program may be run with root (administrator) privileges, it is a lot more important to be careful — but it still matters even if only ordinary mortal users will run the program.
Apache commons-io copy and inherit target permissions
The workaround for commons-io
2.9.0 and higher is:
- FileUtils.copyDirectory(folder, dest);
+ FileUtils.copyDirectory(folder, dest, false);
// HERE -----^
Or alternately...
- FileUtils.copyDirectory(folder, dest);
+ PathUtils.copyDirectory(folder.toPath(), dest.toPath(), StandardCopyOption.REPLACE_EXISTING);
//^------ HERE
Quoting some exchange with the Apache Commons mailing list:
I think this is the problematic line:
https://github.com/apache/commons-io/blob/f22a4227401855ecbfdf8184bbe37275c3aeb5c3/src/main/java/org/apache/commons/io/FileUtils.java#L701From what I'm reading, toggling off
preserveFileDate
will inadvertently and unobviously fix this, but at this point. This fix seems like undesired, undocumented and prone-to-break-later behavior, at least for Windows environments.I'm curious what reasoning was used to associate a file's modified date with the rest of its attributes. Perhaps this was a backward-compat shortcut to maintain the modified date using the new NIO API? Regardless, this introduces permissions changes which can and will break standard file copy operations for environments which expect inherited permissions, e.g. Windows.
Ideally, the file modified date could stay without clobbering the default NIO behavior.
For now a viable workaround is:
FileUtils.copyDirectory(folder, dest, false /* <--- change to FALSE */);
... however this does have the disadvantage of (potentially) losing timestamp information, which is still a regression, albeit smaller.
... however local tests show that timestamp information (files, not folders) is preserved by default on Windows (even with this flag off), so this second concern may not be as... well... concerning. The impact of this change on Unixes is yet to be tested.
Does chmod modify permissions of FILE... arguments in the order specified?
While not specified, all implementations behave naturally like you experienced, but there is no guarantee, beware POSIX (IEEE Std 1003.1-2008, 2016 Edition) says in chmod
command manual - Application Usage:
Some implementations of the chmod utility change the mode of a
directory before the files in the directory when performing a
recursive (-R option) change; others change the directory mode after
the files in the directory. If an application tries to remove read or
search permission for a file hierarchy, the removal attempt fails if
the directory is changed first; on the other hand, trying to re-enable
permissions to a restricted hierarchy fails if directories are changed
last. Users should not try to make a hierarchy inaccessible to
themselves.
Thus any order on the arguments can be applied, you need to use separate commands to ensure the order.
Related Topics
Running Docker on Google Colab
Full Process Name from Task_Struct
Best Way to Build Cross Toolchains on MAC Os X
Sudo User Not Using Same Node Version
Is There a 'ssh-Add' Linux Alpine One Liner
Bash Loop Through Directory Including Hidden File
How to Make Sure Only One Instance of a Bash Script Is Running at a Time
How to Detect If a Server Is Using Spdy
Is There Any Difference Between Executable Binary Files Between Distributions
How to Block Push to Master Branch on Remote
How to Redirect Http to Https Using Gcp Load Balancer
Why Having to Use Non-Blocking Fd in a Edge Triggered Epoll Function
How to Run a Script After User Login Authentication in Linux
How to Manually Install The Eclipse-Cdt Plugin from an Archive/Zip on Ubuntu