From: Danny Hu <dannyhu@arista.com>
To: Alexander Viro <viro@zeniv.linux.org.uk>,
Christian Brauner <brauner@kernel.org>
Cc: Mimi Zohar <zohar@linux.ibm.com>,
Roberto Sassu <roberto.sassu@huawei.com>,
Dmitry Kasatkin <dmitry.kasatkin@gmail.com>,
Eric Snowberg <eric.snowberg@oracle.com>, Jan Kara <jack@suse.cz>,
Victor Kamensky <kamensky@cisco.com>,
Taras Kondratiuk <takondra@cisco.com>,
Zheng Zengkai <zhengzengkai@huawei.com>,
zhangguangzhi <zhangguangzhi3@huawei.com>,
Danny Hu <dannyhu@arista.com>, Jason Yan <yanaijie@huawei.com>,
silviu.vlasceanu@huawei.com, hpa@zytor.com, arnd@arndb.de,
james.w.mcmechan@gmail.com, niveditas98@gmail.com,
pierre@arista.com, julien@arista.com, kbharathi@arista.com,
alexandr.lobakin@intel.com, linux-fsdevel@vger.kernel.org,
linux-integrity@vger.kernel.org,
linux-security-module@vger.kernel.org,
linux-kbuild@vger.kernel.org, initramfs@vger.kernel.org,
linux-api@vger.kernel.org, linux-kernel@vger.kernel.org,
bug-cpio@gnu.org
Subject: [PATCH v6 3/4] initramfs: read metadata from special file METADATA!!!
Date: Thu, 5 Nov 2026 11:37:42 -0800 [thread overview]
Message-ID: <20261105193743.2654656-4-dannyhu@arista.com> (raw)
In-Reply-To: <20261105193743.2654656-1-dannyhu@arista.com>
From: Roberto Sassu <roberto.sassu@huawei.com>
Instead of changing the CPIO format, metadata are parsed from regular files
with special name 'METADATA!!!'. This file immediately follows the file
metadata are added to.
This patch checks if the file being extracted has the special name and, if
yes, creates a buffer with the content of that file and transitions
to a new dedicated CollectMetadata state to buffer the metadata contents
in memory without creating a file in the rootfs.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Reported-by: kbuild test robot <lkp@intel.com>
Signed-off-by: Tianxing Zhang <zhangtianxing3@huawei.com>
Signed-off-by: Zheng Zengkai <zhengzengkai@huawei.com>
Signed-off-by: zhoushuiqing <zhoushuiqing2@huawei.com>
Signed-off-by: zhangguangzhi <zhangguangzhi3@huawei.com>
Signed-off-by: Danny Hu <dannyhu@arista.com>
---
v6 changes:
- Introduce a dedicated CollectMetadata state to collect METADATA!!! entries
in memory. This state replaces the metadata flag and eliminates the need to
reset it on failure paths. Since metadata is collected purely in memory, the
entry is no longer extracted as a regular file to the root of the archive.
This also has the benefit of separating metadata collection from do_copy.
- Validate the checksum before setting the xattr with do_parse_metadata
- Improve bookkeeping of previous_name_buf by setting it only after the target
object is created. Clear the buffer on skipped or failed entries to prevent
setting metadata on the wrong target. Indicate that previous_name_buf is
invalid/not set by having the first byte be the NUL character
- Remove "Reviewed-by: Jason Yan <yanaijie@huawei.com>" because patch has
implementation has significantly changed in the v6 revision
v5 changes:
- clean up metadata buffer when returning from unpack_to_rootfs()
init/initramfs.c | 103 +++++++++++++++++++++++++++++++++++++++++------
1 file changed, 90 insertions(+), 13 deletions(-)
diff --git a/init/initramfs.c b/init/initramfs.c
index d206624d1160..a17c26fde5f5 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -34,6 +34,17 @@
static __initdata bool csum_present;
static __initdata u32 io_csum;
+static void __init update_csum(const unsigned char *buf, size_t len)
+{
+ size_t i;
+
+ if (!csum_present)
+ return;
+
+ for (i = 0; i < len; i++)
+ io_csum += buf[i];
+}
+
static ssize_t __init xwrite(struct file *file, const unsigned char *p,
size_t count, loff_t *pos)
{
@@ -50,12 +61,7 @@ static ssize_t __init xwrite(struct file *file, const unsigned char *p,
} else if (rv == 0)
break;
- if (csum_present) {
- ssize_t i;
-
- for (i = 0; i < rv; i++)
- io_csum += p[i];
- }
+ update_csum(p, rv);
p += rv;
out += rv;
@@ -233,6 +239,7 @@ static __initdata enum state {
SkipIt,
GotName,
CopyFile,
+ CollectMetadata,
GotSymlink,
Reset
} state, next_state;
@@ -266,7 +273,7 @@ static void __init read_into(char *buf, unsigned size, enum state next)
}
}
-static __initdata char *header_buf, *symlink_buf, *name_buf;
+static __initdata char *header_buf, *symlink_buf, *name_buf, *previous_name_buf;
static __initdata char *metadata_buf;
static int __init do_start(void)
@@ -308,10 +315,10 @@ static int __init do_header(void)
next_header = (next_header + 3) & ~3;
state = SkipIt;
if (name_len <= 0 || name_len > PATH_MAX)
- return 0;
+ goto skip;
if (S_ISLNK(mode)) {
if (body_len > PATH_MAX)
- return 0;
+ goto skip;
collect = collected = symlink_buf;
remains = N_ALIGN(name_len) + body_len;
next_state = GotSymlink;
@@ -320,6 +327,11 @@ static int __init do_header(void)
}
if (S_ISREG(mode) || !body_len)
read_into(name_buf, N_ALIGN(name_len), GotName);
+ else
+ goto skip;
+ return 0;
+skip:
+ previous_name_buf[0] = '\0';
return 0;
}
@@ -471,6 +483,8 @@ static __initdata loff_t wfile_pos;
static int __init do_name(void)
{
+ bool target_ready = false;
+
state = SkipIt;
next_state = Reset;
@@ -482,6 +496,19 @@ static int __init do_name(void)
return 1;
}
+ if (S_ISREG(mode) && strcmp(collected, METADATA_FILENAME) == 0) {
+ metadata_len = body_len;
+ if (metadata_len)
+ metadata_buf = kmalloc(metadata_len, GFP_KERNEL);
+ else
+ metadata_buf = NULL;
+ io_csum = 0;
+ state = CollectMetadata;
+ return 0;
+ }
+
+ /* Clear metadata target only after checking entry is not metadata */
+ previous_name_buf[0] = '\0';
if (strcmp(collected, "TRAILER!!!") == 0) {
free_hash();
return 0;
@@ -504,24 +531,65 @@ static int __init do_name(void)
if (body_len)
vfs_truncate(&wfile->f_path, body_len);
state = CopyFile;
+ target_ready = true;
}
} else if (S_ISDIR(mode)) {
- init_mkdir(collected, mode);
+ int ret = init_mkdir(collected, mode);
+
+ target_ready = !ret || ret == -EEXIST;
init_chown(collected, uid, gid, 0);
init_chmod(collected, mode);
dir_add(collected, name_len, mtime);
} else if (S_ISBLK(mode) || S_ISCHR(mode) ||
S_ISFIFO(mode) || S_ISSOCK(mode)) {
- if (maybe_link() == 0) {
- init_mknod(collected, mode, rdev);
+ int ml = maybe_link();
+
+ if (ml == 0) {
+ int ret = init_mknod(collected, mode, rdev);
+
+ target_ready = !ret || ret == -EEXIST;
init_chown(collected, uid, gid, 0);
init_chmod(collected, mode);
do_utime(collected, mtime);
+ } else if (ml == 1) {
+ target_ready = true;
}
}
+ if (target_ready)
+ memcpy(previous_name_buf, collected, strlen(collected) + 1);
return 0;
}
+static void __init do_process_metadata(const char *buf, size_t len)
+{
+ /* Still checksum the body if allocation failed. */
+ update_csum((const unsigned char *)buf, len);
+ if (metadata_buf)
+ memcpy(metadata_buf + (metadata_len - body_len), buf, len);
+}
+
+static int __init do_collect_metadata(void)
+{
+ if (byte_count >= body_len) {
+ do_process_metadata(victim, body_len);
+ if (csum_present && io_csum != hdr_csum)
+ error("bad data checksum");
+ else if (metadata_buf && previous_name_buf[0])
+ do_parse_metadata(previous_name_buf);
+ kfree(metadata_buf);
+ metadata_buf = NULL;
+ metadata_len = 0;
+ eat(body_len);
+ state = SkipIt;
+ return 0;
+ }
+
+ do_process_metadata(victim, byte_count);
+ body_len -= byte_count;
+ eat(byte_count);
+ return 1;
+}
+
static int __init do_copy(void)
{
if (byte_count >= body_len) {
@@ -546,6 +614,7 @@ static int __init do_copy(void)
static int __init do_symlink(void)
{
+ previous_name_buf[0] = '\0';
if (collected[name_len - 1] != '\0') {
pr_err("initramfs symlink without nulterm: %.*s\n",
(int)name_len, collected);
@@ -554,7 +623,8 @@ static int __init do_symlink(void)
}
collected[N_ALIGN(name_len) + body_len] = '\0';
clean_path(collected, 0);
- init_symlink(collected + N_ALIGN(name_len), collected);
+ if (!init_symlink(collected + N_ALIGN(name_len), collected))
+ memcpy(previous_name_buf, collected, strlen(collected) + 1);
init_chown(collected, uid, gid, AT_SYMLINK_NOFOLLOW);
do_utime(collected, mtime);
state = SkipIt;
@@ -569,6 +639,7 @@ static __initdata int (*actions[])(void) = {
[SkipIt] = do_skip,
[GotName] = do_name,
[CopyFile] = do_copy,
+ [CollectMetadata] = do_collect_metadata,
[GotSymlink] = do_symlink,
[Reset] = do_reset,
};
@@ -628,6 +699,7 @@ char * __init unpack_to_rootfs(char *buf, unsigned long len)
char header[CPIO_HDRLEN];
char symlink[PATH_MAX + N_ALIGN(PATH_MAX) + 1];
char name[N_ALIGN(PATH_MAX)];
+ char prev_name[PATH_MAX + N_ALIGN(PATH_MAX) + 1];
} *bufs = kmalloc_obj(*bufs);
if (!bufs)
@@ -636,6 +708,8 @@ char * __init unpack_to_rootfs(char *buf, unsigned long len)
header_buf = bufs->header;
symlink_buf = bufs->symlink;
name_buf = bufs->name;
+ previous_name_buf = bufs->prev_name;
+ previous_name_buf[0] = '\0';
state = Start;
this_header = 0;
@@ -678,6 +752,9 @@ char * __init unpack_to_rootfs(char *buf, unsigned long len)
dir_utime();
/* free any hardlink state collected without optional TRAILER!!! */
free_hash();
+ kfree(metadata_buf);
+ metadata_buf = NULL;
+ metadata_len = 0;
kfree(bufs);
return message;
}
--
2.51.0
next prev parent reply other threads:[~2026-11-05 19:37 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-05 19:37 [PATCH v6 0/4] initramfs: add support for xattrs in the initial ram disk Danny Hu
2026-11-05 19:37 ` [PATCH v6 1/4] ima: skip algorithm availability check until initramfs unpacking is finished Danny Hu
2026-11-05 19:37 ` [PATCH v6 2/4] initramfs: add file metadata Danny Hu
2026-11-05 19:37 ` Danny Hu [this message]
2026-11-05 19:37 ` [PATCH v6 4/4] gen_init_cpio: add support for " Danny Hu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261105193743.2654656-4-dannyhu@arista.com \
--to=dannyhu@arista.com \
--cc=alexandr.lobakin@intel.com \
--cc=arnd@arndb.de \
--cc=brauner@kernel.org \
--cc=bug-cpio@gnu.org \
--cc=dmitry.kasatkin@gmail.com \
--cc=eric.snowberg@oracle.com \
--cc=hpa@zytor.com \
--cc=initramfs@vger.kernel.org \
--cc=jack@suse.cz \
--cc=james.w.mcmechan@gmail.com \
--cc=julien@arista.com \
--cc=kamensky@cisco.com \
--cc=kbharathi@arista.com \
--cc=linux-api@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-integrity@vger.kernel.org \
--cc=linux-kbuild@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=niveditas98@gmail.com \
--cc=pierre@arista.com \
--cc=roberto.sassu@huawei.com \
--cc=silviu.vlasceanu@huawei.com \
--cc=takondra@cisco.com \
--cc=viro@zeniv.linux.org.uk \
--cc=yanaijie@huawei.com \
--cc=zhangguangzhi3@huawei.com \
--cc=zhengzengkai@huawei.com \
--cc=zohar@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®