1. Overview
In this article, we’ll be learning about how permissions apply to symbolic links.
We first will go over the relevant permissions of symbolic links. Then we’ll see how chmod and chown operate upon them.
2. How Do Permissions Relate to Symbolic Links?
To understand relevant symbolic link permissions, we can start by taking a look at their access permissions and ownership.
Let’s begin by creating a symbolic link pointing to a file on our Desktop. We can use su to execute the command ln as user1, which will make sure they have ownership of the created symlink.
$ su user1 -c 'ln -s "/home/user1/Desktop/subdir/file.txt" "/home/user1/links/user1_symlink"'
Then let’s use stat to print the permissions and ownership of the symlink we just created.
$ stat -c "%n | %A | %G:%U" '/home/user1/links/user1_symlink'
/home/user1/links/user1_symlink | lrwxrwxrwx | user1:user1
The symbolic notation, lrwxrwxrwx, is the only set of access permissions a symbolic link can have. Additionally, these permissions are only representative as they are never used for any operation.
Instead, it is up to the parent directory to determine how users may interact with a symlink.
Let’s see if we can access this symbolic link using the readlink command.
$ su user2 -c 'readlink -v "/home/user1/links/user1_symlink"'
readlink: /home/user1/links/user1_symlink: Permission denied
We don’t have the correct permissions to access the symbolic link, so let’s try adding execute permissions to the directories in its path. Then we can re-execute our previous command using fc to see if we get different results.
$ chmod +x "/home/user1/links/" "/home/user1/"; fc -s -1
...
/home/user1/Desktop/subdir/file.txt
The user must have permission to access a symbolic link’s parent directory to be able to access the symlink itself.
If we want readlink to follow a symbolic link instead of just accessing it, we can use the -f flag.
$ su user2 -c 'readlink -v -f "/home/user1/links/user1_symlink"'
readlink: /home/user1/links/user1_symlink: Permission denied
$ chmod +x "/home/user1/Desktop" "/home/user1/Desktop/subdir/"; fc -s -1
...
/home/user1/Desktop/subdir/file.txt
Following a symbolic link requires us to be able to access the target file’s parent directory. If we want to actually operate on the file the symbolic link points to, we need to have the correct permissions on that file as well.
2.1. Symbolic Links Inside Sticky Directories
Any user may remove a symbolic link if they have execute and write privileges of its parent directory with one exception. When a symbolic link is inside a sticky directory, only its owner may delete it. This is the default behavior for any file inside a sticky directory.
There is also a rule unique to symlinks inside sticky directories that are world-writable.
$ su user1 -c 'ln -s "/home/user1/Desktop/subdir" "/tmp/user1_tmp_symlink"'
$ su user2 -c 'cd "/tmp/user1_tmp_symlink"'
bash: line 1: cd: /tmp/user1_tmp_symlink: Permission denied
$ su user2 -c 'cd "/home/user1/Desktop/subdir" && echo "${PWD}"'
/home/user1/Desktop/subdir
Here we have a user who has the correct permissions to access the target file and the symbolic link. However, when trying to dereference the symlink, they get denied.
This occurs because only the symlink’s owner may follow a symbolic link in world-writable sticky directories.
3. How chmod and chown Apply Permissions to Symbolic Links
Two important commands used to apply permissions are chmod and chown. In this section, we go over how they apply to symbolic links.
Let’s start by running these commands on a symlink pointed to our Desktop directory.
$ su user1 -c 'ln -s "/home/user1/Desktop/" "/home/user1/links/user1_symlink2"'
$ chmod 740 '/home/user1/links/user1_symlink2'; chown user2:user2 "$_"
$ stat -c "%n - %a - %U:%G" '/home/user1/Desktop/'
"/home/user1/Desktop/" - 740 - user2:user2
Symbolic links passed to chmod or chown from the command line will be followed. This will cause only the target file to be modified, not the symbolic link.
We may also modify the ownership of a symbolic link with chown.
$ chown -h user2:user2 '/home/user1/links/user1_symlink2'
$ stat -c "%n %U:%G" "$_"
/home/user1/links/user1_symlink2 - user2:user2
The -h flag prevents any symbolic link from being followed when used with chown. There is no equivalent flag for chmod since access permissions can not be edited on symbolic links.
If we want to use recursion with chmod or chown, we can use the -R flag.
$ chmod -R 740 '/home/user1/links'; chown -R user2:user2 "$_"
$ stat -c "%n - %a - %U:%G" '/home/user1/Desktop/subdir/file.txt'
/home/user1/Desktop/subdir/file.txt - 700 - user1:user1
$ chmod 740 -R '/home/user1/links'{/,/*}; chown user1:user1 -R "$_"; fc -s -1
...
/home/user1/Desktop/subdir/file.txt - 740 - user1:user1
As we can see, chmod does not traverse symbolic links that are found using recursion unless they are explicitly passed through the command line. This works with passing a specific file manually but also works with Bash filename expansion.
chown, on the other hand, will not traverse any symbolic link during recursion, even when passed as an argument on the command line. Instead, if we want chown to traverse symbolic links during recursion, we can use the -H flag.
$ chown -R -H user2:user2 '/home/user1/links/'*
$ stat -c "%n - %U:%G" '/home/user1/Desktop/subdir/file.txt'
/home/user1/Desktop/subdir/file.txt - user2:user2
When using -H with chown symbolic links passed on the command line will be traversed.
This flag is just one of three flags used with -R when applying permissions using chown.
The second flag is the -L flag and causes all symlinks to be traversed during recursion. Finally, the -P flag is the default behavior when using -R and prevents any symbolic link from being dereferenced during recursion.
4. Conclusion
In conclusion, symbolic links have irrelevant access permissions. Users are only prevented from operating on a symlink by the permissions of its parent directory and the target file.
Passing a symlink specifically to chown or chmod will cause the target file to be operated on. If we want to traverse symbolic links recursively, we must use the -H or -L flag with chown or pass them as command-line arguments to chmod.