- How to use
- How to disable
I can’t tell if OverlayFS is an actual filesystem I need to create on
the disk images with mkfs -t xxx /path/to/raw/disk/image, or is a
special mounting method and the raw disk images are actually using
something like ext4, but they are mounted in a special way with mount
-t OverlayFS?
One does not need to run any mkfs command for overlayFS, it is just a way of mounting.
Once mounted I believe that I should still be able to see my already
existing files and any files I now create will actually be stored
inside the filesystem1.img file that I could possibly move to another
system?
Yes, for a more detailed explanation of how OverlayFS works, you may wish to refer to «Docker and OverlayFS in practice».
When I run the live image (Ubuntu 18.04), it shows the root filesystem being an overlay with the squashfs image (/cdrom/casper/filesystem.squashfs
, containing the main data) as lower layer, and /cow/upper
as upper layer. But /cow
is not visible anymore as it is hidden by the overlay mounted on root.
Where (on what device) does the upper layer live? Is it accessible somewhere or is it a memory-only device?
asked Dec 21, 2018 at 12:33
9 silver badges13 bronze badges
COW stands for copy-on-write, In the case of live media it refers to the changes that are made to the live environment. It is accessible if you boot live iso in persistence mode, in that case it is written to the drive, folder or casper-rw container file you specify. But if persistence mode is not enabled it is just a memory only device.
There are many articles available on askubuntu regarding persistence.
answered Dec 21, 2018 at 13:51
root@rasp:/home/pi # mount
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
proc on /proc type proc (rw,relatime)
udev on /dev type devtmpfs (rw,nosuid,relatime,size=243284k,nr_inodes=60821,mode=755)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000)
tmpfs on /run type tmpfs (rw,nosuid,noexec,relatime,size=76332k,mode=755)
overlay on / type overlay (rw,noatime,lowerdir=/lower,upperdir=/upper/data,workdir=/upper/work)
securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
cgroup2 on /sys/fs/cgroup/unified type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
none on /sys/fs/bpf type bpf (rw,nosuid,nodev,noexec,relatime,mode=700)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=32,pgrp=1,timeout=0,minproto=5,maxproto=5,direct)
debugfs on /sys/kernel/debug type debugfs (rw,relatime)
mqueue on /dev/mqueue type mqueue (rw,relatime)
configfs on /sys/kernel/config type configfs (rw,relatime)
/dev/mmcblk0p1 on /boot type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,errors=remount-ro)
tmpfs on /run/user/1000 type tmpfs (rw,nosuid,nodev,relatime,size=76328k,mode=700,uid=1000,gid=1000)
binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,relatime)
tracefs on /sys/kernel/debug/tracing type tracefs (rw,relatime)
можно видеть, что / (root) монтирован в overlay, где в скобочках видно lowerdir=/lower,upperdir=/upper/data,workdir=/upper/work
но если сделать так:
root@rasp:/ # ls -la /
total 36
drwxr-xr-x 1 root root 160 Jan 1 1970 .
drwxr-xr-x 1 root root 160 Jan 1 1970 ..
lrwxrwxrwx 1 root root 7 Jan 11 18:50 bin -> usr/bin
drwxr-xr-x 4 root root 4096 Jan 1 1970 boot
drwxr-xr-x 17 root root 3720 Jul 6 12:49 dev
drwxr-xr-x 1 root root 120 Jul 6 16:15 etc
drwxr-xr-x 1 root root 60 Jan 11 18:52 home
lrwxrwxrwx 1 root root 7 Jan 11 18:50 lib -> usr/lib
drwx------ 2 root root 16384 Jan 11 19:08 lost+found
drwxr-xr-x 2 root root 4096 Jan 11 18:50 media
drwxr-xr-x 2 root root 4096 Jan 11 18:50 mnt
drwxr-xr-x 3 root root 4096 Jan 11 18:52 opt
dr-xr-xr-x 194 root root 0 Jan 1 1970 proc
drwx------ 1 root root 120 Jul 6 16:19 root
drwxr-xr-x 20 root root 700 Jul 6 17:38 run
lrwxrwxrwx 1 root root 8 Jan 11 18:50 sbin -> usr/sbin
drwxr-xr-x 2 root root 4096 Jan 11 18:50 srv
dr-xr-xr-x 12 root root 0 Jan 1 1970 sys
drwxrwxrwt 1 root root 340 Jul 6 17:17 tmp
drwxr-xr-x 1 root root 100 Jan 11 18:50 usr
drwxr-xr-x 1 root root 140 Feb 12 21:19 var
то папки /lower или /upper тут нет. А где они?! А как это?
Псевдо-файловая система OverlayFS была впервые включена в релиз 3.18 ядра Linux: она позволяет объединять два дерева каталогов или файловых систем (“верхнее” и “нижнее”) совершенно прозрачно для пользователя, который может обращаться к файлам и каталогам на “объединенном” уровне точно так же, как и на стандартной файловой системе.
В этом руководстве мы изучим основные концепции OverlayFS и увидим демонстрацию ее использования.
В этом руководстве вы узнаете:
- Основные концепции OverlayFS
- Как объединить две файловые системы с помощью OverlayFS
- Введение
- Использование OverlayFS
- Заключение
- Как работает уязвимость
- Способ эксплуатации уязвимости
- Обнаружение CVE-2023-0386
- Вывод
- Note
- Examples
- Nesting OverlayFS
- Mounting OverlayFS in fstab
- How to disable
- Use overlayroot-chroot
- Disable by overlayroot. conf
- Example
- Disable OverlayFS when booting
- Remount
- Access Casper-rw file
- How to use
Введение
Все мы должны быть знакомы со стандартным поведением ядра Linux при монтировании файловой системы: файлы и каталоги, существующие в каталоге, используемом в качестве точки монтирования, маскируются и становятся недоступными для пользователя, в то время как файлы, существующие в смонтированной файловой системе, отображаются.
Доступ к исходным файлам можно получить только после размонтирования файловой системы.
Это также происходит тогда, когда мы монтируем несколько файловых систем в одном каталоге.
Когда используется псевдо-файловая система OverlayFS, вместо этого файлы, существующие на разных слоях, объединяются, и результирующая файловая система может быть смонтирована самостоятельно.
OverlayFS обычно используется в системах, работающих на встроенных устройствах, таких как OpenWRT, где полезно сохранять базовый набор конфигураций и в то же время позволять пользователю выполнять модификации.
OverlayFS также лежит в основе драйверов хранения “overlay” и “overlay2” Docker.
Что происходит при удалении файла или каталога?
Если удаляемый файл принадлежит верхнему слою, то он удаляется на месте; если же он принадлежит нижнему слою, то удаление имитируется с помощью файла whiteout (или непрозрачного каталога – каталога с расширенным атрибутом trusted.overlay.opaque), который создается в слое с возможностью записи и заслоняет исходный элемент.
OverlayFS является основой драйверов Docker overlay и overlay2.
В такой реализации нижний, доступный только для чтения, слой представлен образами; верхний, доступный для записи, представлен контейнерами на их основе.
Образы неизменяемы: все изменения происходят внутри контейнеров и теряются при их удалении (именно поэтому для сохранения данных используются тома).
Использование OverlayFS
Давайте посмотрим, как использовать OverlayFS.
Для данного примера я предположу, что мы хотим объединить две файловые системы: нижнюю, существующую на разделе /dev/sda1, и ту, которая будет использоваться в режиме чтения-записи, на разделе /dev/sda2.
Первое, что мы хотим сделать, это создать каталоги, которые мы будем использовать в качестве точек монтирования:
$ sudo mkdir /lower /overlay
Теперь смонтируем файловую систему /dev/sda1 в каталоге /lower в режиме только для чтения:
$ sudo mount -o ro /dev/sda1 /lower
Команда ls показывает, что файловая система содержит только один файл:
$ ls -l /lower total 20 -rw-r--r--. 1 root root 23 Sep 1 10:43 file1.txt drwx------. 2 root root 16384 Sep 1 10:40 lost+foun
Файлы содержат всего одну строку:
$ cat /lower/file1.txt this is the first line
Теперь давайте продолжим.
В качестве следующего шага мы смонтируем файловую систему /dev/sda2 в каталог /overlay:
$ sudo mount /dev/sda2 /overlay
Когда файловая система смонтирована, мы создаем на ней две директории: upper и work.
В первой будут храниться файлы, являющиеся частью верхнего слоя, вторая будет использоваться для подготовки файлов при переходе с одного слоя на другой: она должна быть пустой и находиться в той же файловой системе, что и верхняя:
$ sudo mkdir /overlay/{upper,work}
Теперь мы можем “собрать” и смонтировать оверлей.
Для выполнения этой задачи мы используем следующую команду:
$ sudo mount overlay -t overlay -o lowerdir=/lower,upperdir=/overlay/upper,workdir=/overlay/work /media
Мы вызвали mount, передав “overlay” в качестве аргумента опции -t (сокращение от –types), тем самым указав тип файловой системы, которую мы хотим смонтировать (в данном случае псевдо-файловую систему), затем мы использовали флаг -o для перечисления опций монтирования: в данном случае “lowerdir”, “upperdir” и “workdir”, чтобы указать: каталог, в который монтируется файловая система только для чтения, каталог, содержащий файлы верхнего, записываемого слоя, и расположение “рабочего” каталога, соответственно. Наконец, мы указали точку монтирования для “объединенной” файловой системы: /media, в данном случае.
С помощью команды mount мы можем просмотреть сводную информацию о настройке оверлея:
$ mount | grep -i overlay overlay on /media type overlay (rw,relatime,seclabel,lowerdir=/lower,upperdir=/overlay/upper,workdir=/overlay/work)
Если мы перечислим файлы в каталоге /media, то увидим, что существует только файл file1.txt, который, как мы знаем, принадлежит нижнему уровню:
$ ls -l /media total 20 -rw-r--r--. 1 root root 23 Sep 1 10:43 file1.txt drwx------. 2 root root 16384 Sep 1 10:40 lost+found
Теперь давайте попробуем добавить строку в файл и посмотрим, что произойдет:
$ echo "this is the second line" | sudo tee -a /media/file1.txt
Если мы проверим содержимое файла, то увидим, что строка была добавлена успешно:
$ cat /media/file1.txt this is the first line this is the second line
Однако оригинальный файл file1.txt не был изменен:
$ cat /lower/file1.txt this is the first line
IВместо этого в верхний слой был добавлен файл с тем же именем:
$ ls -l /overlay/upper -rw-r--r--. 1 root root 47 Sep 1 14:36 file1.txt
Теперь, если мы удалим файл /media/file1.txt, /overlay/upper/file1.txt станет таким файлом whiteout :
$ sudo rm /media/file1.txt $ ls -l /overlay/upper c---------. 2 root root 0, 0 Sep 1 14:45 file1.txt
Как указано в официальной документации, файл whiteout является символьным устройством (это отражено в выводе ls – см. выделенную ведущую “c”) с номером устройства 0/0.
Заключение
В этом руководстве мы поговорили о OverlayFS: мы узнали основные концепции ее использования, увидели, как она может быть использована для объединения двух файловых систем или деревьев каталогов, и каковы некоторые из возможных случаев ее использования.
Наконец, мы увидели, как на самом деле создать установку OverlayFS на Linux.

Я Алексей, исследователь‑аналитик киберугроз в компании R‑Vision. Сегодня я продолжу выявление вредоносных активностей в Linux-системах и рассмотрю новую критичную уязвимость, получившую идентификатор CVE-2023-0386. Уязвимость, обнаруженная в ядре Linux, затронула версии ядра до 6.2 и связана с файловой системой OverlayFS. Она опасна тем, что позволяет непривилегированному пользователю создавать исполняемые файлы с SUID-битом и с их помощью получать привилегии root
.
На просторах сети уже можно найти несколько доступных вариаций эксплуатации CVE-2023-0386 (PoC’ов), некоторые из них представлены под спойлером ниже:
Варианты эксплуатации
В этой статье я хочу разобрать с вами принципы работы данной узвимости и рассмотреть, каким образом мы можем обнаружить ее в системе.
Как работает уязвимость
Для понимая работы CVE-2023-0386, давайте посмотрим, как она была исправлена в ядре Linux с помощью недавно вышедшего патча:
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index 140f2742074d4..c14e90764e356 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -1011,6 +1011,10 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
if (err)
return err;
+ if (!kuid_has_mapping(current_user_ns(), ctx.stat.uid) ||
+ !kgid_has_mapping(current_user_ns(), ctx.stat.gid))
+ return -EOVERFLOW;
+
ctx.metacopy = ovl_need_meta_copy_up(dentry, ctx.stat.mode, flags);
if (parent) {
В нем мы видим дополнительное условие, добавленное в ovl_copy_up_on
— функцию из библиотеки ядра Linux.
Данная функция относится к файловой системе OverlayFS, позволяющей объеднять несколько файловых систем в единую иерархию, и используется для копирования файла или каталога из нижнего слоя (lower layer) в верхний слой (upper layer) OverlayFS. Эта операция дает возможность создать или обновить файлы и каталоги в верхней файловой системе, не затрагивая исходные файлы в нижней.
Но вернемся к условию, оно состоит из двух частей кода:
При этом если хотя бы одно из условий возвращает истину (true), то возвращается и значение -EOVERFLOW
(оно обычно используется для обозначения переполнения или некорректных значений), и тогда функция не будет выполнена.
Способ эксплуатации уязвимости
А теперь посмотрим какие шаги необходимо предпринять для эксплуатация уязвимости. Для этого нам понадобится:
unshare -Urm
-
В новом пространстве имен мы получаем возможность монтирования, для которого обычно требуются права
root.
Теперь можно смонтировать OverlayFS, запустив команду ниже. В ней для нижней директории (lowerdir
) будет использоваться созданная ранее FUSE с исполняемым файлом, а для верхней (upperdir
) любая директория, доступная для записи:
mount -t overlay overlay -o lowerdir=fuse_dir,upperdir=upperdir,workdir=workdir overlay_mount_point
-
Далее нужно «переместить» наш файл с SUID-битом из нижней директории в верхнюю. Для этого достаточно выполнить команду
touch
для файла в OverlayFS. Это не изменит сам файл, но изменит метку времени последнего доступа к файлу. Данного изменения будет достаточно для запуска процесса записи OverlayFS в верхнюю директорию. И поскольку в непропатченном ядре нет условия, описанного выше, файл будет записан в верхнюю директорию со всеми правами. Ну а дальше достаточно выйти из нашего пользовательского пространства и запустить полученный файл из «верхней» директории.
Для более наглядного понимая процесса эксплуатации, представлю описанные мною шаги в виде схемы ниже:

Разобравшись с принципом работы уязвимости, давайте выясним как можно мониторить подобную активность.
Обнаружение CVE-2023-0386
Повышение привилегий через исполняемые файлы с SUID-битом до сих пор является одним из наиболее популярных способов у злоумышленников, согласно отчету компании red-canary. В данной уязвимости также применяется эта техника, поэтому детектирование повышения привилегий через SUID-бит в данном случае будет также актуально. Но CVE-2023-0386 позволяет создать любой файл с SUID-битом, поэтому мы будем рассматривать именно обнаружение процесса эксплуатации самой уязвимости.
Для этого нам будет достаточно мониторить системный вызов mount. Так как он вызывается только привилегированным пользователем, то вызов с UID
не равным 0 может свидетельствовать о вызове из пространства имен (namespace).
Также mount хранит информацию о типе вызываемой файловой системы. Ниже показано, как данный системный вызов будет выглядеть в ядре:
mount("overlay", "/home/sea-admin/cveOver/overlay_mount_point", "overlay", 0, "lowerdir=hello_mount_point,upper"...) = 0
А для мониторинга в реальном времени посмотрим, как mount представлен в логе auditd
. С этой целью добавим правило, которое позволит отследить нужный нам системный вызов:
-a always,exit -F arch=b64 -S mount -F key=mount
И увидим, как mount()
выглядит в auditd
:
type=SYSCALL msg=audit(1685308769.215:832): arch=c000003e syscall=165 success=yes exit=0 a0=5615b38dbb70 a1=5615b286c7d4 a2=5615b38dbbb0 a3=6 items=5 ppid=73263 pid=73264 auid=1000 uid=1001 gid=1001 euid=0 suid=0 fsuid=0 egid=1001 sgid=1001 fsgid=1001 tty=pts1 ses=1 comm="fusermount" exe="/usr/bin/fusermount3" subj=unconfined key="mount" ARCH=x86_64 SYSCALL=mount AUID="sea-admin" UID="sea-admin" GID="sea-admin" EUID="sea-admin" SUID="sea-admin" FSUID="sea-admin" EGID="sea-admin" SGID="sea-admin" FSGID="sea-admin"
Но как можно заметить, в этом событии мы не обнаружили значений аргументов a0-a2, а только ссылки на их адресное пространство. Так как данные аргументы хранят информацию о типе файловой системы и точках монтирования, они также важны для детектирования.
Поэтому мы попробуем получить их с помощью eBPF, а для этого напишем следующий С-код:
BPF_PERF_OUTPUT(args);
#include <linux/ptrace.h>
// структура данных для передачи в пользовательское пространство
struct args {
char task[TASK_COMM_LEN];
u32 m_uid;
char m_source[32];
char m_target[32];
char m_filesystem[32];
char m_data[64];
long m_flags;
};
// основная функция для перехвата системных вызовов mount()
int syscall__mount(struct pt_regs *ctx, const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data){
struct args arg_data = {};
//вызывающая команда
bpf_get_current_comm(&arg_data.task, sizeof(&arg_data.task));
//uid пользователя
arg_data.m_uid = bpf_get_current_uid_gid();
//аргументы системного вызова
bpf_probe_read(&arg_data.m_source, sizeof(arg_data.m_source), &*source);
bpf_probe_read(&arg_data.m_target, sizeof(arg_data.m_target), &*target);
bpf_probe_read(&arg_data.m_filesystem, sizeof(arg_data.m_filesystem), &*filesystemtype);
bpf_probe_read(&arg_data.m_flags, sizeof(arg_data.m_flags), &mountflags);
bpf_probe_read(&arg_data.m_data, sizeof(arg_data.m_data), &*data);
args.perf_submit(ctx, &arg_data, sizeof(arg_data));
return 0;
}
Данный код мониторит все системные вызовы mount()
и передает их аргументы в пользовательское пространство через perf ring buffer. Для загрузки в пользовательское пространство данного BPF и вывода результата воспользуемся Python «оберткой», пример которой представлен ниже под спойлером:
Пример обертки
from bcc import BPF
# Читаем ebpf код из файла
with open("bpf.c") as file:
bpf_txt = file.read()
def handle_event(cpu, data, size):
output = bpf_ctx["args"].event(data)
print("{:15} {:<5} {:<10} {:<15} {:<10} {:<10} {:<30}".format(output.task.decode("utf-8") , output.m_uid,
output.m_source.decode("utf-8"), output.m_target.decode("utf-8"), output.m_filesystem.decode("utf-8"), output.m_flags, output.m_data.decode("utf-8")))
bpf_ctx = BPF(text=bpf_txt)
syscall_fnname = bpf_ctx.get_syscall_fnname("mount")
# Присоединяем наш ebpf к системному вызову bpf
bpf_ctx.attach_kprobe(event=syscall_fnname, fn_name="syscall__mount")
bpf_ctx["args"].open_perf_buffer(handle_event)
# Настраиваем вывод в консоль
print("{:<15} {:<5} {:<10} {:<15} {:<10} {:<10} {:<30}".format('exe_task',"uid",
'source', 'target', 'fs type','flags', 'data'))
while 1:
try:
bpf_ctx.perf_buffer_poll()
except KeyboardInterrupt:
print()
exit()
После загрузки нашего BPF и эксплуатации уязвимости, нам станет доступен следующий вывод:
exe_task uid source target fs type flags data
fuse 1000 /dev/fuse ./ovlcap/lower fuse 6 fd=3,rootmode=40000,user_id=1000,group_id=1000
fusermo 1000 /dev/fuse . fuse 6 fd=4,rootmode=40000,user_id=1000,group_id=1000
exp 1000 overlay ./ovlcap/merge overlay 0 lowerdir=./ovlcap/lower,upperdir=./ovlcap/upper,workdir=./ovlcap
И здесь мы увидим, что изначально была создана файловая система fuse
из-под пользователя с UID 1000 с точкой монтирования в ./ovlcap/lower
.
В то же время в конце вывода показано создание файловой системы Overlay из-под того же пользователя в «нижний уровень», которой передается та же директория ./ovlcap/lower
. Логическое правило будет выглядеть так:
event1.uid = event2.uid != 0 &
event1.fs_type = fuse &
event2.fs_type = overlay &
event1.target = event2.data.lowerdir
Данная логика полностью соответствует принципу работы уязвимости и маловероятно встретить ее в легитимной работе приложений. Реализовать подобное правило можно в SIEM-системе, передав ей данные логи, или непосредственно в самом модуле eBPF.
Вывод
Уязвимости ядра Linux могут создавать большие возможности для атакующего, как например уязвимость OverlayFS (CVE-2023-0386), которая сегодня была рассмотрена этой в статье. Как мы могли заметить, стандартных механизмов auditd
явно недостаточно, чтобы обеспечить корректное детектирование эксплуатации данной уязвимости. Поэтому мною было предложено решение, основанное на механизме eBPF. Оно позволило увидеть все аргументы системного вызова mount()
и сформировать корреляционное правило.
Чтобы защититься от подобных уязвимостей, помимо обнаружения их эксплуатации, я также рекомендую вам регулярно обновлять свои информационные системы.
Спасибо за внимание! Если у вас остались вопросы — пишите в комментариях 🙂
Note
noauto,x-systemd.automount
This will have effect, that overlay filesystem will be simply not mounted at boot time (noauto option), avoiding possible failure if previous mounts are not ready. On first access to overlay directory, the filesystem will be mounted (x-systemd.automount option). This approach has two weaknesses:
- If needed lower/upper directories are not ready this mount will fail.
- Mount will succeed even if lower/upper directories are not populated (ISO is not mounted f.e.)
We can avoid later, by adding x-systemd.require to the options list.
Examples
Creating an overlay mount can be done purely with directories if desired as demonstrated here:
cd /tmp
mkdir lower upper workdir overlay
sudo mount -t overlay -o \
lowerdir=/tmp/lower,\
upperdir=/tmp/upper,\
workdir=/tmp/workdir \
none /tmp/overlay
cd /tmp
# Create the necessary directories.
mkdir lower upper overlay
# Lets create a fake block device to hold our "lower" filesystem
dd if=/dev/zero of=lower-fs.img bs=4096 count=102400
dd if=/dev/zero of=upper-fs.img bs=4096 count=102400
# Give this block device an ext4 filesystem.
mkfs -t ext4 lower-fs.img
mkfs -t ext4 upper-fs.img
# Mount the filesystem we just created and give it a file
sudo mount lower-fs.img /tmp/lower
sudo chown $USER:$USER /tmp/lower
echo "hello world" >> /tmp/lower/lower-file.txt
# Remount the lower filesystem as read only just for giggles
sudo mount -o remount,ro lower-fs.img /tmp/lower
# Mount the upper filesystem
sudo mount upper-fs.img /tmp/upper
sudo chown $USER:$USER /tmp/upper
# Create the workdir in the upper filesystem and the
# directory in the upper filesystem that will act as the upper
# directory (they both have to be in the same filesystem)
mkdir /tmp/upper/upper
mkdir /tmp/upper/workdir
# Create our overlayfs mount
sudo mount -t overlay -o \
lowerdir=/tmp/lower,\
upperdir=/tmp/upper/upper,\
workdir=/tmp/upper/workdir \
none /tmp/overlay
The examples above are taken from my blog post on using overlayfs.
Nesting OverlayFS
You can nest overlayFS. For example, you can nest the example above as the lowerdir to another overlayFS system by running:
mkdir -p /tmp/upperdir2/upper /tmp/upperdir2/workdir /tmp/overlay2
sudo mount -t overlay -o \
lowerdir=/tmp/overlay,\
upperdir=/tmp/upperdir2/upper,\
workdir=/tmp/upperdir2/workdir \
none /tmp/overlay2
When Ubuntu gets kernel 4.0+, we should be able to combine multiple lower directories in a single command by using the colon character as a separator like so:
sudo mount -t overlay -o \
lowerdir=/tmp/lower:/tmp/lowest,\
upperdir=/tmp/upper,\
workdir=/tmp/workdir \
none /tmp/overlay
In this case, you do not have two workdirs but one, and you keep the same merged path of /tmp/overlay
. The lower directories will be stacked from right to left. You can also omit upperdir=
entirely, which results in a readonly mount.
Mounting OverlayFS in fstab
Above answers have explained how to mount overlay filesystem from cmd line and/or script. It is also possible to mount OverlayFS from fstab.
Mounting directory which is not present, will fail, while mounting not yet «populated» directory will not fail, since OverlayFS has no way to know, if directory is ready.
When mounting filesystems from fstab, that is particularly a problem, since all mounting is done in parallel, thus we can not ensure that everything is prepared for OverlayFS.
However, if Linux distribution uses systemd, than mounting of filesystems is handled by it. Systemd reads fstab file, and creates mount units on the fly. After that all mounting is processed by systemd. Systemd unit files have options: require, after, before, which can be used to control the order and dependency of mounts defined in fstab, thus ensuring that mounting of OverlayFS will not fail (at least not, because of wrong order).
To set order/dependency of mounts in fstab file, we will declare systemd option «require» using syntax: x-systemd.require. Argument for this option is mount point of the mount which should be successfully mounted before given mount (defined in fstab).
How to disable
When you change some file under OverlayFS, and after the reboot, the file will keep the same.
But sometimes you do want to change the original file, how to disable this feature?
We have these methods:
- Remount the disk with rw, and change the file under lowerdir
- Use overlayroot-chroot tool provided by the package
- Disable OverlayFS when booting
- Disable by overlayroot.conf
Use overlayroot-chroot
If we want to install some package and keep the package after reboot, we can’t use the first method, since the package may change many files under different directories.
We still have a simple way, you run overlayroot-chroot with root, make changes, and the changes will be saved after reboot.
$ sudo overlayroot-chroot
The change may not take effect immediately after exit the command, you can mount again like this:
$ sudo mount -o remount /
Disable by overlayroot. conf
We can disable OverlayFS during the boot time, but if we want to keep it disabled after several reboots, we have a simple way.
You can change the overlayroot.conf config file using the remount method, and comment all the lines, and then reboot again.
If we want to enable, we can remount and un-comment the config lines, and after reboot, the OverlayFS will be enabled agian.
$ cat /media/root-ro/etc/overlayroot.conf
# overlayroot="tmpfs:swap=1,recurse=0"
Example
To show an example (and syntax of fstab entries), we will show case, where we will overlay directory on which iso image is mounted, while this particular image file will be stored on separate hdd, which will have to be mounted before we access image file. Thus forming required ordered of events:
mount hdd -> mount iso image -> mount OverlayFS
For given case fstab entries would look like:
# 1. mount hdd partition
# 2. mount iso image from hdd partition, but only if/after hdd is mounted
# 3. overlay iso image, but only if/after iso image is mounted
#
/dev/hdb1 /mnt/hdd ext4 errors=remount-ro 0 2
/mnt/hdd/linux.iso /mnt/iso auto x-systemd.requires=/mnt/hdd,ro 0 0
overlay /mnt/merged overlay x-systemd.requires=/mnt/iso,lowerdir=/mnt/iso,upperdir=/overlay/lower,workdir=/overlay/working 0 0
If any mounts in chain fail, dependent one(s) will not be executed.
Disable OverlayFS when booting
The overlayroot-chroot method may solve 90% of the problem, but it do has some limitation.
The overlayroot-chroot just like chroot into the lower filesystem, and remount with writable.
If you have some scripts-say postinstall in some package, checks the chroot mode, it may refuse to execute under this case.
To fix this problem, we can disable OverlayFS during the booting phase.
We can edit the boot command line, append overlayroot=disabled and boot again.
Under this case, the OverlayFS will be disabled completely.
Remount
# remount with read-write
$ sudo mount -o remount,rw /dev/sda3
# say we want to change overlayroot.conf
# note: we must change under the file under the lowerdir: /media/root-ro
$ sudo vim /media/root-ro/etc/overlayroot.conf
# remount with read-only
$ sudo mount -o remount,ro /dev/sda3
Access Casper-rw file
You can mount casper-rw file and access contents within using:
sudo mkdir /media/casper
sudo mount -o loop casper-rw /media/casper/
answered Dec 1, 2021 at 3:15
10 gold badges63 silver badges103 bronze badges
How to use
We have a device running Ubuntu and will be powered off directly without shutdown gracefully.
In order to keep the file system from damage, we use the OverlayFS provided in Linux kernel since 3.18.
# first install overlayroot package
$ sudo apt-get install overlayroot
# second, change the config file /etc/overlayroot.conf
# the simple config is as following
# we enable swap, and disable recurse overlay
$ cat /etc/overlayroot.conf
overlayroot="tmpfs:swap=1,recurse=0"
After rebooting, we should see something like this:
$ df -h
Filesystem Size Used Avail Use% Mounted on
udev 16G 8.0K 16G 1% /dev
tmpfs 3.1G 74M 3.1G 3% /run
/dev/sda3 96G 16G 76G 17% /media/root-ro
tmpfs-root 16G 60M 16G 1% /media/root-rw
overlayroot 16G 60M 16G 1% /
tmpfs 16G 24K 16G 1% /dev/shm
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 16G 0 16G 0% /sys/fs/cgroup
$ mount
[...]
configfs on /sys/kernel/config type configfs (rw,relatime)
overlayroot on /var/cache/apt/archives type overlay (rw,relatime,lowerdir=/media/root-ro,upperdir=/media/root-rw/overlay,workdir=/media/root-rw/overlay-workdir/_)
overlayroot on /opt/var/cache/apt/archives type overlay (rw,relatime,lowerdir=/media/root-ro,upperdir=/media/root-rw/overlay,workdir=/media/root-rw/overlay-workdir/_)
overlayroot on /var/lib/apt/lists type overlay (rw,relatime,lowerdir=/media/root-ro,upperdir=/media/root-rw/overlay,workdir=/media/root-rw/overlay-workdir/_)
overlayroot on /opt/var/lib/apt/lists type overlay (rw,relatime,lowerdir=/media/root-ro,upperdir=/media/root-rw/overlay,workdir=/media/root-rw/overlay-workdir/_)