Working with files in Linux – File Attributes

In the previous two posts, we’ve looked at file permissions and access control lists. Today let’s take look at file attributes. Whereas, permissions and ACL’s deal with user and group access to a file, attributes are properties of a file that regulate how the operating system interacts with a given file. There are 15 file attributes: append only (a), no atime updates (A), compressed (c), no copy on write (C), no dump (d), synchronous directory updates (D), extent format (e), immutable (i), data journalling (j), project hierarchy (P), secure deletion (s), synchronous updates (S), no tail-merging (t), top of directory hierarchy (T), and undeletable (u). Even though there are 15 attributes it’s been my experience that (i) immutable, and (a) append only attributes seem to be the only ones that work consistently across filesystems. If you are using an ext2, ext3, or ext4 filesystem then c,s, and u will not be honored by your filesystems. The secure delete (s), and undeletable (u) attributes would definitely be a nice-to-have feature in the future. If you are using btrfs (likely on a SUSE or OpenSUSE based system) then (c) compression will be respected along with a few others (feel free to experiment).

The only attribute flag that I want to look at today is (i) immutable. The reason I have singled this attribute out is to demonstrate the power you have with this flag, and because it’s the only one I use on any regular basis.

List attributes with lsattr

Let’s make a file and add some content to it:

luke@Tumbleweed01:~/Documents> touch file1
luke@Tumbleweed01:~/Documents> echo "Some awesome file content" >> file1
luke@Tumbleweed01:~/Documents> cat file1
Some awesome file content

What attributes does this file have upon creation?

luke@Tumbleweed01:~/Documents> lsattr file1
------------------- file1

By default, you will notice that newly created files have no attributes (at least if you are using OpenSUSE with btrfs like I am). If you are using Ubuntu you will very likely see the “e” flag which means that your file system is using extents for mapping the file to disk.

Making a file immutable with chattr

What does it mean to make a file “immutable”? Basically, this means that the file cannot be changed in any way. You can’t delete it, you can’t add new data, or remove old data, or even change its name. When you add the (i) attribute you have chiseled the file into stone. Not even root can change a file that has been marked immutable (at least not without removing the flag first).

Attribute flags can be added and removed with sudo using the  chattr command with +/- and the attribute.

sudo chattr +i file1

Now try to add another line to this file.

luke@Tumbleweed01:~/Documents> echo "Even more awesome content" >> file1
bash: file1: Operation not permitted

What about as root? Still not permitted right?

Can you delete it?

luke@Tumbleweed01:~/Documents> rm file1
rm: cannot remove 'file1': Operation not permitted
luke@Tumbleweed01:~/Documents> sudo rm file1
rm: cannot remove 'file1': Operation not permitted

Notice the message output “Operation not permitted” even when using sudo.

Our POSIX permissions have not changed if you check:

luke@Tumbleweed01:~/Documents> ls -l file1
-rw-r--r-- 1 luke users 26 Feb 21 10:49 file1

You can see that my user should have read and write access to this file. The file attribute tells the filesystem that the contents of this file are frozen and cannot change.

Remove the immutable flag by replacing +i with -i:

luke@Tumbleweed01:~/Documents> sudo chattr -i file1

 What is the use case for this?

I see using these attributes as only a single layer to defend files that I want to protect against accidental deletion or to prevent them from being altered. For example, I use a media server called Plex to stream photos and movies to other devices in my home. I use the immutable flag to prevent files from being accidentally deleted or maliciously deleted in the event that the wrong person was to gain access to my Plex server. File attributes should be seen as a way to further layer your file access scheme, and not as a replacement for best practices.

Working with Linux Files – Access Control Lists

In the last post, we looked at basic file permissions. The ideas covered in that post are probably enough to get you through a large portion of the real world scenario’s that you will encounter. There are some special cases, however. One of them being access control lists (ACL) which I will discuss in this post.

Access Control List – ACL

As we saw in part 1 every file on a Linux system has an owner and a group associated with it, each of which has separate permissions. But what if a user or group needed read permissions to a file that they do not own? You could modify permissions to allow all users access to a file with  chmod o+r but this is not ideal on a system with multiple users where data needs to be kept confidential. Instead of going this route, which is insecure, we can add a list of users, or groups, or both that have permissions to a file that are separate from the standard owner/group in basic POSIX permissions.

Using ACL’s

So let’s look at a simple example. Batman and the finance group need to be able to read and write a payroll document, Superman and Robin need to be able to write, but not read, the payroll document (we don’t want them to know that Batman makes more money than they do).

First, let’s set up our environment:

sudo useradd batman
sudo useradd superman
sudo useradd robin
sudo groupadd finance
sudo usermod -aG finance batman

Set a password for each user. I’m just going to use the username for each as the password to make it easy for this example. It should go without saying that this wouldn’t be an acceptable password policy for real world use.

sudo passwd batman
New password: 
BAD PASSWORD: it is based on a dictionary word
BAD PASSWORD: is too simple

sudo passwd superman
New password: 
BAD PASSWORD: it is based on a dictionary word
BAD PASSWORD: is too simple

sudo passwd robin
New password: 
BAD PASSWORD: it is based on a dictionary word
BAD PASSWORD: is too simple

Switch to the user batman and create a file called jlpayroll.txt in the /tmp directory.

su - batman
cd /tmp
newgrp finance
touch jlpayroll.txt
chmod 660 jlpayroll.txt
ls -l jlpayroll.txt
-rw-rw---- 1 batman finance 0 Feb  5 09:32 jlpayroll.txt

At this point, batman can read and write to the jlpayroll.txt file. Now add batman’s pay to this file.

echo "Batman Week One: 2,000,000" >> jlpayroll.txt 
cat jlpayroll.txt 
Batman Week One: 2,000,000

Now we need to add ACL’s to allow superman and robin to add their payroll information, while also ensuring that they can’t read the file. Batman can do that with the  setfacl command that he keeps in his utility belt.

setfacl -m u:superman:w -m u:robin:w jlpayroll.txt

Take a look at this command for a minute. First, notice that you can add multiple users at the same time each separated by the -m option. In the setfacl command -m means modify.

Next, notice the format that is used to identify users. The  setfacl  command expects 3 values separated by colons:

<type>:<name>:<permission> – the type can be “u” for user or “g” for group, the name is the group or username, and the permissions are the standard read, write, and execute permissions that we looked at previously.

So how does this affect the way permissions are displayed?

ls -l jlpayroll.txt -rw-rw----+ 1 batman finance 27 Feb 5 09:43 jlpayroll.txt

The change is subtle but it’s there. Notice the “+” after “-rw-rw—-“. That + sign indicates that permissions have been altered by access control lists.

How to display the ACL’s on a file.

Access control list’s can be displayed with the  getfacl command.

getfacl jlpayroll.txt 
# file: jlpayroll.txt
# owner: batman
# group: finance

The output here is a detailed look at exactly who has what level of access to this file. It lists the file name, owner, and group. Then each user and group have individual access level’s displayed.

Testing the ACL’s

Switch to the user superman and make sure he can write to the jlpayroll.txt file.

su - superman
cd /tmp
uid=1007(superman) gid=100(users) groups=100(users)
ls -l jlpayroll.txt
-rw-rw----+ 1 batman finance 27 Feb  5 09:43 jlpayroll.txt

We can see that superman is not in the finance group and he is not the owner of this file. Normally he wouldn’t have any access to this file at all. But with the ACL we set up earlier he should be able to write to this file but not read it.

cat jlpayroll.txt 
cat: jlpayroll.txt: Permission denied

As you can see superman cannot read the jlpayroll.txt file. Can he write to it?

echo "Superman Week One: 400" >> jlpayroll.txt

As long as that command doesn’t return an error then it should’ve worked. Let’s do the same thing for robin

su - robin
cd /tmp
echo "Robin Week One: 4,000" >> jlpayroll.txt

Since payroll is done for the week lets make sure that batman can see each entry. If you’ve been following along you can get back to batman using the “exit” command twice.

cat jlpayroll.txt 
Batman Week One: 2,000,000
Superman Week One: 400
Robin Week One: 4,000

Access control lists allow an administrator to exercise fine-grained control over files and directories that would not be possible using only POSIX permissions. This was a pretty simple example but it should give you an idea about how ACL’s work, how to set them, and how to discover what ACL’s are set on a file.

 Clean up

When you are finished with this example make sure you clean up your system to get rid of the users and group we made at the beginning of the tutorial. Switch back to your normal user account with sudo privileges.

sudo userdel batman
sudo userdel superman
sudo userdel robin
sudo groupdel finance
sudo rm /tmp/jlpayroll.txt

sudo bang bang

So a day or two ago a co-worker mentioned that you can do  sudo !! to execute the last command in your history as root. I had never heard of such a thing! My life has been changed forever!

Here I’ve been hitting the back arrow like a peasant just to put  sudo in front of a previous command.

Please use your new found powers responsibly.