License cleanup: add SPDX GPL-2.0 license identifier to files with no license
Many source files in the tree are missing licensing information, which
makes it harder for compliance tools to determine the correct license.
By default all files without license information are under the default
license of the kernel, which is GPL version 2.
Update the files which contain no license information with the 'GPL-2.0'
SPDX license identifier. The SPDX identifier is a legally binding
shorthand, which can be used instead of the full boiler plate text.
This patch is based on work done by Thomas Gleixner and Kate Stewart and
Philippe Ombredanne.
How this work was done:
Patches were generated and checked against linux-4.14-rc6 for a subset of
the use cases:
- file had no licensing information it it.
- file was a */uapi/* one with no licensing information in it,
- file was a */uapi/* one with existing licensing information,
Further patches will be generated in subsequent months to fix up cases
where non-standard license headers were used, and references to license
had to be inferred by heuristics based on keywords.
The analysis to determine which SPDX License Identifier to be applied to
a file was done in a spreadsheet of side by side results from of the
output of two independent scanners (ScanCode & Windriver) producing SPDX
tag:value files created by Philippe Ombredanne. Philippe prepared the
base worksheet, and did an initial spot review of a few 1000 files.
The 4.13 kernel was the starting point of the analysis with 60,537 files
assessed. Kate Stewart did a file by file comparison of the scanner
results in the spreadsheet to determine which SPDX license identifier(s)
to be applied to the file. She confirmed any determination that was not
immediately clear with lawyers working with the Linux Foundation.
Criteria used to select files for SPDX license identifier tagging was:
- Files considered eligible had to be source code files.
- Make and config files were included as candidates if they contained >5
lines of source
- File already had some variant of a license header in it (even if <5
lines).
All documentation files were explicitly excluded.
The following heuristics were used to determine which SPDX license
identifiers to apply.
- when both scanners couldn't find any license traces, file was
considered to have no license information in it, and the top level
COPYING file license applied.
For non */uapi/* files that summary was:
SPDX license identifier # files
---------------------------------------------------|-------
GPL-2.0 11139
and resulted in the first patch in this series.
If that file was a */uapi/* path one, it was "GPL-2.0 WITH
Linux-syscall-note" otherwise it was "GPL-2.0". Results of that was:
SPDX license identifier # files
---------------------------------------------------|-------
GPL-2.0 WITH Linux-syscall-note 930
and resulted in the second patch in this series.
- if a file had some form of licensing information in it, and was one
of the */uapi/* ones, it was denoted with the Linux-syscall-note if
any GPL family license was found in the file or had no licensing in
it (per prior point). Results summary:
SPDX license identifier # files
---------------------------------------------------|------
GPL-2.0 WITH Linux-syscall-note 270
GPL-2.0+ WITH Linux-syscall-note 169
((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) 21
((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 17
LGPL-2.1+ WITH Linux-syscall-note 15
GPL-1.0+ WITH Linux-syscall-note 14
((GPL-2.0+ WITH Linux-syscall-note) OR BSD-3-Clause) 5
LGPL-2.0+ WITH Linux-syscall-note 4
LGPL-2.1 WITH Linux-syscall-note 3
((GPL-2.0 WITH Linux-syscall-note) OR MIT) 3
((GPL-2.0 WITH Linux-syscall-note) AND MIT) 1
and that resulted in the third patch in this series.
- when the two scanners agreed on the detected license(s), that became
the concluded license(s).
- when there was disagreement between the two scanners (one detected a
license but the other didn't, or they both detected different
licenses) a manual inspection of the file occurred.
- In most cases a manual inspection of the information in the file
resulted in a clear resolution of the license that should apply (and
which scanner probably needed to revisit its heuristics).
- When it was not immediately clear, the license identifier was
confirmed with lawyers working with the Linux Foundation.
- If there was any question as to the appropriate license identifier,
the file was flagged for further research and to be revisited later
in time.
In total, over 70 hours of logged manual review was done on the
spreadsheet to determine the SPDX license identifiers to apply to the
source files by Kate, Philippe, Thomas and, in some cases, confirmation
by lawyers working with the Linux Foundation.
Kate also obtained a third independent scan of the 4.13 code base from
FOSSology, and compared selected files where the other two scanners
disagreed against that SPDX file, to see if there was new insights. The
Windriver scanner is based on an older version of FOSSology in part, so
they are related.
Thomas did random spot checks in about 500 files from the spreadsheets
for the uapi headers and agreed with SPDX license identifier in the
files he inspected. For the non-uapi files Thomas did random spot checks
in about 15000 files.
In initial set of patches against 4.14-rc6, 3 files were found to have
copy/paste license identifier errors, and have been fixed to reflect the
correct identifier.
Additionally Philippe spent 10 hours this week doing a detailed manual
inspection and review of the 12,461 patched files from the initial patch
version early this week with:
- a full scancode scan run, collecting the matched texts, detected
license ids and scores
- reviewing anything where there was a license detected (about 500+
files) to ensure that the applied SPDX license was correct
- reviewing anything where there was no detection but the patch license
was not GPL-2.0 WITH Linux-syscall-note to ensure that the applied
SPDX license was correct
This produced a worksheet with 20 files needing minor correction. This
worksheet was then exported into 3 different .csv files for the
different types of files to be modified.
These .csv files were then reviewed by Greg. Thomas wrote a script to
parse the csv files and add the proper SPDX tag to the file, in the
format that the file expected. This script was further refined by Greg
based on the output to detect more types of files automatically and to
distinguish between header and source .c files (which need different
comment types.) Finally Greg ran the script using the .csv files to
generate the patches.
Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org>
Reviewed-by: Philippe Ombredanne <pombredanne@nexb.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-11-01 15:07:57 +01:00
|
|
|
|
2011-11-23 19:26:23 -05:00
|
|
|
|
2011-12-06 12:21:54 -05:00
|
|
|
|
|
|
|
|
|
2014-10-31 22:56:04 -04:00
|
|
|
|
2015-01-10 19:01:08 -05:00
|
|
|
|
2011-12-06 12:21:54 -05:00
|
|
|
|
2026-01-12 16:47:10 +01:00
|
|
|
|
2026-10-02 16:14:27 +02:00
|
|
|
|
2026-10-02 15:52:45 +02:00
|
|
|
|
2025-01-29 17:58:01 +01:00
|
|
|
|
|
|
|
|
|
2011-12-06 12:21:54 -05:00
|
|
|
|
2014-10-31 22:56:04 -04:00
|
|
|
|
2011-12-06 13:32:36 -05:00
|
|
|
|
2024-12-15 21:17:06 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-07-26 21:08:32 -07:00
|
|
|
|
2016-08-08 14:37:37 -05:00
|
|
|
|
2025-09-12 13:52:41 +02:00
|
|
|
|
2025-02-21 14:13:00 +01:00
|
|
|
|
2014-02-27 14:40:10 -05:00
|
|
|
|
2025-01-29 17:57:59 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-04-27 10:26:02 +02:00
|
|
|
|
2023-10-25 16:02:00 +02:00
|
|
|
|
2016-09-28 00:27:17 -05:00
|
|
|
|
2024-06-24 11:49:46 -04:00
|
|
|
|
2025-11-10 16:08:22 +01:00
|
|
|
|
2016-10-28 01:22:25 -07:00
|
|
|
|
2011-11-23 19:26:23 -05:00
|
|
|
|
2011-11-24 22:53:09 -05:00
|
|
|
|
fs: don't let a migrating task hide its reference from do_umount()
propagate_mount_busy() uses mnt_get_count() via do_refcount_check() to
figure out whether a synchronous umount may proceed or not by summing
the per-CPU mnt_count counter under mount_lock.
The fastpath for mntget() and mntput() doesn't require that lock. A task
that already holds a reference and takes another one on a cpu the loop
has summed can get migrated and drops that reference again on another
cpu. The loop might not have reached that cpu yet. That ends up
undercounting. The original reference of the task is missed and umount()
ends up succeeding with the file still open. The mount is destroyed
later when the task mntput()s so it degrades to a lazy umount.
That's basically the umount(2) variant of commit 9ea0a46ca2c3 ("fix
mntput/mntput race") closed for the final mntput(). The same
cpu-migration caused a UAF.
Luckily this isn't a UAF. It's just a hidden reference pinning the
mount but it's wrong nonetheless.
Like the other race it's a narrow window but I can reproduce it reliably
with some patching. The debug patch below prints the sum the loop
computed next to an immediate re-sum of the same counters. It reports
who drops the last reference to that mount later:
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -34,6 +34,8 @@
#include <linux/mnt_idmapping.h>
#include <linux/pidfs.h>
#include <linux/nstree.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
#include "pnode.h"
#include "internal.h"
@@ -263,17 +265,48 @@
#endif
}
+static u32 mnt_get_count_delay_ms;
+static int mnt_get_count_debug_id;
+
+static int __init mnt_get_count_debug_init(void)
+{
+ debugfs_create_u32("mnt_get_count_delay_ms", 0600, NULL,
+ &mnt_get_count_delay_ms);
+ return 0;
+}
+late_initcall(mnt_get_count_debug_init);
+
/*
* vfsmount lock must be held for write
*/
int mnt_get_count(struct mount *mnt)
{
#ifdef CONFIG_SMP
- int count = 0;
+ static int seen[NR_CPUS];
+ bool slow = mnt_get_count_delay_ms &&
+ !(mnt->mnt.mnt_flags & MNT_UMOUNT);
+ int count = 0, again = 0;
int cpu;
for_each_possible_cpu(cpu) {
- count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_count;
+ seen[cpu] = per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_count;
+ count += seen[cpu];
+ if (slow)
+ mdelay(mnt_get_count_delay_ms);
+ }
+ if (slow) {
+ for_each_possible_cpu(cpu) {
+ int now;
+
+ now = per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_count;
+ again += now;
+ pr_err("mount %d: cpu%d read %d, now %d\n",
+ mnt->mnt_id, cpu, seen[cpu], now);
+ }
+ mnt_get_count_debug_id = mnt->mnt_id;
+ pr_err("mount %d: sum %d, re-sum %d, %ps\n",
+ mnt->mnt_id, count, again,
+ __builtin_return_address(0));
}
return count;
@@ -1350,6 +1383,9 @@
smp_mb();
mnt_add_count(mnt, -1);
count = mnt_get_count(mnt);
+ if (count == 0 && mnt->mnt_id == mnt_get_count_debug_id)
+ pr_err("mount %d: last put by %s (%d)\n", mnt->mnt_id,
+ current->comm, task_pid_nr(current));
if (count != 0) {
WARN_ON(count < 0);
rcu_read_unlock();
A task holds open a directory fd on a tmpfs. A synchronous rumount() of
the tmpfs sums up. Concurrently a task calls fchdir() on that fd on
CPU 0 and fchdir()s back to / on CPU 3. This will cause a path_get() and
a path_put() with a migration in between without mount_lock held.
Adding a delay per CPU makes the count loop miss the get in a cpu it
already visited but count the put in one it hasn't.
The reproducer, run as root with debugfs mounted:
/*
* gcc -static -o umount-torn umount-torn.c
*/
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <sched.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/wait.h>
#define KNOB "/sys/kernel/debug/mnt_get_count_delay_ms"
#define MNT "/mnt/x"
static int kmsg;
static void pin(int cpu)
{
cpu_set_t s;
CPU_ZERO(&s);
CPU_SET(cpu, &s);
sched_setaffinity(0, sizeof(s), &s);
}
static void knob(const char *v)
{
int fd = open(KNOB, O_WRONLY);
write(fd, v, strlen(v));
close(fd);
}
int main(void)
{
int last = sysconf(_SC_NPROCESSORS_ONLN) - 1;
int p[2], fd, ret;
pid_t pid;
char c;
kmsg = open("/dev/kmsg", O_WRONLY);
mkdir(MNT, 0755);
mount("none", MNT, "tmpfs", 0, NULL);
fd = open(MNT "/f", O_WRONLY | O_CREAT, 0644);
write(fd, "still here\n", 11);
close(fd);
pipe(p);
pid = fork();
if (pid == 0) {
int dirfd = open(MNT, O_RDONLY | O_DIRECTORY);
int rootfd = open("/", O_RDONLY | O_DIRECTORY);
struct stat st;
char buf[16];
/* one get/put pair while the umount is summing */
usleep(150000);
pin(0);
fchdir(dirfd); /* mntget() */
dprintf(kmsg, "holder %d: get on cpu %d\n", getpid(),
sched_getcpu());
pin(last);
fchdir(rootfd); /* mntput() */
dprintf(kmsg, "holder %d: put on cpu %d\n", getpid(),
sched_getcpu());
/* the umount has returned, is the fd still good? */
read(p[0], &c, 1);
fd = openat(dirfd, "f", O_RDONLY);
ret = read(fd, buf, sizeof(buf));
dprintf(kmsg, "holder %d: fstat %d openat %d read %d\n",
getpid(), fstat(dirfd, &st), fd, ret);
_exit(0);
}
pin(1);
knob("100");
ret = umount2(MNT, 0);
knob("0");
if (ret)
dprintf(kmsg, "umount: %s\n", strerror(errno));
else
dprintf(kmsg, "umount: 0\n");
write(p[1], "x", 1);
waitpid(pid, NULL, 0);
return 0;
}
The log shows the busy check summing 2 and when read right after it
reads 3. The loop read CPU 0 before the get landed there and CPU 3
after the put did. The umount succeeds while there's still someone
with an fd. The mount is then dropped when the fd goes:
[ 2.511944] holder 90: get on cpu 0
[ 2.512023] holder 90: put on cpu 3
[ 2.671388] mount 28: cpu0 read 1, now 2
[ 2.671398] mount 28: cpu1 read 2, now 2
[ 2.671401] mount 28: cpu2 read 0, now 0
[ 2.671404] mount 28: cpu3 read -1, now -1
[ 2.671407] mount 28: sum 2, re-sum 3, propagate_mount_busy
[ 2.671773] umount: 0
[ 2.672963] holder 90: fstat 0 openat 8 read 11
[ 2.673663] mount 28: last put by umount-torn (90)
Easy fix would be to order mntget() against the loop that sums up. But
that's a full barrier and a flag test in mntget() afaict. No bueno...
That would cost every path_get().
So learn from SRCU. Keep gets and puts in separate per-cpu counters and
make mnt_get_count() sum all puts first and all gets second with a full
barrier in between.
A put is always after its own get (hopefully...) independent of the cpu
the task is on. So a put the first pass counted must have its get
visible to the second pass. Ergo, we can't undercount.
This is the two pass sum srcu_readers_active_idx_check() does for
srcu_locks and srcu_unlocks. mntget() keeps a single
this_cpu_inc(). mntput() gains an smp_wmb() before its increment, a
compiler barrier on x86 and a store fence on the weakly ordered
architectures, since the two counters are two words and a put stored
after a get could otherwise become visible before it. The counters
are unsigned so the difference stays right after they wrap.
The count can still come out high when a get is counted whose put
the first pass did not see. We don't care. A task can only take a new
reference if:
(1) it holds one already
(2) through __legitimize_mnt() which the seqcount orders
against the write side
So a get in this window means someone has a reference and -EBUSY is
correct. The final mntput() is unchanged. Once ->mnt_ns is NULL every
put takes the slow path under mount_lock and so no put is in flight
while it counts. Here's an attempted proof for that crap:
(i) A put never becomes visible before its get. Within one task the
smp_wmb() in mntput_no_expire() orders every earlier store before the
increment of the puts.
Any task that migrated in between had its stores flushed by the
scheduler. When that reference is handed to another task that's
trivially true.
(ii) The double count in mnt_get_count() is ordered via smp_mb(). That
keeps every read of the puts counter before every read of the gets
counter.
(iii) We never undercount by (ii).
(iv) There are no spurious counts/differences. A get is counted only if
it happened and a put is left out only if it hasn't happened when
the counter was read. With (iii) this means it's equivalent to the
old count whenever nothing is taken or dropped during the loop.
(v) do_umount() holds a reference and mount_lock hence. New references
come from: (v.a) __legitimize_mnt() managed by the seqcount. Either
it's smp_mb() made the get visible to the loop or it takes the lock
and waits for the loop. By (iii) a mount with a additional
references is refused. By (iv) refusing the umount just means that
any additional reference existed, same as the old counter.
(vi) mntput_no_expire_slowpath() runs with ->mnt_ns already NULL. Hence,
every other put must take the slowpath as well and hangs on mount_lock.
The grace period in namespace_unlock() will make every fast path do
a put that still saw ->mnt_ns.
No put is in flight during the loop.
A get that is in flight comes from a task holding another reference.
That must be included by the count or from __legitimize_mnt() as in
(v).
Ergo, zero means the last reference and non-zero means a reference
is live.
(vii) may_umount() uses propagate_mount_busy() as well and
may_umount_tree() sums mnt_get_count() itself.
With this patch the race is dead:
[ 3.066786] mount 28: sum 3, re-sum 3, propagate_mount_busy
[ 3.105867] umount: Device or resource busy
[ 3.106047] holder 90: fstat 0 openat 8 read 11
Link: https://patch.msgid.link/20260923-work-mount-fixes-v1-7-f424cf8d3242@kernel.org
Fixes: b3e19d924b6e ("fs: scale mntget/mntput")
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-09-23 14:27:59 +02:00
|
|
|
|
|
|
|
|
|
2011-11-24 22:53:09 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-03-15 10:53:28 -04:00
|
|
|
|
2014-02-28 13:46:44 -05:00
|
|
|
|
2013-03-15 10:53:28 -04:00
|
|
|
|
namespace: rework connected mounts
UMOUNT_CONNECTED as implemented allows for the creation of reference
count cycles. Here's a simple example
mkdir /x; mkfifo /ready /go
unshare -m sh -c 'mount -t tmpfs tmpfs /x
truncate -s 8M /x/img; mkfs.ext4 -q /x/img
dev=$(losetup -f --show /x/img)
mkdir /x/mp; mount $dev /x/mp
echo $dev > /ready; read r < /go' &
read dev < /ready
rmdir /x
echo > /go
wait
losetup -d $dev
losetup -a
Take a directory /x on the host, create a new mount namespace, mount a
tmpfs on /x, use a file on that tmpfs as the backing file for a loop
device, mount that loop device on that tmpfs. Now rmdir /x on the host.
This will lazily unmount the mount on top of /x in the container with
UMOUNT_CONNECTED. Once the namespace exits nothing references the mount
anymore. Now the tmpfs is pinned by the backing file of the loop device
and the loop mount is owned by the tmpfs superblock.
Fun fact, such cycles can be formed by at least the following
subsystems and I have added reproducers for all of them:
(1) a loop mount P from an image on a tmpfs next to it, so that P's
death shows as the loop device giving up its backing file
(2) autofs with a FIFO on P as its pipe, zram with a device node on P as
its writeback device, both on a minix image since vfat has neither
(3) ecryptfs with its lower directory on P, under a passphrase token
added to the session keyring
(4) binfmt_misc in a new user namespace with an 'F' interpreter on P
(5) a fuse server that answers FUSE_INIT with passthrough on and
registers a file on P as a backing file
(6) zloop with its zone files in a directory on P
(7) a mass storage gadget on the dummy UDC with its LUN file on P,
mounted from the SCSI disk the gadget shows up as
(8) md with a RAID1 of one loop device and its bitmap file on P, which
skips while SET_BITMAP_FILE has no way to succeed
(9) rmdir of P's mountpoint from the parent, then the child exits, then
the device must be free and LOOP_CLR_FD must release the file
The underlying mechanism is UMOUNT_CONNECTED (MNT_LOCKED falls into the
same class). With UMOUNT_CONNECTED an unmounted mount stays attached to
its parent. This is used to protect revealing the underlying mount and
is a non-negotiable security mechanism. So now the parent owns that
mount and is put on the parent's final mntput(). That moves it to
mnt_stuck_children and ultimately it's cleaned up by cleanup_mnt().
The fact that ownership of the child mount gets transferred to the
parent turns every reference from a child's superblock back to one of
its ancestors into a cycle.
Don't keep the child attached at all. What the parent needs is that a
lookup at the child's mountpoint keeps finding some mount, not the child
itself and it's not a guarantee we have given really.
When an unmounted mount would have stayed attached to its unmounted
parent disconnect it like every other unmounted mount and leave a
marker behind.
A lookup on the parent that misses the mount hash and hits a marker
finds knullfs. Either a file or a directory. Nothing leads from a marker
to any other mount.
The marker is owned by the parent and dropped by the parent's final
mntput() or by __detach_mounts() when the mountpoint is deleted from
under it. It is allocated together with the mount.
With that every unmounted mount is a root and holds only its own
reference which namespace_unlock() drops. No unmounted mount owns
another one. A superblock that pins an ancestor can't form a cycle.
It has a visible change. Mounts left connected (rmdir etc.) used to stay
traversable through the parent for as long as something held the parent.
Now it is detached with the umount. It lives as long as something
references it but it isn't reachable through the parent anymore and ".."
inside it leads nowhere which is the same as for every other lazily
unmounted mount.
Link: https://gist.github.com/mvo5/63ef46482349f3b1c3957d463a0c9c6f
Link: https://patch.msgid.link/20261002-work-mount-cover-v1-2-232a8f52b43c@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-10-02 16:14:28 +02:00
|
|
|
|
|
|
|
|
|
2013-03-15 10:53:28 -04:00
|
|
|
|
|
|
|
|
|
namespace: rework connected mounts
UMOUNT_CONNECTED as implemented allows for the creation of reference
count cycles. Here's a simple example
mkdir /x; mkfifo /ready /go
unshare -m sh -c 'mount -t tmpfs tmpfs /x
truncate -s 8M /x/img; mkfs.ext4 -q /x/img
dev=$(losetup -f --show /x/img)
mkdir /x/mp; mount $dev /x/mp
echo $dev > /ready; read r < /go' &
read dev < /ready
rmdir /x
echo > /go
wait
losetup -d $dev
losetup -a
Take a directory /x on the host, create a new mount namespace, mount a
tmpfs on /x, use a file on that tmpfs as the backing file for a loop
device, mount that loop device on that tmpfs. Now rmdir /x on the host.
This will lazily unmount the mount on top of /x in the container with
UMOUNT_CONNECTED. Once the namespace exits nothing references the mount
anymore. Now the tmpfs is pinned by the backing file of the loop device
and the loop mount is owned by the tmpfs superblock.
Fun fact, such cycles can be formed by at least the following
subsystems and I have added reproducers for all of them:
(1) a loop mount P from an image on a tmpfs next to it, so that P's
death shows as the loop device giving up its backing file
(2) autofs with a FIFO on P as its pipe, zram with a device node on P as
its writeback device, both on a minix image since vfat has neither
(3) ecryptfs with its lower directory on P, under a passphrase token
added to the session keyring
(4) binfmt_misc in a new user namespace with an 'F' interpreter on P
(5) a fuse server that answers FUSE_INIT with passthrough on and
registers a file on P as a backing file
(6) zloop with its zone files in a directory on P
(7) a mass storage gadget on the dummy UDC with its LUN file on P,
mounted from the SCSI disk the gadget shows up as
(8) md with a RAID1 of one loop device and its bitmap file on P, which
skips while SET_BITMAP_FILE has no way to succeed
(9) rmdir of P's mountpoint from the parent, then the child exits, then
the device must be free and LOOP_CLR_FD must release the file
The underlying mechanism is UMOUNT_CONNECTED (MNT_LOCKED falls into the
same class). With UMOUNT_CONNECTED an unmounted mount stays attached to
its parent. This is used to protect revealing the underlying mount and
is a non-negotiable security mechanism. So now the parent owns that
mount and is put on the parent's final mntput(). That moves it to
mnt_stuck_children and ultimately it's cleaned up by cleanup_mnt().
The fact that ownership of the child mount gets transferred to the
parent turns every reference from a child's superblock back to one of
its ancestors into a cycle.
Don't keep the child attached at all. What the parent needs is that a
lookup at the child's mountpoint keeps finding some mount, not the child
itself and it's not a guarantee we have given really.
When an unmounted mount would have stayed attached to its unmounted
parent disconnect it like every other unmounted mount and leave a
marker behind.
A lookup on the parent that misses the mount hash and hits a marker
finds knullfs. Either a file or a directory. Nothing leads from a marker
to any other mount.
The marker is owned by the parent and dropped by the parent's final
mntput() or by __detach_mounts() when the mountpoint is deleted from
under it. It is allocated together with the mount.
With that every unmounted mount is a root and holds only its own
reference which namespace_unlock() drops. No unmounted mount owns
another one. A superblock that pins an ancestor can't form a cycle.
It has a visible change. Mounts left connected (rmdir etc.) used to stay
traversable through the parent for as long as something held the parent.
Now it is detached with the umount. It lives as long as something
references it but it isn't reachable through the parent anymore and ".."
inside it leads nowhere which is the same as for every other lazily
unmounted mount.
Link: https://gist.github.com/mvo5/63ef46482349f3b1c3957d463a0c9c6f
Link: https://patch.msgid.link/20261002-work-mount-cover-v1-2-232a8f52b43c@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-10-02 16:14:28 +02:00
|
|
|
|
|
|
|
|
|
2011-11-23 12:14:10 -05:00
|
|
|
|
2014-03-20 21:10:51 -04:00
|
|
|
|
2011-11-24 22:19:58 -05:00
|
|
|
|
2011-11-24 22:25:07 -05:00
|
|
|
|
2011-11-23 12:14:10 -05:00
|
|
|
|
2014-08-08 13:08:20 -04:00
|
|
|
|
2024-12-15 21:17:05 +01:00
|
|
|
|
2014-08-08 13:08:20 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-11-24 22:53:09 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-11-24 23:24:33 -05:00
|
|
|
|
|
|
|
|
|
preparations to taking MNT_WRITE_HOLD out of ->mnt_flags
We have an unpleasant wart in accessibility rules for struct mount. There
are per-superblock lists of mounts, used by sb_prepare_remount_readonly()
to check if any of those is currently claimed for write access and to
block further attempts to get write access on those until we are done.
As soon as it is attached to a filesystem, mount becomes reachable
via that list. Only sb_prepare_remount_readonly() traverses it and
it only accesses a few members of struct mount. Unfortunately,
->mnt_flags is one of those and it is modified - MNT_WRITE_HOLD set
and then cleared. It is done under mount_lock, so from the locking
rules POV everything's fine.
However, it has easily overlooked implications - once mount has been
attached to a filesystem, it has to be treated as globally visible.
In particular, initializing ->mnt_flags *must* be done either prior
to that point or under mount_lock. All other members are still
private at that point.
Life gets simpler if we move that bit (and that's *all* that can get
touched by access via this list) out of ->mnt_flags. It's not even
hard to do - currently the list is implemented as list_head one,
anchored in super_block->s_mounts and linked via mount->mnt_instance.
As the first step, switch it to hlist-like open-coded structure -
address of the first mount in the set is stored in ->s_mounts
and ->mnt_instance replaced with ->mnt_next_for_sb and ->mnt_pprev_for_sb -
the former either NULL or pointing to the next mount in set, the
latter - address of either ->s_mounts or ->mnt_next_for_sb in the
previous element of the set.
In the next commit we'll steal the LSB of ->mnt_pprev_for_sb as
replacement for MNT_WRITE_HOLD.
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2025-08-27 12:33:11 -04:00
|
|
|
|
|
|
|
|
|
2025-08-27 13:37:12 -04:00
|
|
|
|
|
|
|
|
|
2011-11-25 02:25:17 -05:00
|
|
|
|
2024-12-15 21:17:05 +01:00
|
|
|
|
2011-11-25 00:22:05 -05:00
|
|
|
|
|
|
|
|
|
2025-06-24 23:51:31 -04:00
|
|
|
|
|
|
|
|
|
2011-11-25 00:10:28 -05:00
|
|
|
|
2026-06-03 21:31:57 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-03-15 10:53:28 -04:00
|
|
|
|
2019-07-04 16:57:51 -04:00
|
|
|
|
|
|
|
|
|
namespace: rework connected mounts
UMOUNT_CONNECTED as implemented allows for the creation of reference
count cycles. Here's a simple example
mkdir /x; mkfifo /ready /go
unshare -m sh -c 'mount -t tmpfs tmpfs /x
truncate -s 8M /x/img; mkfs.ext4 -q /x/img
dev=$(losetup -f --show /x/img)
mkdir /x/mp; mount $dev /x/mp
echo $dev > /ready; read r < /go' &
read dev < /ready
rmdir /x
echo > /go
wait
losetup -d $dev
losetup -a
Take a directory /x on the host, create a new mount namespace, mount a
tmpfs on /x, use a file on that tmpfs as the backing file for a loop
device, mount that loop device on that tmpfs. Now rmdir /x on the host.
This will lazily unmount the mount on top of /x in the container with
UMOUNT_CONNECTED. Once the namespace exits nothing references the mount
anymore. Now the tmpfs is pinned by the backing file of the loop device
and the loop mount is owned by the tmpfs superblock.
Fun fact, such cycles can be formed by at least the following
subsystems and I have added reproducers for all of them:
(1) a loop mount P from an image on a tmpfs next to it, so that P's
death shows as the loop device giving up its backing file
(2) autofs with a FIFO on P as its pipe, zram with a device node on P as
its writeback device, both on a minix image since vfat has neither
(3) ecryptfs with its lower directory on P, under a passphrase token
added to the session keyring
(4) binfmt_misc in a new user namespace with an 'F' interpreter on P
(5) a fuse server that answers FUSE_INIT with passthrough on and
registers a file on P as a backing file
(6) zloop with its zone files in a directory on P
(7) a mass storage gadget on the dummy UDC with its LUN file on P,
mounted from the SCSI disk the gadget shows up as
(8) md with a RAID1 of one loop device and its bitmap file on P, which
skips while SET_BITMAP_FILE has no way to succeed
(9) rmdir of P's mountpoint from the parent, then the child exits, then
the device must be free and LOOP_CLR_FD must release the file
The underlying mechanism is UMOUNT_CONNECTED (MNT_LOCKED falls into the
same class). With UMOUNT_CONNECTED an unmounted mount stays attached to
its parent. This is used to protect revealing the underlying mount and
is a non-negotiable security mechanism. So now the parent owns that
mount and is put on the parent's final mntput(). That moves it to
mnt_stuck_children and ultimately it's cleaned up by cleanup_mnt().
The fact that ownership of the child mount gets transferred to the
parent turns every reference from a child's superblock back to one of
its ancestors into a cycle.
Don't keep the child attached at all. What the parent needs is that a
lookup at the child's mountpoint keeps finding some mount, not the child
itself and it's not a guarantee we have given really.
When an unmounted mount would have stayed attached to its unmounted
parent disconnect it like every other unmounted mount and leave a
marker behind.
A lookup on the parent that misses the mount hash and hits a marker
finds knullfs. Either a file or a directory. Nothing leads from a marker
to any other mount.
The marker is owned by the parent and dropped by the parent's final
mntput() or by __detach_mounts() when the mountpoint is deleted from
under it. It is allocated together with the mount.
With that every unmounted mount is a root and holds only its own
reference which namespace_unlock() drops. No unmounted mount owns
another one. A superblock that pins an ancestor can't form a cycle.
It has a visible change. Mounts left connected (rmdir etc.) used to stay
traversable through the parent for as long as something held the parent.
Now it is detached with the umount. It lives as long as something
references it but it isn't reachable through the parent anymore and ".."
inside it leads nowhere which is the same as for every other lazily
unmounted mount.
Link: https://gist.github.com/mvo5/63ef46482349f3b1c3957d463a0c9c6f
Link: https://patch.msgid.link/20261002-work-mount-cover-v1-2-232a8f52b43c@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-10-02 16:14:28 +02:00
|
|
|
|
2019-07-04 16:57:51 -04:00
|
|
|
|
2011-11-25 02:35:16 -05:00
|
|
|
|
2017-02-01 09:21:58 +01:00
|
|
|
|
2011-11-25 02:35:16 -05:00
|
|
|
|
2025-01-29 17:58:01 +01:00
|
|
|
|
|
|
|
|
|
2011-11-25 02:35:16 -05:00
|
|
|
|
2025-06-21 18:06:19 -04:00
|
|
|
|
2023-10-25 16:01:59 +02:00
|
|
|
|
|
|
|
|
|
2011-11-25 00:50:41 -05:00
|
|
|
|
2011-11-25 00:57:42 -05:00
|
|
|
|
2014-08-07 06:23:41 -04:00
|
|
|
|
namespace: rework connected mounts
UMOUNT_CONNECTED as implemented allows for the creation of reference
count cycles. Here's a simple example
mkdir /x; mkfifo /ready /go
unshare -m sh -c 'mount -t tmpfs tmpfs /x
truncate -s 8M /x/img; mkfs.ext4 -q /x/img
dev=$(losetup -f --show /x/img)
mkdir /x/mp; mount $dev /x/mp
echo $dev > /ready; read r < /go' &
read dev < /ready
rmdir /x
echo > /go
wait
losetup -d $dev
losetup -a
Take a directory /x on the host, create a new mount namespace, mount a
tmpfs on /x, use a file on that tmpfs as the backing file for a loop
device, mount that loop device on that tmpfs. Now rmdir /x on the host.
This will lazily unmount the mount on top of /x in the container with
UMOUNT_CONNECTED. Once the namespace exits nothing references the mount
anymore. Now the tmpfs is pinned by the backing file of the loop device
and the loop mount is owned by the tmpfs superblock.
Fun fact, such cycles can be formed by at least the following
subsystems and I have added reproducers for all of them:
(1) a loop mount P from an image on a tmpfs next to it, so that P's
death shows as the loop device giving up its backing file
(2) autofs with a FIFO on P as its pipe, zram with a device node on P as
its writeback device, both on a minix image since vfat has neither
(3) ecryptfs with its lower directory on P, under a passphrase token
added to the session keyring
(4) binfmt_misc in a new user namespace with an 'F' interpreter on P
(5) a fuse server that answers FUSE_INIT with passthrough on and
registers a file on P as a backing file
(6) zloop with its zone files in a directory on P
(7) a mass storage gadget on the dummy UDC with its LUN file on P,
mounted from the SCSI disk the gadget shows up as
(8) md with a RAID1 of one loop device and its bitmap file on P, which
skips while SET_BITMAP_FILE has no way to succeed
(9) rmdir of P's mountpoint from the parent, then the child exits, then
the device must be free and LOOP_CLR_FD must release the file
The underlying mechanism is UMOUNT_CONNECTED (MNT_LOCKED falls into the
same class). With UMOUNT_CONNECTED an unmounted mount stays attached to
its parent. This is used to protect revealing the underlying mount and
is a non-negotiable security mechanism. So now the parent owns that
mount and is put on the parent's final mntput(). That moves it to
mnt_stuck_children and ultimately it's cleaned up by cleanup_mnt().
The fact that ownership of the child mount gets transferred to the
parent turns every reference from a child's superblock back to one of
its ancestors into a cycle.
Don't keep the child attached at all. What the parent needs is that a
lookup at the child's mountpoint keeps finding some mount, not the child
itself and it's not a guarantee we have given really.
When an unmounted mount would have stayed attached to its unmounted
parent disconnect it like every other unmounted mount and leave a
marker behind.
A lookup on the parent that misses the mount hash and hits a marker
finds knullfs. Either a file or a directory. Nothing leads from a marker
to any other mount.
The marker is owned by the parent and dropped by the parent's final
mntput() or by __detach_mounts() when the mountpoint is deleted from
under it. It is allocated together with the mount.
With that every unmounted mount is a root and holds only its own
reference which namespace_unlock() drops. No unmounted mount owns
another one. A superblock that pins an ancestor can't form a cycle.
It has a visible change. Mounts left connected (rmdir etc.) used to stay
traversable through the parent for as long as something held the parent.
Now it is detached with the umount. It lives as long as something
references it but it isn't reachable through the parent anymore and ".."
inside it leads nowhere which is the same as for every other lazily
unmounted mount.
Link: https://gist.github.com/mvo5/63ef46482349f3b1c3957d463a0c9c6f
Link: https://patch.msgid.link/20261002-work-mount-cover-v1-2-232a8f52b43c@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-10-02 16:14:28 +02:00
|
|
|
|
|
|
|
|
|
2026-04-27 10:26:02 +02:00
|
|
|
|
2025-06-20 22:46:55 -04:00
|
|
|
|
2016-10-28 01:22:25 -07:00
|
|
|
|
2011-11-23 12:14:10 -05:00
|
|
|
|
2025-06-21 18:06:19 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-06-09 00:59:08 -04:00
|
|
|
|
|
|
|
|
|
2011-11-23 12:14:10 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-04-28 21:48:45 -04:00
|
|
|
|
2011-11-23 19:26:23 -05:00
|
|
|
|
2011-11-24 22:19:58 -05:00
|
|
|
|
2011-11-23 19:26:23 -05:00
|
|
|
|
2011-11-24 18:22:03 -05:00
|
|
|
|
2012-06-09 00:59:08 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-20 15:26:15 -08:00
|
|
|
|
2012-06-09 00:59:08 -04:00
|
|
|
|
|
|
|
|
|
2013-10-01 16:11:26 -04:00
|
|
|
|
2011-12-06 12:21:54 -05:00
|
|
|
|
2015-05-08 11:43:53 -04:00
|
|
|
|
2013-09-29 22:06:07 -04:00
|
|
|
|
2016-11-24 08:03:41 +11:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-10-03 01:31:18 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-12-06 12:21:54 -05:00
|
|
|
|
|
|
|
|
|
2025-09-18 12:11:47 +02:00
|
|
|
|
2011-12-06 12:21:54 -05:00
|
|
|
|
|
|
|
|
|
2013-09-29 22:06:07 -04:00
|
|
|
|
2013-09-29 11:24:49 -04:00
|
|
|
|
2025-08-20 19:54:45 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-12-06 12:21:54 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-10-04 19:15:13 -07:00
|
|
|
|
2025-06-09 22:03:17 -04:00
|
|
|
|
|
|
|
|
|
2013-10-04 19:15:13 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-01-30 13:30:21 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-11-10 16:08:22 +01:00
|
|
|
|
2019-01-30 13:30:21 -05:00
|
|
|
|
2020-05-14 16:44:24 +02:00
|
|
|
|
2025-06-08 23:25:36 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-12-15 21:17:05 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-02-21 14:13:01 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-06-17 21:35:22 -04:00
|
|
|
|
2023-10-25 16:02:00 +02:00
|
|
|
|
2024-12-15 21:17:06 +01:00
|
|
|
|
2024-12-15 21:17:05 +01:00
|
|
|
|
2024-12-15 21:17:06 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-12-15 21:17:05 +01:00
|
|
|
|
2026-04-27 10:26:02 +02:00
|
|
|
|
|
|
|
|
|
2023-10-25 16:02:00 +02:00
|
|
|
|
|
|
|
|
|
2024-05-24 12:19:39 +02:00
|
|
|
|
2024-12-13 00:03:44 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-07-19 13:41:52 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-01-29 17:58:00 +01:00
|
|
|
|
2025-01-29 17:58:01 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-09-30 15:31:53 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-01-29 17:58:01 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-08-20 03:23:12 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-08-27 13:37:12 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-01-29 17:58:00 +01:00
|
|
|
|