Cannot open file for writing error while trying to edit a file in /tmp (even as root user)

Written by - 0 comments

Published on - Listed in Linux Security


While working on a RHEL 9 system, I wanted to edit a config file located in /tmp/. After sudoing to the root user, I opened the file with vim and was then pretty surprised to see I was unable to save my changes. Instead of writing and exiting the file, the terminal showed an error message:

E212: Can't open file for writing

Can't open file for writing error in vim. Even as root user.

Verifying permissions

The first thought was that the file system was mounted read-only - then obviously no write operations can be done. But the /tmp file system was correctly mounted with the rw flag.

Was it a basic file permission problem? But file permissions also looked fine, especially for the root user, which can write anything:

[root@rhel9 tmp]# ls -la /tmp/test1
-rw-r-----. 1 user group1 18 Sep  6 07:51 /tmp/test1

No errors were logged in any log.

SELinux could also be a potential blocker and was verified.

[root@rhel9 ~]# getenforce
Enforcing

Although SELinux is obviously enabled (enforcing), it should still be possible for the root user to write a file, even if root is not the owner.

Could it be related to special file attributes, which could add additional flags and make a file immutable? But lsattr showed the default attributes.

[root@rhel9 ~]# lsattr /tmp/test1
--------------e----- /tmp/test1

To top that all, a write operation using a simple echo into the file works:

[root@rhel9 ~]# echo "but why?" /tmp/test1
[root@rhel9 ~]# tail -n 1 /tmp/test1
but why?

I'm scratching my head at this point.

Kernel configuration: fs.protected_regular

Additional research to similar editing problems pointed me (via ArchLinux forums) towards the Kernel configuration options fs.protected_*. There are currently four such entries:

  • fs.protected_fifos: When set to "1" don't allow O_CREAT open on FIFOs that we don't own in world writable sticky directories, unless they are owned by the owner of the directory. When set to "2" it also applies to group writable sticky directories.
  • fs.protected_hardlinks: When set to "1" hardlinks cannot be created by users if they do not already own the source file, or do not have read/write access to it.
  • fs.protected_regular: When set to "1" don't allow O_CREAT open on regular files that we don't own in world writable sticky directories, unless they are owned by the owner of the directory. When set to "2" it also applies to group writable sticky directories.
    fs.protected_symlinks: When set to "1" symlinks are permitted to be followed only when outside a sticky world-writable directory, or when the uid of the symlink and follower match, or when the directory owner matches the symlink's owner.

To my understanding, the fs.protected_regular description matches the permission problems when trying to edit the file with vim. Besides this, the file in question is located inside /tmp, which is a world writeable sticky directoy.

Let's check the current Kernel settings using sysctl:

[root@rhel9 ~]# sysctl -a | grep fs.protected
fs.protected_fifos = 1
fs.protected_hardlinks = 1
fs.protected_regular = 1
fs.protected_symlinks = 1

They are all enabled.

Let's try a vim modification after disabling fs.protected_regular:

[root@rhel9 ~]# sysctl -w fs.protected_regular=0
fs.protected_regular = 0

[root@rhel9 ~]# vi /tmp/test1
-> Editing the file and adding [adding some additional text] at the end of the file
:wq

No error showed up this time and the added text was indeed saved in /tmp/test1:

[root@rhel9 ~]# tail -n 1 /tmp/test1
adding some additional text

After enabling fs.protected_regular again (set to 1), the vim edit permission error showed up again.

Where does this come from?

These additional file protections were added in the Linux Kernel 4.19 in commit namei: allow restricted O_CREAT of FIFOs and regular files. The goal is obviously to tackle a security issue, where an attacker could spoof on "shared" files in world writeable directories (e.g. PHP sys_temp_dir). That even root can't edit files anymore seems to be a side-effect.

This can also be reproduced in other Linux distributions. On an Ubuntu 22.04 and Debian 11 with Kernel 5.15 and on Debian 12 with Kernel 6.1.0, the fs.protected Kernel settings are by default set to these values:

claudio@ubuntu:~$ sudo sysctl -a | grep fs.protected
fs.protected_fifos = 1
fs.protected_hardlinks = 1
fs.protected_regular = 2
fs.protected_symlinks = 1

It turns out this is not a RHEL9 related "problem" but a newer Kernel security standard which I happened to never come across - until now. :-)

Note that these additional security settings are only applied on world writeable (1) or group writeable (2) directories with the sticky bit set (chmod 1777). On most Linux systems this is by default /tmp and /var/tmp:

root@debian ~ # stat /tmp/
  File: /tmp/
  Size: 4096          Blocks: 8          IO Block: 4096   directory
Device: fe00h/65024d    Inode: 2           Links: 9
Access: (1777/drwxrwxrwt)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2023-09-05 19:51:26.708920185 +0200
Modify: 2023-09-06 11:49:08.931388484 +0200
Change: 2023-09-06 11:49:08.931388484 +0200
 Birth: 2018-07-04 08:18:47.000000000 +0200

root@debian ~ # stat /var/tmp/
  File: /var/tmp/
  Size: 4096          Blocks: 8          IO Block: 4096   directory
Device: fe02h/65026d    Inode: 198         Links: 4
Access: (1777/drwxrwxrwt)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2023-09-06 02:15:10.973909196 +0200
Modify: 2023-09-06 00:00:02.193560882 +0200
Change: 2023-09-06 00:00:02.193560882 +0200
 Birth: 2018-07-04 08:18:59.675347253 +0200

Outside such directories, the normal permission handling applies and root can open, edit and save any regular file.


Add a comment

Show form to leave a comment

Comments (newest first)

No comments yet.

RSS feed

Blog Tags:

  AWS   Android   Ansible   Apache   Apple   Atlassian   BSD   Backup   Bash   Bluecoat   CMS   Chef   Cloud   Coding   Consul   Containers   CouchDB   DB   DNS   Database   Databases   Docker   ELK   Elasticsearch   Filebeat   FreeBSD   Galera   Git   GlusterFS   Grafana   Graphics   HAProxy   HTML   Hacks   Hardware   Icinga   Influx   Internet   Java   KVM   Kibana   Kodi   Kubernetes   LVM   LXC   Linux   Logstash   Mac   Macintosh   Mail   MariaDB   Minio   MongoDB   Monitoring   Multimedia   MySQL   NFS   Nagios   Network   Nginx   OSSEC   OTRS   Office   OpenSearch   PGSQL   PHP   Perl   Personal   PostgreSQL   Postgres   PowerDNS   Proxmox   Proxy   Python   Rancher   Rant   Redis   Roundcube   SSL   Samba   Seafile   Security   Shell   SmartOS   Solaris   Surveillance   Systemd   TLS   Tomcat   Ubuntu   Unix   VMWare   VMware   Varnish   Virtualization   Windows   Wireless   Wordpress   Wyse   ZFS   Zoneminder