2020-04-20
An important safety note about chown
and symlinks (also chmod and chgrp)
Today I had a little Twitter exchange about a little (or not so little) thing that is not as well known as it should be:
@thatcks: Ah yes, the eternal question: is it 'chown -Hr' or 'chown -hR' that I want?
(Answer: the second. Also, -h should be the default, at least with -R.)
@mrhoten: TIL I have run some pretty dang risky chown -R's and not even known it.
For those who haven't encountered this particular combination of
arguments for the chown
command, -R
is a recursive chown through a directory hierarchy, while -h is,
well, let me quote the manual (for GNU chown):
affect symbolic links instead of any referenced file (useful only on systems that can change the ownership of a symlink)
(Similar wording is in the FreeBSD chown manpage.)
Let me translate this. If you run plain 'chown -R user.group dirtree
',
and the directory tree contains symlinks that point outside itself,
your recursive chown will change the ownership of the files that those
symlinks point to. Is there a symlink to /etc/shadow
? Well, you just
changed its ownership. A recursive chown
without -h
can do random
damage to owners and groups anywhere on your system.
Recursive chowns aren't the only time this comes up. Consider 'chown
user.group *
' in a directory, to fix ownership for the user. If there
are any symlinks, congratulations, you once again changed the ownership
of random files on your system. You should always use -h
with
chown
unless you're sure you know what you're doing. You almost
never want to change the ownership of the target of a symlink.
(If you have a tangled chain of symlinks and you need to fix the
permissions of the real underlying file behind them all, generally
use realpath
to find out what it is first.)
Naturally the same thing applies to the chgrp
command. The GNU
chmod command unfortunately lacks a -h
option, and will always
change permissions on the target of symlinks given on the command
line (which might happen in, for example, 'chmod g+r *
').
FreeBSD's chmod
does have a -h
option and you should always use it unless you're
sure.
Sidebar: The potential bad state of OpenBSD and chown
The OpenBSD chown
manpage
contains the following hair-raising statement about the -h
option (emphasis mine):
Treat symbolic links like other files: modify links instead of following them. The
-h
and-R
options are mutually exclusive.
OpenBSD's chown
also has a -P argument, which is the default
behavior in 'chown -R
'. This is described as:
If the
-R
option is specified, no symbolic links are followed.
It's not clear what OpenBSD's manpage means by 'followed' here.
Are symbolic links that point to directories not descended into
but symbolic links are chown'd in general, or are symbolic links
entirely ignored, being neither chown'd nor descended into?
If OpenBSD chown
really does follow the POSIX chown
specification,
then the POSIX specification
is much clearer here and specifies the behavior we don't want:
If the
-R
option is specified and a symbolic link is specified on the command line or encountered during the traversal of a file hierarchy,chown
shall change the owner ID (and group ID, if specified) of the symbolic link. Thechown
utility shall not follow the symbolic link to any other part of the file hierarchy.
Update: I think I misread this and was wrong about the POSIX
behavior, because it specifies that with -P
, the symbolic link itself
is chown'd. That would make it the behavior we want.
If OpenBSD chown
really uses the POSIX behavior, then you can't safely
use chown
on OpenBSD to change the ownership of a directory tree. You
need to use a much more awkward find
command line to chown everything
that isn't a symlink.
(POSIX appears to implicitly forbid combining '-h
' and '-R
',
but that's crazy and may be a mistake in POSIX.)