fs/f2fs/segment.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-)
From: Yao Xiao <xiangyaof4free@gmail.com>
To: Jaegeuk Kim <jaegeuk@kernel.org>, Chao Yu <chao@kernel.org>
Cc: linux-f2fs-devel@lists.sourceforge.net,
linux-fsdevel@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH v2] f2fs: add overflow/underflow checks to update_sit_entry
The update_sit_entry() function performs an arithmetic operation between
se->valid_blocks (a 10-bit unsigned bitfield) and a signed integer 'del'.
Under C integer promotion rules, the signed integer is converted to unsigned
before the addition, which can lead to wraparound behavior:
- If 'del' is negative and large, it becomes a large unsigned integer,
resulting in an unintended huge positive addition.
- If 'del' is positive and large, the result can exceed the bitfield's
maximum representable range.
To avoid undefined behavior caused by performing the arithmetic first and
validating the result afterwards, this patch adds explicit overflow/underflow
checks before computing the new value. This ensures the operation is safe
and prevents inconsistent SIT metadata updates.
This change follows the defensive overflow check style used in previous
f2fs fixes addressing similar boundary issues.
Signed-off-by: Yao Xiao <xiangyaof4free@gmail.com>
---
fs/f2fs/segment.c | 28 +++++++++++++++++++++++-----
1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index b45eace879d7..05ab34600e32 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -2569,13 +2569,33 @@ static void update_sit_entry(struct
f2fs_sb_info *sbi, block_t blkaddr, int del)
struct seg_entry *se;
unsigned int segno, offset;
long int new_vblocks;
+ unsigned int max_valid;
segno = GET_SEGNO(sbi, blkaddr);
if (segno == NULL_SEGNO)
return;
se = get_seg_entry(sbi, segno);
- new_vblocks = se->valid_blocks + del;
+ max_valid = f2fs_usable_blks_in_seg(sbi, segno);
+
+ /* Prevent overflow/underflow before performing arithmetic. */
+ if (del > 0) {
+ if ((unsigned int)del > max_valid ||
+ se->valid_blocks > max_valid - (unsigned int)del) {
+ f2fs_bug_on(sbi, 1);
+ return;
+ }
+ } else if (del < 0) {
+ if (se->valid_blocks < (unsigned int)(-del)) {
+ f2fs_bug_on(sbi, 1);
+ return;
+ }
+ }
+
+ new_vblocks = (long int)se->valid_blocks + del;
offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr);
f2fs_bug_on(sbi, (new_vblocks < 0 ||
--
2.34.1
From 4acb10c7517b0a2bd9fd6f1ab3337cfc1b90f99b Mon Sep 17 00:00:00 2001
From: Yao Xiao <xiangyaof4free@gmail.com>
Date: Wed, 4 Dec 2024 12:00:00 +0800
Subject: [PATCH v2] f2fs: add overflow/underflow checks to update_sit_entry
Signed-off-by: Yao Xiao <xiangyaof4free@gmail.com>
---
fs/f2fs/segment.c | 28 +++++++++++++++++++++++-----
1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index b45eace879d7..05ab34600e32 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -2569,13 +2569,33 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
struct seg_entry *se;
unsigned int segno, offset;
long int new_vblocks;
+ unsigned int max_valid;
segno = GET_SEGNO(sbi, blkaddr);
if (segno == NULL_SEGNO)
return;
se = get_seg_entry(sbi, segno);
- new_vblocks = se->valid_blocks + del;
+ max_valid = f2fs_usable_blks_in_seg(sbi, segno);
+
+ /* Prevent overflow/underflow before performing arithmetic. */
+ if (del > 0) {
+ if ((unsigned int)del > max_valid ||
+ se->valid_blocks > max_valid - (unsigned int)del) {
+ f2fs_bug_on(sbi, 1);
+ return;
+ }
+ } else if (del < 0) {
+ if (se->valid_blocks < (unsigned int)(-del)) {
+ f2fs_bug_on(sbi, 1);
+ return;
+ }
+ }
+
+ new_vblocks = (long int)se->valid_blocks + del;
offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr);
f2fs_bug_on(sbi, (new_vblocks < 0 ||
--
2.34.1
© 2016 - 2025 Red Hat, Inc.