4

How can we lock a symlink so it cannot be deleted?

With a normal file/directory chattr +i /file/location can achieve this but doing so with a symlink we get chattr: Operation not supported while reading flags on my-file.

There is a similar question, How to set `chattr +i` for my `/etc/resolv.conf `?, but without a solution that could be applied here.

Stephen Kitt
  • 411,918
  • 54
  • 1,065
  • 1,164
intika
  • 13,920
  • 7
  • 41
  • 79

3 Answers3

5

This doesn’t provide a solution, but it explains why chattr can’t make a symlink immutable.

On Linux, immutable attributes are part of a set of flags which are controlled using the FS_IOC_SETFLAGS ioctl. Historically this was implemented first in ext2, and chattr itself is still part of e2fsprogs. When it attempts to retrieve the flags, before it can set them, chattr explicitly checks that the file it’s handling is a regular file or a directory:

    if (!lstat(name, &buf) &&
        !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) {
        goto notsupp;
    }

One might think that removing these checks, or changing them to allow symlinks too, would be a good first step towards allowing chattr to make a symlink immutable, but the next hurdle comes up immediately thereafter:

    fd = open (name, OPEN_FLAGS);
    if (fd == -1)
        return -1;
    r = ioctl (fd, EXT2_IOC_GETFLAGS, &f);

ioctl operates on file descriptors, which means the target has to be opened before its flags can be set. Symlinks can’t be opened for use with ioctl; while open supports O_NOFOLLOW and O_NOPATH on symlinks, the former on its own will fail with ELOOP, and the latter will return a file descriptor which can’t be used with ioctl.

Stephen Kitt
  • 411,918
  • 54
  • 1,065
  • 1,164
3

chattr is not supported on symlinks but you can make an undeleteable link using bind mounts.

For directories:

$ mkdir a b
$ echo a>a/ok
$ sudo mount --bind a b
$ cat b/ok
a
$ rmdir b
rmdir: failed to remove 'b': Device or resource busy

And for files:

$ mkdir c d
$ echo c>c/ok
$ echo d>d/ok
$ sudo mount --bind c/ok d/ok
$ cat d/ok
c
$ rm d/ok
rm: cannot remove 'd/ok': Device or resource busy
laktak
  • 5,616
  • 20
  • 38
0

Since I can't comment:

chattr is most likely using one of chmod, fchmod() or fchmodat() syscalls, or ioctl(which doesn't mention anything about symlinks). Can't find which right now, though. Using Ubuntu man pages here, some of this might have changed.

From chmod man page:

chmod never changes the permissions of symbolic links; the chmod system call cannot change their permissions. This is not a problem since the permissions of symbolic links are never used. However, for each sym‐ bolic link listed on the command line, chmod changes the permissions of the pointed-to file. In contrast, chmod ignores symbolic links encoun‐ tered during recursive directory traversals.

Looking through the manpage of the fchmod,chmod and fchmodat syscall, none of them implement it. Chmod-ing will just dereference the path, and fchmodat() system call hasn't implemented AT_SYMLINK_NOFOLLOW:

AT_SYMLINK_NOFOLLOW If pathname is a symbolic link, do not dereference it: instead operate on the link itself. This flag is not currently implemented.

Nephilim
  • 49
  • 5