The nodev mount option
Brief summary about mount security principles, Linux file types and risk about this specific option.
Disclaimer: this article is not intended to be exhaustive and is the result of my own research and understanding of this quiet complex and vast subject.
About mounting
Operating systems implement many interoperable features in order to read, write or execute files from file systems. Some of them are based on standards: CIFS SMB, NFS, ...
On Linux, mount
is a privileged system call to attach a filesystem specified by a source related to a type with options.
Note:
mount
program is different thanmount
system call: the first one does not need specific privileges by default, unless you use it to effectively mount a filesystem. You can spotmount
program callingmount
syscall by usingstrace mount
for a real mount attempt. By default, without arguments,mount
program will read informative system files like/proc/self/mountinfo
readable by standard users.
Mount privileges
You could tell that the usage of root
user (EUID 0) is mandatory, but I will answer you that only CAP_SYS_ADMIN
effective capability is needed (Read page 2 of mount manual).
By default, that should be enabled in the initial user namespace, it does not apply to a child user namespace except if the requested filesystem especially accept it through a fs_flag
containing FS_USERNS_MOUNT
. Fast preview from a grep
in Linux source code shows that OverlayFS could be mount by a non-privileged user in their initial user namespace:
fs/overlayfs/super.c:1480: .fs_flags = FS_USERNS_MOUNT,
So, given a mount (MNT) namespace and user (USR) namespace combined with
CAP_SYS_ADMIN
capability could offer you a privileged access to local devices sharing this namespace.
Required and obtained privileges are also dependent of each filesystem module implementation. The GameOver(lay) vulnerability (CVE-2023-2640 and CVE-2023-32629) exploits a defect in the OverlayFS module in the security management of mounting this filesystem for non-privileged user.
Additionally, mount
could also be gated through seccomp or AppArmor.
Mount types
As explained in the page 8 of mount manual, the mount type matches the compatible filesystem to be attached to your current context.
Mount types can be found in folder /lib/modules/$(uname -r)/kernel/fs
. In my case:
❯ find /lib/modules/$(uname -r)/kernel/fs/ -type d | cut -d '/' -f7 | sort | uniq
9p
adfs
affs
afs
autofs
befs
bfs
btrfs
cachefiles
ceph
cifs
coda
configfs
dlm
ecryptfs
efivarfs
efs
erofs
exfat
ext4
f2fs
fat
freevxfs
fscache
fuse
gfs2
hfs
hfsplus
hpfs
isofs
jbd2
jffs2
jfs
ksmbd
lockd
minix
netfs
nfs
nfs_common
nfsd
nilfs2
nls
ocfs2
omfs
orangefs
overlayfs
pstore
qnx4
qnx6
quota
reiserfs
romfs
smbfs_common
squashfs
sysv
ubifs
udf
ufs
vboxsf
xfs
zonefs
Mount options
The manual also specifies that filesystem mounting can be done with following options:
async
atime
auto
context=context
defaults
defcontext=context
dev
diratime
dirsync
exec
fscontext=context
group
iversion
lazytime
loud
mand
_netdev
noatime
noauto
nodev
nodiratime
noexec
nofail
noiversion
nolazytime
nomand
norelatime
nostrictatime
nosuid
nosymfollow
nouser
owner
relatime
remount
ro
rootcontext=context
rw
silent
strictatime
suid
sync
user
users
x-*
X-*
X-mount.auto-fstypes=list
X-mount.group=group|GID
X-mount.idmap=id-type:id-mount:id-host:id-range
X-mount.mkdir[=mode]
X-mount.mode=mode
X-mount.owner=username|UID
X-mount.subdir=directory
All these options are not compatible / implemented for every filesystem / OS / context.
The options have an effect on the attached filesystem behavior, and sometimes on general security.
I did not find a clear compatibility matrix between mount types and options. You are welcome to share one!
Mounting operations and udisks
Although mount
system call needs privileges, hopefully a standard user does not always directly needs them by default to get a filesystem mount.
For an easy example, in non-hardened systems, an unprivileged user should have the capability to use an USB flash drive without having administrator rights.
How do we manage unprivileged mounts (without messing up with kernel)?
Auto-mount handling is managed by external programs.
First, in my case, GNOME is responsible of this feature:
❯ gsettings get org.gnome.desktop.media-handling automount
true
Second, though I did not dig into GNOME code, it is probably interacting with udisks
(Or udisks2
) interface, dedicated to mount USB flash drives without high privileges.
You can try with
udisksctl mount -b /dev/sda1
(If/dev/sda1
is the target partition of your USB flash drive), then you will get your UDisk mounted at/media/user/xyz
.
That's sound crazy at first sight: how this device get mounted in so far mount
syscall needs CAP_SYS_ADMIN
privileges ?
Because udisks
is asynchronous: it works via polling and jobs thanks to its autonomous daemon, and not direct user action. It can be seen with udiskctl monitor
. Example after a direct USB flash drive plug-in:
19:53:05.489: Added /org/freedesktop/UDisks2/block_devices/sda
org.freedesktop.UDisks2.Block:
Configuration: []
CryptoBackingDevice: '/'
Device: /dev/sda
DeviceNumber: 2048
Drive: '/org/freedesktop/UDisks2/drives/General_UDisk_General_UDisk_0_3a0'
HintAuto: true
HintIconName:
HintIgnore: false
HintName:
HintPartitionable: true
HintSymbolicIconName:
HintSystem: false
Id:
IdLabel:
IdType:
IdUUID:
IdUsage:
IdVersion:
MDRaid: '/'
MDRaidMember: '/'
PreferredDevice: /dev/sda
ReadOnly: false
Size: 8054112256
Symlinks: /dev/disk/by-diskseq/27
/dev/disk/by-id/usb-General_UDisk-0:0
/dev/disk/by-path/pci-0000:06:00.4-usb-0:2:1.0-scsi-0:0:0:0
UserspaceMountOptions:
org.freedesktop.UDisks2.PartitionTable:
Partitions:
Type: dos
19:53:05.553: Added /org/freedesktop/UDisks2/block_devices/sda1
org.freedesktop.UDisks2.Block:
Configuration: []
CryptoBackingDevice: '/'
Device: /dev/sda1
DeviceNumber: 2049
Drive: '/org/freedesktop/UDisks2/drives/General_UDisk_General_UDisk_0_3a0'
HintAuto: true
HintIconName:
HintIgnore: false
HintName:
HintPartitionable: true
HintSymbolicIconName:
HintSystem: false
Id: by-uuid-5B67C7955E71E727
IdLabel: usb1
IdType: ntfs
IdUUID: 5B67C7955E71E727
IdUsage: filesystem
IdVersion:
MDRaid: '/'
MDRaidMember: '/'
PreferredDevice: /dev/sda1
ReadOnly: false
Size: 8053063680
Symlinks: /dev/disk/by-id/usb-General_UDisk-0:0-part1
/dev/disk/by-label/usb1
/dev/disk/by-partuuid/a100c314-01
/dev/disk/by-path/pci-0000:06:00.4-usb-0:2:1.0-scsi-0:0:0:0-part1
/dev/disk/by-uuid/5B67C7955E71E727
UserspaceMountOptions:
org.freedesktop.UDisks2.Filesystem:
MountPoints:
Size: 0
org.freedesktop.UDisks2.Partition:
Flags: 0
IsContained: false
IsContainer: false
Name:
Number: 1
Offset: 1048576
Size: 8053063680
Table: '/org/freedesktop/UDisks2/block_devices/sda'
Type: 0x07
UUID: a100c314-01
19:53:05.553: /org/freedesktop/UDisks2/block_devices/sda: org.freedesktop.UDisks2.PartitionTable: Properties Changed
Partitions: /org/freedesktop/UDisks2/block_devices/sda1
19:53:05.617: Added /org/freedesktop/UDisks2/jobs/14
org.freedesktop.UDisks2.Job:
Bytes: 0
Cancelable: true
ExpectedEndTime: 0
Objects: /org/freedesktop/UDisks2/block_devices/sda1
Operation: filesystem-mount
Progress: 0.0
ProgressValid: false
Rate: 0
StartTime: 1692813185616440
StartedByUID: 0
19:53:05.668: /org/freedesktop/UDisks2/jobs/14: org.freedesktop.UDisks2.Job::Completed (true, '')
19:53:05.669: Removed /org/freedesktop/UDisks2/jobs/14
19:53:05.669: /org/freedesktop/UDisks2/block_devices/sda1: org.freedesktop.UDisks2.Filesystem: Properties Changed
MountPoints: /media/seb/usb1
19:53:05.673: /org/freedesktop/UDisks2/block_devices/sda1: org.freedesktop.UDisks2.Block: Properties Changed
UserspaceMountOptions: uhelper=udisks2
udisks
security can be configured with (Not exhaustive):
polkit
rules (Check/usr/share/polkit-1/*
and/etc/polkit-1/*
).- Options from
/etc/udisks2/mount_options.conf
. - Hardcoded configuration. As the manual of
udisks2
is pretty good, you can refer to http://storaged.org/doc/udisks2-api/latest/mount_options.html. It is particularly written:
Apart from the final computed options UDisks always adds the following options due to security concerns:
nodev, nosuid, uhelper=udisks2
no matter if included in _allow or not. These are hardcoded and can't be changed.
That said, we can go deeper in the mount option nodev
and why it is important for system security.
The nodev
option
From the Linux manual
Sure it could be very interesting to enumerate all security impacts for all other options for each filesystem, but I will just explain the security risk about nodev
option.
What does the manual tell us about nodev
?
Do not interpret character or block special devices on the filesystem.
It could be unclear about real effects of this option on the attached filesystem and security, especially for a Linux neophyte. Some knowledges are prerequisites about Linux file types before understanding the impacts.
Let me tell you how I discovered the security risk about NOT using the nodev
option ...
Security risk
The case
I was analysing the security of two devices, where first one (A) had an automatic CIFS SMB mount of a share from the other one (B).
I have limited privileges on the device (A).
I have high privileges on the share of the device (B).
About file types
I was aware that every file you see on a filesystem could not be a regular file. In fact, we can distinguish following file types (Brought by POSIX standard, read https://en.wikipedia.org/wiki/Unix_file_types):
- Regular file
- Directory file
- Symbolic link (Or symlink)
- FIFO (Or named pipe)
- Socket
- Device file (Divided in character or block types)
Synthesis with needed capabilities for creating these files:
File type | Macro name (S_IFMT ) | File type attribute flag | Needed capabilities | Example of file creation |
---|---|---|---|---|
Regular | S_IFREG | - | - | touch myfile |
Directory | S_IFDIR | d | - | mkdir mydirectory |
Symbolic link | S_IFLNK | l | - | ln -s mysymlink |
FIFO | S_IFIFO | p | - | mknod myfifo p |
Socket | S_IFSOCK | s | - | socat UNIX-LISTEN:my.socket - |
Device (block) | S_IFBLK | b | Capability CAP_MKNOD | mknod myblockdevice b 1 2 |
Device (character) | S_IFCHR | c | Capability CAP_MKNOD | mknod mychardevice c 3 4 |
A block device is using two identifiers to point a real device like a disk. You can list them with lsblk
. For example, on the device (A), we have:
nvme1n1 259:5 0 931,5G 0 disk
└─nvme1n1p1 259:6 0 931,5G 0 part /
So the partition nvme1n1p1
have identifiers 259
and 6
.
The matching block device file can also be found at /dev/nvme1n1p1
:
❯ ls -l /dev/nvme1n1p1
brw-rw---- 1 root disk 259, 6 23 août 20:25 /dev/nvme1n1p1
If I create a block device somewhere else with those identifiers, it will refer to the same partition.
Experiment
I was curious how device files (which needs high privileges) were interpreted through SMB mount ...
On the device (B), I can create a block device matching the partition from the device (A):
# In the SMB share from device (B) - Creation of block device pointing to the partition present in device (A)
sudo mknod mypartition b 259 6
Go back in the device (A), with standard user:
# Go into the SMB share mounted path
❯ cd /mnt/shared
# List
❯ ls -l
brwxrwxrwx 1 root root 259, 6 22 août 20:30 mypartition
# Try to display the block device
❯ head mypartition
# (...) Raw bytes here (...)
Consequences
I can have now a full raw access to the main partition as a standard user, through the mounted block device.
Why it is permitted ? For this case, it is mainly because nodev
was not set in the options of the CIFS SMB share mount.
If nodev
were set (mount -t cifs -o nodev (...)
), I would had an error of type EACCES
, even with root
user, which is very efficient.
You can reproduce it with a single USB flash drive containing a block device, without using udisk
. Simply mount it with mount -t auto /dev/sda1 /mnt/usb
(Of course you need CAP_SYS_ADMIN
)
So, next times, be aware of mount without options impacting security like nodev
;)