Wednesday, January 28, 2015

How to make a file immutable on Linux

Suppose you want to write-protect some important files on Linux, so that they cannot be deleted or tampered with by accident or otherwise. In other cases, you may want to prevent certain configuration files from being overwritten automatically by software. While changing their ownership or permission bits on the files by using chown or chmod is one way to deal with this situation, this is not a perfect solution as it cannot prevent any action done with root privilege. That is when chattr comes in handy.

chattr is a Linux command which allows one to set or unset attributes on a file, which are separate from the standard (read, write, execute) file permission. A related command is lsattr which shows which attributes are set on a file. While file attributes managed by chattr and lsattr are originally supported by EXT file systems (EXT2/3/4) only, this feature is now available on many other native Linux file systems such as XFS, Btrfs, ReiserFS, etc.

In this tutorial, I am going to demonstrate how to use chattr to make files immutable on Linux.
chattr and lsattr commands are a part of e2fsprogs package which comes pre-installed on all modern Linux distributions.

Basic syntax of chattr is as follows.
$ chattr [-RVf] [operator][attribute(s)] files...

The operator can be '+' (which adds selected attributes to attribute list), '-' (which removes selected attributes from attribute list), or '=' (which forces selected attributes only).

Some of available attributes are the following.
  • a: can be opened in append mode only.
  • A: do not update atime (file access time).
  • c: automatically compressed when written to disk.
  • C: turn off copy-on-write.
  • i: set immutable.
  • s: securely deleted with automatic zeroing.

Immutable Attribute

To make a file immutable, you can add "immutable" attribute to the file as follows. For example, to write-protect /etc/passwd file:
$ sudo chattr +i /etc/passwd

Note that you must use root privilege to set or unset "immutable" attribute on a file. Now verify that "immutable" attribute is added to the file successfully.
$ lsattr /etc/passwd

Once the file is set immutable, this file is impervious to change for any user. Even the root cannot modify, remove, overwrite, move or rename the file. You will need to unset the immutable attribute before you can tamper with the file again.

To unset the immutable attribute, use the following command:
$ sudo chattr -i /etc/passwd

If you want to make a whole directory (e.g., /etc) including all its content immutable at once recursively, use "-R" option:
$ sudo chattr -R +i /etc

Append Only Attribute

Another useful attribute is "append-only" attribute which forces a file to grow only. You cannot overwrite or delete a file with "append-only" attribute set. This attribute can be useful when you want to prevent a log file from being cleared by accident.

Similar to immutable attribute, you can turn a file into "append-only" mode by:
$ sudo chattr +a /var/log/syslog

Note that when you copy an immutable or append-only file to another file, those attributes will not be preserved on the newly created file.


In this tutorial, I showed how to use chattr and lsattr commands to manage additional file attributes to prevent (accidental or otherwise) file tampering. Beware that you cannot rely on chattr as a security measure as one can easily undo immutability. One possible way to address this limitation is to restrict the availability of chattr command itself, or drop kernel capability CAP_LINUX_IMMUTABLE. For more details on chattr and available attributes, refer to its man page.

How to limit network bandwidth on Linux

If you often run multiple networking applications on your Linux desktop, or share bandwidth among multiple computers at home, you will want to have a better control over bandwidth usage. Otherwise, when you are downloading a big file with a downloader, your interactive SSH session may become sluggish to the point where it's unusable. Or when you sync a big folder over Dropbox, your roommate may complain that video streaming at her computer gets choppy.

In this tutorial, I am going to describe two different ways to rate limit network traffic on Linux.

Rate Limit an Application on Linux

One way to rate limit network traffic is via a command-line tool called trickle. The trickle command allows you to shape the traffic of any particular program by "pre-loading" a rate-limited socket library at run-time. A nice thing about trickle is that it runs purely in user-space, meaning you don't need root privilege to restrict the bandwidth usage of a program. To be compatible with trickle, the program must use socket interface with no statically linked library. trickle can be handy when you want to rate limit a program which does not have a built-in bandwidth control functionality.

To install trickle on Ubuntu, Debian and their derivatives:
$ sudo apt-get install trickle

To install trickle on Fedora or CentOS/RHEL (with EPEL repository):
$ sudo yum install trickle

Basic usage of trickle is as follows. Simply put, you prepend trickle (with rate) in front of the command you are trying to run.
$ trickle -d -u

This will limit the download and upload rate of to specified values (in KBytes/s).

For example, set the maximum upload bandwidth of your scp session to 100 KB/s:
$ trickle -u 100 scp backup.tgz

If you want, you can set the maximum download speed (e.g., 300 KB/s) of your Firefox browser by creating a custom launcher with the following command.
trickle -d 300 firefox %u

Finally, trickle can run in a daemon mode, where it can restrict the "aggregate" bandwidth usage of all running programs launched via trickle. To launch trickle as a daemon (i.e., trickled):
$ sudo trickled -d 1000

Once the trickled daemon is running in the background, you can launch other programs via trickle. If you launch one program with trickle, its maximum download rate is 1000 KB/s. If you launch another program with trickle, each of them will be rate limited to 500 KB/s, etc.

Rate Limit a Network Interface on Linux

Another way to control your bandwidth resource is to enforce bandwidth limit on a per-interface basis. This is useful when you are sharing your upstream Internet connection with someone else. Like anything else, Linux has a tool for you. wondershaper exactly does that: rate-limit a network interface.

wondershaper is in fact a shell script which uses tc to define traffic shaping and QoS for a specific network interface. Outgoing traffic is shaped by being placed in queues with different priorities, while incoming traffic is rate-limited by packet dropping.

In fact, the stated goal of wondershaper is much more than just adding bandwidth cap to an interface. wondershaper tries to maintain low latency for interactive sessions such as SSH while bulk download or upload is going on. Also, it makes sure that bulk upload (e.g., Dropbox sync) does not suffocate download, and vice versa.

To install wondershaper on Ubuntu, Debian and their derivatives:
$ sudo apt-get install wondershaper

To install wondershaper on Fedora or CentOS/RHEL (with EPEL repository):
$ sudo yum install wondershaper

Basic usage of wondershaper is as follows.
$ sudo wondershaper

For example, to set the maximum download/upload bandwidth for eth0 to 1000Kbit/s and 500Kbit/s, respectively:
$ sudo wondershaper eth0 1000 500

You can remove the rate limit by running:
$ sudo wondershaper clear eth0

If you are interested in how wondershaper works, you can read its shell script (/sbin/wondershaper).


In this tutorial, I introduced two different ways to control your bandwidth usages on Linux desktop, on per-application or per-interface basis. Both tools are extremely user-friendly, offering you a quick and easy way to shape otherwise unconstrained traffic. For those of you who want to know more about rate control on Linux, refer to the Linux bible.

Clamping down on users with rbash

restricted sign

One way to restrict what users can do on your Linux systems is by using rbash -- the restricted Bourne Again shell -- but only if you take some additional steps to ensure that your users can't break out of their cells.

What is rbash?

Rbash is an alternative to chrooted accounts -- though it works much better as an add-on. It works by disallowing a number of shell features. For example, when assigned rbash as their shell, your users cannot change their PATH environment variable. They cannot change directories with the cd command. They cannot use full paths to run commands. They cannot use redirection. If you meander down to the 90th page or so of the bash man page, you will likely see a list of those things that a user cannot do if they are constrained to using rbash. The list will look something like this:
  • changing directories with cd
  • setting or unsetting the values of SHELL, PATH, ENV, or BASH_ENV
  • specifying command names containing /
  • specifying a file name containing a / as an argument to the . builtin command
  • Specifying a filename containing a slash as an argument to the -p option to the hash builtin command
  • importing function definitions from the shell environment at startup
  • parsing the value of SHELLOPTS from the shell environment at startup
  • redirecting output using the >, >|, <>, >&, &>, and >> redirection operators
  • using the exec builtin command to replace the shell with another command
  • adding or deleting builtin commands with the -f and -d options to the enable builtin command
  • Using the enable builtin command to enable disabled shell builtins
  • specifying the -p option to the command builtin command
  • turning off restricted mode with set +r or set +o restricted.
That's a lot of things to not be able to do if you're an rbash user. Unfortunately (or fortunately, depending on your role in this situation), there are also a lot of ways you can escape your rbash shell if you'vr been restricted. But before we get into this, let's first look at how rbash is set up and used.

For the first thing, it's an optional feature of bash. It can be included in bash if the --enable-restricted option is used with the configure command when bash is built. To make it usable, you (assuming you're the admin now) create a symbolic link to bash and call is rbash. It's as simple as that. And if you're not sure if a system that you use or administer provides the rbash functionality, try this:
  • Create a symbolic link to bash and call it rbash -- ln -s /bin/bash rbash
  • Start rbash -- rbash
  • Try a forbidden operation such as this one -- cd /tmp
If you get a response like what you see below, rbash is available to you.
$ cd /tmp
rbash: cd: restricted

Now, let's try breaking out. Obviously since you're running rbash within bash, you can always just ^D your way back to your starting point, but that wouldn't prove much. Instead, try starting yet another shell.
$ cd /tmp
rbash: cd: restricted
$ /bin/bash
rbash: /bin/bash: restricted: cannot specify `/' in command names
$ bash
$ cd /tmp
$ pwd
You can also try redirecting command output, changing your PATH variable, and asking where the date command is located (i.e., which date) and you will notice that you're not in Kansas anymore.

In the little exercise above, your restricted shell balked at your attempt to start a third shell when typing its full path, but not when you took advantage of the fact that /bin was on your search path and you typed just "bash". You might also be able to add other tools to your account that would allow you to do things that yoiur restricted environment would not.

For rbash to work well at restricting users, therefore, you also need to limit what they can do. You probably won't want /bin in their paths. That means that you probably want to set up a new bin directory containing only the commands that you want your restricted users to use. And it won't contain bash, scp, cp or any commands beyond what you want your restricted users to be able to do.

If you have a number of accounts to restrict, it's probably a good idea to set up a bin that all of them can use rather than giving each of them their own -- if only to save a little disk space.

Make sure that your restricted users' search paths are limited to your limited bin directory and, of course, make sure that bash is listed in their /etc/passwd entries.

Rbash will not stop your restricted users from listing files in other directories. If you need that kind of control, you should look into a chrooted setup in which their restricted environment appears to them to be the entire system. That kind of environment is more work than using rbash, but isn't all that difficult to configure.