* FAILED: patch "[PATCH] gfs2: reject invalid inode sizes" failed to apply to 6.6-stable tree
@ 2026-11-07 10:29 Sasha Levin
2026-11-10 12:50 ` [PATCH 6.6.y] gfs2: reject invalid inode sizes Sasha Levin
0 siblings, 1 reply; 2+ messages in thread
From: Sasha Levin @ 2026-11-07 10:29 UTC (permalink / raw)
To: r772577952, agruenba; +Cc: stable
The patch below does not apply to the 6.6-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.6.y
git checkout FETCH_HEAD
git cherry-pick -x 33ed0a0567e0abe66ea65e89dad2e35082890fbe
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '20261107052902-failed-6.6-33ed0a0567e0@kernel.org' --subject-prefix 'PATCH 6.6.y' 'HEAD^..'
Thanks,
Sasha
------------------ original commit in Linus's tree ------------------
From 33ed0a0567e0abe66ea65e89dad2e35082890fbe Mon Sep 17 00:00:00 2001
From: Jiaming Zhang <r772577952@gmail.com>
Date: Mon, 31 Aug 2026 18:54:25 +0800
Subject: [PATCH] gfs2: reject invalid inode sizes
A corrupted GFS2 image can store a dinode size that is larger than what VFS
i_size can represent. gfs2_dinode_in() reads the on-disk di_size as a u64 and
writes it directly into inode->i_size. If the value is larger than S64_MAX, the
incore i_size becomes negative. That negative value can bypass the existing
stuffed inode size check:
inode->i_size > gfs2_max_stuffed_size(ip)
Later, gfs2_quotad may try to sync the quota file and unstuff the quota inode.
gfs2_unstuffer_folio() reads the negative i_size into an unsigned length and
passes it to memcpy(), turning it into a huge copy size and triggering a
out-of-bound issue.
Reject dinodes whose size exceeds sb->s_maxbytes before storing the value in
inode->i_size. Also make the stuffed inode check use the raw on-disk size while
it is still unsigned.
Fixes: 70376c7ff312 ("gfs2: Always check inode size of inline inodes")
Closes: https://lore.kernel.org/lkml/CANypQFaF6bvORKKbRALvEL0k_epFaneFiOQqco4gjdmKVbdURg@mail.gmail.com/
Assisted-by: Codex:gpt-5.5-xhigh
Cc: stable@vger.kernel.org
Signed-off-by: Jiaming Zhang <r772577952@gmail.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/gfs2/glops.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 662d033fd2caf..2597e1cf2315c 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -393,6 +393,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
umode_t mode = be32_to_cpu(str->di_mode);
struct inode *inode = &ip->i_inode;
bool is_new = inode_state_read_once(inode) & I_NEW;
+ u64 size;
if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr))) {
gfs2_consist_inode(ip);
@@ -418,7 +419,12 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
i_uid_write(inode, be32_to_cpu(str->di_uid));
i_gid_write(inode, be32_to_cpu(str->di_gid));
set_nlink(inode, be32_to_cpu(str->di_nlink));
- i_size_write(inode, be64_to_cpu(str->di_size));
+ size = be64_to_cpu(str->di_size);
+ if (unlikely(size > inode->i_sb->s_maxbytes)) {
+ gfs2_consist_inode(ip);
+ return -EIO;
+ }
+ i_size_write(inode, size);
gfs2_set_inode_blocks(inode, be64_to_cpu(str->di_blocks));
atime.tv_sec = be64_to_cpu(str->di_atime);
atime.tv_nsec = be32_to_cpu(str->di_atime_nsec);
@@ -462,7 +468,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
return -EIO;
}
- if (gfs2_is_stuffed(ip) && inode->i_size > gfs2_max_stuffed_size(ip)) {
+ if (gfs2_is_stuffed(ip) && size > gfs2_max_stuffed_size(ip)) {
gfs2_consist_inode(ip);
return -EIO;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [PATCH 6.6.y] gfs2: reject invalid inode sizes
2026-11-07 10:29 FAILED: patch "[PATCH] gfs2: reject invalid inode sizes" failed to apply to 6.6-stable tree Sasha Levin
@ 2026-11-10 12:50 ` Sasha Levin
0 siblings, 0 replies; 2+ messages in thread
From: Sasha Levin @ 2026-11-10 12:50 UTC (permalink / raw)
To: stable; +Cc: Jiaming Zhang, Andreas Gruenbacher, Sasha Levin
From: Jiaming Zhang <r772577952@gmail.com>
[ Upstream commit 33ed0a0567e0abe66ea65e89dad2e35082890fbe ]
A corrupted GFS2 image can store a dinode size that is larger than what VFS
i_size can represent. gfs2_dinode_in() reads the on-disk di_size as a u64 and
writes it directly into inode->i_size. If the value is larger than S64_MAX, the
incore i_size becomes negative. That negative value can bypass the existing
stuffed inode size check:
inode->i_size > gfs2_max_stuffed_size(ip)
Later, gfs2_quotad may try to sync the quota file and unstuff the quota inode.
gfs2_unstuffer_folio() reads the negative i_size into an unsigned length and
passes it to memcpy(), turning it into a huge copy size and triggering a
out-of-bound issue.
Reject dinodes whose size exceeds sb->s_maxbytes before storing the value in
inode->i_size. Also make the stuffed inode check use the raw on-disk size while
it is still unsigned.
Fixes: 70376c7ff312 ("gfs2: Always check inode size of inline inodes")
Closes: https://lore.kernel.org/lkml/CANypQFaF6bvORKKbRALvEL0k_epFaneFiOQqco4gjdmKVbdURg@mail.gmail.com/
Assisted-by: Codex:gpt-5.5-xhigh
Cc: stable@vger.kernel.org
Signed-off-by: Jiaming Zhang <r772577952@gmail.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
[ sashal: adjusted context for direct inode->i_state access instead of inode_state_read_once() ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/gfs2/glops.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index f575cd8ff47c1..0be93498e3308 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -412,6 +412,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
umode_t mode = be32_to_cpu(str->di_mode);
struct inode *inode = &ip->i_inode;
bool is_new = inode->i_state & I_NEW;
+ u64 size;
if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr))) {
gfs2_consist_inode(ip);
@@ -437,7 +438,12 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
i_uid_write(inode, be32_to_cpu(str->di_uid));
i_gid_write(inode, be32_to_cpu(str->di_gid));
set_nlink(inode, be32_to_cpu(str->di_nlink));
- i_size_write(inode, be64_to_cpu(str->di_size));
+ size = be64_to_cpu(str->di_size);
+ if (unlikely(size > inode->i_sb->s_maxbytes)) {
+ gfs2_consist_inode(ip);
+ return -EIO;
+ }
+ i_size_write(inode, size);
gfs2_set_inode_blocks(inode, be64_to_cpu(str->di_blocks));
atime.tv_sec = be64_to_cpu(str->di_atime);
atime.tv_nsec = be32_to_cpu(str->di_atime_nsec);
@@ -475,7 +481,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
ip->i_depth = (u8)depth;
ip->i_entries = be32_to_cpu(str->di_entries);
- if (gfs2_is_stuffed(ip) && inode->i_size > gfs2_max_stuffed_size(ip)) {
+ if (gfs2_is_stuffed(ip) && size > gfs2_max_stuffed_size(ip)) {
gfs2_consist_inode(ip);
return -EIO;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-11-10 12:50 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-07 10:29 FAILED: patch "[PATCH] gfs2: reject invalid inode sizes" failed to apply to 6.6-stable tree Sasha Levin
2026-11-10 12:50 ` [PATCH 6.6.y] gfs2: reject invalid inode sizes Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox