From: "Darrick J. Wong" <djwong@kernel.org>
To: Christoph Hellwig <hch@infradead.org>
Cc: cheng.lin130@zte.com.cn, david@fromorbit.com,
linux-xfs@vger.kernel.org, jiang.yong5@zte.com.cn,
wang.liang82@zte.com.cn, liu.dong3@zte.com.cn
Subject: [PATCH] xfs: pin inodes that would otherwise overflow link count
Date: Wed, 11 Oct 2023 13:33:50 -0700 [thread overview]
Message-ID: <20231011203350.GY21298@frogsfrogsfrogs> (raw)
From: Darrick J. Wong <djwong@kernel.org>
The VFS inc_nlink function does not explicitly check for integer
overflows in the i_nlink field. Instead, it checks the link count
against s_max_links in the vfs_{link,create,rename} functions. XFS
sets the maximum link count to 2.1 billion, so integer overflows should
not be a problem.
However. It's possible that online repair could find that a file has
more than four billion links, particularly if the link count got
corrupted while creating hardlinks to the file. The di_nlinkv2 field is
not large enough to store a value larger than 2^32, so we ought to
define a magic pin value of ~0U which means that the inode never gets
deleted. This will prevent a UAF error if the repair finds this
situation and users begin deleting links to the file.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
fs/xfs/libxfs/xfs_format.h | 6 ++++++
fs/xfs/scrub/nlinks.c | 8 ++++----
fs/xfs/scrub/repair.c | 12 ++++++------
fs/xfs/xfs_inode.c | 28 +++++++++++++++++++++++-----
4 files changed, 39 insertions(+), 15 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 6409dd22530f2..320522b887bb3 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -896,6 +896,12 @@ static inline uint xfs_dinode_size(int version)
*/
#define XFS_MAXLINK ((1U << 31) - 1U)
+/*
+ * Any file that hits the maximum ondisk link count should be pinned to avoid
+ * a use-after-free situation.
+ */
+#define XFS_NLINK_PINNED (~0U)
+
/*
* Values for di_format
*
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 4db2c2a6538d6..30604e11182c4 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -910,15 +910,25 @@ xfs_init_new_inode(
*/
static int /* error */
xfs_droplink(
- xfs_trans_t *tp,
- xfs_inode_t *ip)
+ struct xfs_trans *tp,
+ struct xfs_inode *ip)
{
+ struct inode *inode = VFS_I(ip);
+
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
- drop_nlink(VFS_I(ip));
+ if (inode->i_nlink == 0) {
+ xfs_info_ratelimited(tp->t_mountp,
+ "Inode 0x%llx link count dropped below zero. Pinning link count.",
+ ip->i_ino);
+ set_nlink(inode, XFS_NLINK_PINNED);
+ }
+ if (inode->i_nlink != XFS_NLINK_PINNED)
+ drop_nlink(inode);
+
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
- if (VFS_I(ip)->i_nlink)
+ if (inode->i_nlink)
return 0;
return xfs_iunlink(tp, ip);
@@ -932,9 +942,17 @@ xfs_bumplink(
struct xfs_trans *tp,
struct xfs_inode *ip)
{
+ struct inode *inode = VFS_I(ip);
+
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
- inc_nlink(VFS_I(ip));
+ if (inode->i_nlink == XFS_NLINK_PINNED - 1)
+ xfs_info_ratelimited(tp->t_mountp,
+ "Inode 0x%llx link count exceeded maximum. Pinning link count.",
+ ip->i_ino);
+ if (inode->i_nlink != XFS_NLINK_PINNED)
+ inc_nlink(inode);
+
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
}
next reply other threads:[~2023-10-11 20:34 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-10-11 20:33 Darrick J. Wong [this message]
2023-10-11 21:08 ` [PATCH] xfs: pin inodes that would otherwise overflow link count Dave Chinner
2023-10-11 21:14 ` Dave Chinner
2023-10-11 21:25 ` Darrick J. Wong
2023-10-11 21:41 ` Darrick J. Wong
2023-10-11 22:21 ` Dave Chinner
2023-10-12 11:05 ` cheng.lin130
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=20231011203350.GY21298@frogsfrogsfrogs \
--to=djwong@kernel.org \
--cc=cheng.lin130@zte.com.cn \
--cc=david@fromorbit.com \
--cc=hch@infradead.org \
--cc=jiang.yong5@zte.com.cn \
--cc=linux-xfs@vger.kernel.org \
--cc=liu.dong3@zte.com.cn \
--cc=wang.liang82@zte.com.cn \
/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