lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260124003939.426931-3-hpa@zytor.com>
Date: Fri, 23 Jan 2026 16:39:35 -0800
From: "H. Peter Anvin" <hpa@...or.com>
To: Alexander Viro <viro@...iv.linux.org.uk>,
        Christian Brauner <brauner@...nel.org>, Jan Kara <jack@...e.cz>,
        Jonathan Corbet <corbet@....net>, "H. Peter Anvin" <hpa@...or.com>
Cc: linux-fsdevel@...r.kernel.org, linux-doc@...r.kernel.org,
        linux-kernel@...r.kernel.org,
        Lennart Poettering <lennart@...ttering.net>,
        systemd-devel@...ts.freedesktop.org
Subject: [RFC PATCH 2/3] initramfs: support mounting filesystems during initramfs expansion

Expanding the initramfs contents directly into the rootfs is not
always desirable. Allow the initramfs to contain instructions to mount
additional filesystems before continuing processing.

This is done by a magic filename !!!MOUNT!!! which, instead of being
expanded as a file, is processed as a simplified fstab(5) mount
specification (see following documentation patch.)

Some reasons this may be desirable:

1. The early init code may wish to expand into a separate tmpfs so it
   can be pivoted, remounted, or efficiently garbage collected on
   umount.
2. The early init code may which to pass some content, but not all, to
   the main userspace. This allows mounting a second tmpfs that can
   then be mounted underneath somewhere the main root without having
   to copy the contents.
3. The main userspace can retain the rootfs as the only root. In that
   case, the initramfs contents can be expanded into a tmpfs that is
   mounted at a different path. One use case for that might be
   /lib/modules.
4. It may be convenient for the early init code to have /dev, /proc
   and /sys pre-mounted.

Signed-off-by: H. Peter Anvin (Intel) <hpa@...or.com>
---
 init/initramfs.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 95 insertions(+), 3 deletions(-)

diff --git a/init/initramfs.c b/init/initramfs.c
index 6ddbfb17fb8f..681ab59ab6cd 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -222,6 +222,7 @@ static __initdata enum state {
 	GotName,
 	CopyFile,
 	GotSymlink,
+	GotMountpoint,
 	Reset
 } state, next_state;
 
@@ -254,6 +255,9 @@ static void __init read_into(char *buf, unsigned size, enum state next)
 	}
 }
 
+#define SYMLINK_BUF_SIZE	(PATH_MAX + N_ALIGN(PATH_MAX) + 1)
+#define NAME_BUF_SIZE		N_ALIGN(PATH_MAX)
+
 static __initdata char *header_buf, *symlink_buf, *name_buf;
 
 static int __init do_start(void)
@@ -355,6 +359,37 @@ static int __init maybe_link(void)
 	return 0;
 }
 
+static int __init maybe_mountpoint(void)
+{
+	static const char mount_magic_name[] __initconst = "!!!MOUNT!!!";
+	const unsigned long mount_magic_len = sizeof(mount_magic_name)-1;
+	unsigned long len = name_len-1;
+	const char *name = collected;
+
+	if (!S_ISREG(mode))
+		return 0;
+	if (len < mount_magic_len)
+		return 0;
+	if (len > mount_magic_len && name[len-mount_magic_len] != '/')
+		return 0;
+	if (memcmp(name+len-mount_magic_len, mount_magic_name, mount_magic_len))
+		return 0;
+
+	/* Factor out the parent directory name and save it in name_buf */
+	len -= mount_magic_len;
+	if (!len)
+		name_buf[len++] = '.';
+	else
+		memmove(name_buf, name, len);
+	name_buf[len] = '\0';
+
+	if (body_len >= SYMLINK_BUF_SIZE)
+		return 1;	/* Option file too large */
+
+	read_into(symlink_buf, body_len, GotMountpoint);
+	return 1;
+}
+
 static __initdata struct file *wfile;
 static __initdata loff_t wfile_pos;
 
@@ -375,6 +410,10 @@ static int __init do_name(void)
 		free_hash();
 		return 0;
 	}
+
+	if (maybe_mountpoint())
+		return 0;
+
 	clean_path(collected, mode);
 	if (S_ISREG(mode)) {
 		int ml = maybe_link();
@@ -392,6 +431,7 @@ static int __init do_name(void)
 			vfs_fchmod(wfile, mode);
 			if (body_len)
 				vfs_truncate(&wfile->f_path, body_len);
+
 			state = CopyFile;
 		}
 	} else if (S_ISDIR(mode)) {
@@ -451,6 +491,56 @@ static int __init do_symlink(void)
 	return 0;
 }
 
+static int __init do_mountpoint(void)
+{
+	int ret;
+	char *p, *ep;
+	const char *opts[3];
+	const char *opstart;
+	unsigned long n;
+
+	state = SkipIt;
+	next_state = Reset;
+
+	memset(opts, 0, sizeof(opts));
+
+	/* Default filesystem type */
+	opts[0] = IS_ENABLED(CONFIG_TMPFS) ? "tmpfs" : "ramfs";
+
+	p = collected;
+	ep = p + body_len;
+	n = 0;
+	opstart = NULL;
+	while (p < ep && n < 3) {
+		char c = *p;
+		if (c <= ' ') {
+			if (opstart) {
+				*p = '\0';
+				opts[n++] = opstart;
+				opstart = NULL;
+			}
+		} else {
+			if (!opstart)
+				opstart = p;
+		}
+		p++;
+	}
+
+	if (!opts[1])
+		opts[1] = opts[0];
+
+	ret = init_mount(opts[0], name_buf, opts[1], 0, opts[2]);
+	if (!ret) {
+		init_chown(name_buf, uid, gid, 0);
+		init_chmod(name_buf, mode); /* S_IFMT is ignored by chmod() */
+		dir_add(name_buf, name_len, mtime);
+	} else {
+		pr_err("initramfs mount %s %s %s failed, error %d\n",
+		       opts[0], name_buf, opts[1], ret);
+	}
+	return 0;
+}
+
 static __initdata int (*actions[])(void) = {
 	[Start]		= do_start,
 	[Collect]	= do_collect,
@@ -459,6 +549,7 @@ static __initdata int (*actions[])(void) = {
 	[GotName]	= do_name,
 	[CopyFile]	= do_copy,
 	[GotSymlink]	= do_symlink,
+	[GotMountpoint] = do_mountpoint,
 	[Reset]		= do_reset,
 };
 
@@ -515,8 +606,8 @@ char * __init unpack_to_rootfs(char *buf, unsigned long len)
 	const char *compress_name;
 	struct {
 		char header[CPIO_HDRLEN];
-		char symlink[PATH_MAX + N_ALIGN(PATH_MAX) + 1];
-		char name[N_ALIGN(PATH_MAX)];
+		char symlink[SYMLINK_BUF_SIZE];
+		char name[NAME_BUF_SIZE];
 	} *bufs = kmalloc(sizeof(*bufs), GFP_KERNEL);
 
 	if (!bufs)

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ