Currently, commit e9e2eae89ddb dropped a (int) decoration from
XFS_LITINO(mp), and since sizeof() expression is also involved,
the result of XFS_LITINO(mp) is simply as the size_t type
(commonly unsigned long).
Considering the expression in xfs_attr_shortform_bytesfit():
offset = (XFS_LITINO(mp) - bytes) >> 3;
let "bytes" be (int)340, and
"XFS_LITINO(mp)" be (unsigned long)336.
on 64-bit platform, the expression is
offset = ((unsigned long)336 - (int)340) >> 8 =
(int)(0xfffffffffffffffcUL >> 3) = -1
but on 32-bit platform, the expression is
offset = ((unsigned long)336 - (int)340) >> 8 =
(int)(0xfffffffcUL >> 3) = 0x1fffffff
instead.
so offset becomes a large number on 32-bit platform, and cause
xfs_attr_shortform_bytesfit() returns maxforkoff rather than 0
Therefore, one result is
"ASSERT(new_size <= XFS_IFORK_SIZE(ip, whichfork));"
assertion failure in xfs_idata_realloc().
, which can be triggered with the following commands:
touch a;
setfattr -n user.0 -v "`seq 0 80`" a;
setfattr -n user.1 -v "`seq 0 80`" a
on 32-bit platform.
Fix it by restoring (int) decorator to XFS_LITINO(mp) since
int type for XFS_LITINO(mp) is safe and all pre-exist signed
calculations are correct.
Fixes: e9e2eae89ddb ("xfs: only check the superblock version for dinode size calculation")
Cc: <stable(a)vger.kernel.org> # 5.7+
Signed-off-by: Gao Xiang <hsiangkao(a)redhat.com>
---
I'm not sure this is the preferred way or just simply fix
xfs_attr_shortform_bytesfit() since I don't look into the
rest of XFS_LITINO(mp) users. Add (int) to XFS_LITINO(mp)
will avoid all potential regression at least.
fs/xfs/libxfs/xfs_format.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index dd764da08f6f..f58f0a44c024 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -1061,7 +1061,7 @@ enum xfs_dinode_fmt {
sizeof(struct xfs_dinode) : \
offsetof(struct xfs_dinode, di_crc))
#define XFS_LITINO(mp) \
- ((mp)->m_sb.sb_inodesize - XFS_DINODE_SIZE(&(mp)->m_sb))
+ ((int)((mp)->m_sb.sb_inodesize - XFS_DINODE_SIZE(&(mp)->m_sb)))
/*
* Inode data & attribute fork sizes, per inode.
--
2.18.4