From: Baolin Liu <liubaolin12138@163.com>
To: linkinjeon@kernel.org, hyc.lee@gmail.com
Cc: ntfs@lists.linux.dev, linux-kernel@vger.kernel.org,
chenxiaosong@chenxiaosong.com, Baolin Liu <liubaolin@kylinos.cn>
Subject: [PATCH v2 02/10] ntfs: validate EA chains and link zero-terminated tails
Date: Sun, 20 Sep 2026 16:31:23 +0800 [thread overview]
Message-ID: <20260920083131.1880061-3-liubaolin12138@163.com> (raw)
In-Reply-To: <20260920083131.1880061-1-liubaolin12138@163.com>
From: Baolin Liu <liubaolin@kylinos.cn>
A zero next-entry offset terminates an EA list. Appending an entry
without linking the old tail makes the new entry unreachable. Invalid
entries are also treated as missing names, allowing setters to proceed
on corrupt metadata.
Validate the entire chain before modifying it and connect a zero tail
to the append position. Check name terminators and retain the full tail
span when removing an entry. Return EUCLEAN for malformed EA structures
and inconsistent information lengths, preserving that error through the
get and set paths. Keep ENOENT for a missing name and translate it to
ENODATA only at the xattr read boundary. Preserve lower-level read errors.
Signed-off-by: Baolin Liu <liubaolin@kylinos.cn>
---
fs/ntfs/ea.c | 49 +++++++++++++++++++++++++++++++++++--------------
1 file changed, 35 insertions(+), 14 deletions(-)
diff --git a/fs/ntfs/ea.c b/fs/ntfs/ea.c
index bb97df3045a0..59160e49a53f 100644
--- a/fs/ntfs/ea.c
+++ b/fs/ntfs/ea.c
@@ -53,10 +53,13 @@ static int ntfs_ea_lookup(char *ea_buf, s64 ea_buf_size, const char *name,
loff_t offset, p_ea_size;
unsigned int next;
+ if (!ea_buf_size)
+ return -ENOENT;
+
offset = 0;
do {
if (ea_buf_size - offset < sizeof(struct ea_attr))
- break;
+ return -EUCLEAN;
p_ea = (const struct ea_attr *)&ea_buf[offset];
next = le32_to_cpu(p_ea->next_entry_offset);
@@ -64,31 +67,31 @@ static int ntfs_ea_lookup(char *ea_buf, s64 ea_buf_size, const char *name,
if (p_ea_size < sizeof(struct ea_attr) ||
offset + p_ea_size > ea_buf_size)
- break;
+ return -EUCLEAN;
if ((s64)p_ea->ea_name_length + 1 >
p_ea_size - offsetof(struct ea_attr, ea_name))
- break;
+ return -EUCLEAN;
actual_size = ALIGN(struct_size(p_ea, ea_name, 1 + p_ea->ea_name_length +
le16_to_cpu(p_ea->ea_value_length)), 4);
- if (actual_size > p_ea_size)
- break;
+ if (actual_size > p_ea_size ||
+ p_ea->ea_name[p_ea->ea_name_length])
+ return -EUCLEAN;
- if (p_ea->ea_name_length == name_len &&
+ if (name && p_ea->ea_name_length == name_len &&
!memcmp(p_ea->ea_name, name, name_len)) {
*ea_offset = offset;
- *ea_size = next ? next : actual_size;
+ *ea_size = p_ea_size;
if (ea_buf_size < *ea_offset + *ea_size)
- goto out;
+ return -EUCLEAN;
return 0;
}
offset += next;
} while (next > 0 && offset < ea_buf_size);
-out:
return -ENOENT;
}
@@ -126,7 +129,7 @@ static int ntfs_get_ea(struct inode *inode, const char *name, size_t name_len,
return PTR_ERR(p_ea_info);
if (ea_info_size != sizeof(struct ea_information)) {
kvfree(p_ea_info);
- return -EIO;
+ return -EUCLEAN;
}
ea_info_qlen = le32_to_cpu(p_ea_info->ea_query_length);
@@ -137,7 +140,7 @@ static int ntfs_get_ea(struct inode *inode, const char *name, size_t name_len,
return PTR_ERR(ea_buf);
if (ea_info_qlen > all_ea_size) {
- err = -EIO;
+ err = -EUCLEAN;
goto free_ea_buf;
}
@@ -162,7 +165,8 @@ static int ntfs_get_ea(struct inode *inode, const char *name, size_t name_len,
return ea_value_len;
}
- err = -ENODATA;
+ if (err == -ENOENT)
+ err = -ENODATA;
free_ea_buf:
kvfree(ea_buf);
return err;
@@ -216,7 +220,7 @@ static int ntfs_set_ea(struct inode *inode, const char *name, size_t name_len,
goto out;
}
if (ea_info_size != sizeof(struct ea_information)) {
- err = -EIO;
+ err = -EUCLEAN;
goto out;
}
@@ -255,12 +259,29 @@ static int ntfs_set_ea(struct inode *inode, const char *name, size_t name_len,
}
if (ea_info_qsize > all_ea_size) {
- err = -EIO;
+ err = -EUCLEAN;
goto out;
}
+ /* Validate the whole chain before modifying it, including its tail. */
+ err = ntfs_ea_lookup(ea_buf, ea_info_qsize, NULL, 0, &ea_off,
+ &ea_size);
+ if (err != -ENOENT)
+ goto out;
+ /* A zero tail offset must be linked before appending another EA. */
+ for (ea_off = 0; ea_off < ea_info_qsize; ea_off += ea_size) {
+ p_ea = (struct ea_attr *)(ea_buf + ea_off);
+ ea_size = le32_to_cpu(p_ea->next_entry_offset);
+ if (!ea_size) {
+ ea_size = ea_info_qsize - ea_off;
+ p_ea->next_entry_offset = cpu_to_le32(ea_size);
+ }
+ }
+
err = ntfs_ea_lookup(ea_buf, ea_info_qsize, name, name_len, &ea_off,
&ea_size);
+ if (err && err != -ENOENT)
+ goto out;
if (ea_info_qsize && !err) {
if (flags & XATTR_CREATE) {
err = -EEXIST;
--
2.51.0
next prev parent reply other threads:[~2026-09-20 8:32 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-20 8:31 [PATCH v2 00/10] ntfs: persist Linux file attributes in an EA Baolin Liu
2026-09-20 8:31 ` [PATCH v2 01/10] ntfs: keep the EA presence flag after creating the first entry Baolin Liu
2026-09-20 8:31 ` Baolin Liu [this message]
2026-09-21 6:17 ` [PATCH v2 02/10] ntfs: validate EA chains and link zero-terminated tails Namjae Jeon
2026-09-21 10:34 ` liubaolin
2026-09-20 8:31 ` [PATCH v2 03/10] ntfs: propagate EA write and truncate errors Baolin Liu
2026-09-20 8:31 ` [PATCH v2 04/10] ntfs: preserve EA attribute lookup errors Baolin Liu
2026-09-20 8:31 ` [PATCH v2 05/10] ntfs: distinguish empty EA values from removal Baolin Liu
2026-09-20 8:31 ` [PATCH v2 06/10] ntfs: restore EA attributes when an update fails Baolin Liu
2026-09-20 8:31 ` [PATCH v2 07/10] ntfs: add fileattr query support Baolin Liu
2026-09-20 8:31 ` [PATCH v2 08/10] ntfs: persist immutable in the $LXFLAGS EA Baolin Liu
2026-09-22 1:21 ` Hyunchul Lee
2026-09-22 3:26 ` liubaolin
2026-09-22 5:25 ` Hyunchul Lee
2026-09-22 6:02 ` liubaolin
2026-09-20 8:31 ` [PATCH v2 09/10] ntfs: persist append-only " Baolin Liu
2026-09-20 8:31 ` [PATCH v2 10/10] ntfs: persist nodump " Baolin Liu
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=20260920083131.1880061-3-liubaolin12138@163.com \
--to=liubaolin12138@163.com \
--cc=chenxiaosong@chenxiaosong.com \
--cc=hyc.lee@gmail.com \
--cc=linkinjeon@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=liubaolin@kylinos.cn \
--cc=ntfs@lists.linux.dev \
/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®