1. Introduction

Permissions are a pillar of security. Because of this, an operating system (OS) should not only support filesystems with ways to store permissions but also provide mechanisms to handle them correctly in the kernel and modules around it. Thus, Linux has the umask command based on the umask() system call.

In this tutorial, we take a deep dive into umask and explore how to set a system-wide umask. First, we go over the way Linux handles default file permissions. Next, we extrapolate the usual base permissions set. After that, we check how umask augments these settings for new files. Finally, we enumerate ways to change the umask value globally.

For brevity, we use umask to mean both the actual mask and the command that handles it under Linux. Although the positions of permissions digits matter, they are taken as stand-alone numbers when we convert to other number systems.

We tested the code in this tutorial on Debian 12 (Bookworm) with GNU Bash 5.1.4. It should work in most POSIX-compliant environments unless otherwise specified.

2. Default File Permissions

When creating files, the OS typically assigns permissions based on a number of factors:

  • user that issued the creation command
  • context of the creation command
  • creation command parameters
  • umask

For example, *let’s create a new file with touch and check its permissions with ls and its [-l]ong listing mode*:

$ whoami
baeldung
$ touch file
$ ls -l
total 0
-rw-r--r-- 1 baeldung baeldung 0 May 05 06:56 file

In this case, we get a file owned by the currently logged-in user and its group as verified by whoami in the context of the current shells.

Further, the permissions are -rw-r–r–, i.e., 000110100100 in binary or octal mode 0644.

Let’s find out how these are calculated.

3. Base Permission Set

In essence, mode 777 or rwxrwxrwx (111111111) is the maximum or most open permission set for any filesystem object. Further, mode 666 or rw-rw-rw- (110110110) allows world reads and writes only since the executable permission is a bonus.

However, we have several special permissions:

  • 1### – sticky bit
  • 2### – SGID bit
  • 4### – SUID bit

With the above, the final base permission set is 0666 or -rw-rw-rw- (000110110110).

In fact, we can verify this via strace as well:

$ strace touch file
[...]
openat(AT_FDCWD, "file", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = 3
[...]

Evidently, touch uses the openat() system call to open or [O_CREAT]e the file.

The last argument, 0666, is the permissions to use or assign. It coincides with the base set above. Yet, as we saw earlier, the final permissions of the file are different.

4. umask Permission Modifications

In Linux, a umask is a way to reduce the permissions new files have.

In particular, to get the default permissions for newly created files, we OR the base mode (default usually 0666) with the current umask value as returned by the umask command:

$ umask
0022

Now, let’s perform the calculation Operation with the Base and umask permission modes, one by one, to get the Actual permissions of a new file in our case:

+---------------------------------------------------+
| Permission | Base | umask | Operation    | Actual |
|------------+------+-------+-----------------------|
| Special    |    0 | 0     | $(( 0 | 0 )) | 0      |
| Read       |    6 | 0     | $(( 6 | 0 )) | 6      |
| Write      |    6 | 2     | $(( 6 | 2 )) | 4      |
| Execute    |    6 | 2     | $(( 6 | 2 )) | 4      |
+---------------------------------------------------+

Of course, we can perform this for any umask and Base to arrive at the correct umask value.

In general, to apply the value we decide on, we just use the umask command:

$ umask
0022
$ umask 0044
$ umask
0044

Yet, a reboot wipes this setting, so we’d have to ensure the last command runs on start-up using this approach. However, there are several mechanisms to avoid having to deal with hard-to-manage files.

5. System-Wide umask

Normally, a umask applies to the current process, user, and context. However, we can also set a global umask via a Pluggable Authentication Module (PAM).

Once enabled, this module looks for the umask value at several locations in order:

  1. /etc/passwd
  2. /etc/pam.d/common-session
  3. /etc/login.defs
  4. /etc/default/login

Let’s see how we can configure the module.

5.1. Install pam-modules

To have control over configuration important for the general system security, we usually install the pam-modules package:

$ apt-get install pam-modules

In this case, we use apt to do so. At this point, we can configure pluggable modules for different stages of the system utilization.

5.2. Enable pam_umask.so Module

For managing the umask with pam-modules, we check for a line in the /etc/pam.d/common-session configuration file:

$ cat /etc/pam.d/common-session
[...]
session optional pam_umask.so
[...]

If the line above isn’t in the file, we can add it manually. This way, we ensure the pam_umask.so module is active. Otherwise, none of the settings below would be respected.

5.3. System-Wide Hard Default in /etc/pam.d/common-session

Actually, we can set a system-wide hard default value for umask by adding an option to the line in /etc/pam.d/common-session:

$ cat /etc/pam.d/common-session
[...]
session optional pam_umask.so umask=022
[...]

Now, any user or context in the system will start with a umask of 022. Using umask= this way sets the umask value permanently as long as there are no user-specific settings.

5.4. System-Wide Soft Default in /etc/default/login

To set a system-wide soft default, we can modify or create the /etc/default/login file with a UMASK= line:

$ cat /etc/pam.d/common-session
[...]
UMASK=024
[...]

Here, we use a value of 024 for the umask. This option has the least priority of all.

5.5. User Value in /etc/passwd

Using the additional information or GEneral Comprehensive Operating System (GECOS) field of a given user entry in the /etc/passwd file, we can also modify the umask:

$ cat /etc/passwd
[...]
baeldung:x:1000:1000:,,,umask=044:/home/baeldung:/bin/bash
[...]

For example, adding umask=044 as above would ensure umask returns that value for that particular user (baeldung in this case). The /etc/passwd user field setting takes precedence over all the others, except setting umask manually via the umask command for a particular session.

5.6. /etc/login.defs

Finally, we can modify the /etc/login.defs file with a UMASK line:

$ cat /etc/login.defs
[...]
UMASK 002
[...]

Here, we set a umask of 002. This value is considered only before the last resort: /etc/default/login.

6. systemd Unit umask

In Linux, a systemd unit is a service operated by the systemd system and service manager. The way a particular unit functions is described in a so-called unit file with definitions.

6.1. Unit File UMask

Among other options, the unit file syntax provides the UMask setting:

$ cat /etc/systemd/user/default.target.wants/pulseaudio.service
[...]
[Service]
[...]
UMask=0077
Slice=session.slice

[Install]
Also=pulseaudio.socket
WantedBy=default.target

In this case, we see the pulseaudio.service configuration and the UMask=0077 definition in the [Service] section. Effectively, this means that any file this unit creates has the 0077 mask as its default. If we don’t use the UMask option, the unit file umask defaults to 0022.

6.2. User Units

Usually, user units also have a default of 0022, since the value depends on the user service manager. Yet, the latter is most often linked to the system service manager.

Still, we can also modify the user@.service instance unit file to change the umask on a per-user basis:

$ cat /etc/systemd/system/user@<UID>.service
[...]
UMask=0044
[...]

Here, we see the UMask set to 0044 for the user with the UID user identifier via its user service manager configuration.

6.3. systemd-homed

Another approach involves user records as managed by systemd-homed.service.

Specifically, we can use the homectl command. With homectl, we create or modify home directories, including the .identity user record. The latter can include different settings that systemd-homed manages via the .identity files:

$ homectl update <USERNAME> --umask 0033

In this case, we update user USERNAME to have a umask of 0033 and also update their identity file.

7. Summary

In this article, we looked at the concept of a umask and how to configure its global value.

In conclusion, a umask is a critical security mechanism, so Linux provides several different ways to set it at different levels.