public inbox for ntfs3@lists.linux.dev
 help / color / mirror / Atom feed
* [bug report] fs/ntfs3: Add initialization of super block
@ 2021-08-24  7:58 Dan Carpenter
  2021-08-24 10:33 ` Kari Argillander
  2026-02-09 15:24 ` [PATCH] fs/ntfs3: avoid calling run_get_entry() when run == NULL in ntfs_read_run_nb_ra() Konstantin Komarov
  0 siblings, 2 replies; 5+ messages in thread
From: Dan Carpenter @ 2021-08-24  7:58 UTC (permalink / raw)
  To: almaz.alexandrovich; +Cc: ntfs3

Hello Konstantin Komarov,

The patch 82cae269cfa9: "fs/ntfs3: Add initialization of super block"
from Aug 13, 2021, leads to the following
Smatch static checker warning:

	fs/ntfs3/index.c:238 bmp_buf_get()
	warn: 'bh' could be an error pointer

fs/ntfs3/index.c
    229 	data_size = le64_to_cpu(b->nres.data_size);
    230 	if (WARN_ON(off >= data_size)) {
    231 		/* looks like filesystem error */
    232 		return -EINVAL;
    233 	}
    234 
    235 	valid_size = le64_to_cpu(b->nres.valid_size);
    236 
    237 	bh = ntfs_bread_run(sbi, &indx->bitmap_run, off);
--> 238 	if (!bh)
    239 		return -EIO;
    240 
    241 	if (IS_ERR(bh))

This is not a bug, but it is wrong style.  When a function returns both
error pointers and NULL then the NULL return is means the feature is
disabled.  It's not an error.  Just that the feature is turned off
deliberately in the Kconfig or whatever.  Don't print an error message,
just continue with the feature disabled as the admin has requested.

But here NULL is just an error.  The ntfs_bread_run() should do:

	bh = ntfs_bread();
	if (!bh)
		return ERR_PTR(-EIO);
	return bh;

    242 		return PTR_ERR(bh);
    243 
    244 	bbuf->bh = bh;
    245 

regards,
dan carpenter

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [bug report] fs/ntfs3: Add initialization of super block
  2021-08-24  7:58 [bug report] fs/ntfs3: Add initialization of super block Dan Carpenter
@ 2021-08-24 10:33 ` Kari Argillander
  2026-02-09 15:24 ` [PATCH] fs/ntfs3: avoid calling run_get_entry() when run == NULL in ntfs_read_run_nb_ra() Konstantin Komarov
  1 sibling, 0 replies; 5+ messages in thread
From: Kari Argillander @ 2021-08-24 10:33 UTC (permalink / raw)
  To: Dan Carpenter; +Cc: almaz.alexandrovich, ntfs3

On Tue, Aug 24, 2021 at 10:58:19AM +0300, Dan Carpenter wrote:
> Hello Konstantin Komarov,
> 
> The patch 82cae269cfa9: "fs/ntfs3: Add initialization of super block"
> from Aug 13, 2021, leads to the following
> Smatch static checker warning:
> 
> 	fs/ntfs3/index.c:238 bmp_buf_get()
> 	warn: 'bh' could be an error pointer
> 
> fs/ntfs3/index.c
>     229 	data_size = le64_to_cpu(b->nres.data_size);
>     230 	if (WARN_ON(off >= data_size)) {
>     231 		/* looks like filesystem error */
>     232 		return -EINVAL;
>     233 	}
>     234 
>     235 	valid_size = le64_to_cpu(b->nres.valid_size);
>     236 
>     237 	bh = ntfs_bread_run(sbi, &indx->bitmap_run, off);
> --> 238 	if (!bh)
>     239 		return -EIO;
>     240 
>     241 	if (IS_ERR(bh))
> 
> This is not a bug, but it is wrong style.  When a function returns both
> error pointers and NULL then the NULL return is means the feature is
> disabled.  It's not an error.  Just that the feature is turned off
> deliberately in the Kconfig or whatever.  Don't print an error message,
> just continue with the feature disabled as the admin has requested.
> 
> But here NULL is just an error.  The ntfs_bread_run() should do:

Agreed.

> 
> 	bh = ntfs_bread();
> 	if (!bh)
> 		return ERR_PTR(-EIO);
> 	return bh;

Can also be like below but probably your version is more readable.

return ntfs_bread(sb, lbo >> sb->s_blocksize_bits) ? : ERR_PTR(-EIO);

> 
>     242 		return PTR_ERR(bh);
>     243 
>     244 	bbuf->bh = bh;
>     245 
> 
> regards,
> dan carpenter

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [bug report] fs/ntfs3: Add initialization of super block
       [not found] <caa37f28-a2e8-4e0a-a9ce-a365ce805e4b@stanley.mountain>
@ 2026-02-06 13:41 ` Dan Carpenter
  2026-02-09 10:20   ` Konstantin Komarov
  0 siblings, 1 reply; 5+ messages in thread
From: Dan Carpenter @ 2026-02-06 13:41 UTC (permalink / raw)
  To: Konstantin Komarov; +Cc: ntfs3, linux-kernel

[ Smatch checking is paused while we raise funding.  #SadFace
  https://lore.kernel.org/all/aTaiGSbWZ9DJaGo7@stanley.mountain/ -dan ]

Hello Konstantin Komarov,

Commit 82cae269cfa9 ("fs/ntfs3: Add initialization of super block")
from Aug 13, 2021 (linux-next), leads to the following Smatch static
checker warning:

fs/ntfs3/fsntfs.c:1260 ntfs_read_run_nb_ra() error: we previously assumed 'run' could be null (see line 1178)
fs/ntfs3/fsntfs.c:1259 ntfs_read_run_nb_ra() error: uninitialized symbol 'clen'.
fs/ntfs3/fsntfs.c:1260 ntfs_read_run_nb_ra() error: uninitialized symbol 'idx'.

fs/ntfs3/fsntfs.c
    1161 int ntfs_read_run_nb_ra(struct ntfs_sb_info *sbi, const struct runs_tree *run,
    1162                         u64 vbo, void *buf, u32 bytes, struct ntfs_buffers *nb,
    1163                         struct file_ra_state *ra)
    1164 {
    1165         int err;
    1166         struct super_block *sb = sbi->sb;
    1167         struct address_space *mapping = sb->s_bdev->bd_mapping;
    1168         u32 blocksize = sb->s_blocksize;
    1169         u8 cluster_bits = sbi->cluster_bits;
    1170         u32 off = vbo & sbi->cluster_mask;
    1171         u32 nbh = 0;
    1172         CLST vcn_next, vcn = vbo >> cluster_bits;
    1173         CLST lcn, clen;
    1174         u64 lbo, len;
    1175         size_t idx;
    1176         struct buffer_head *bh;
    1177 
    1178         if (!run) {
    1179                 /* First reading of $Volume + $MFTMirr + $LogFile goes here. */
    1180                 if (vbo > MFT_REC_VOL * sbi->record_size) {
    1181                         err = -ENOENT;
    1182                         goto out;
    1183                 }
    1184 
    1185                 /* Use absolute boot's 'MFTCluster' to read record. */
    1186                 lbo = vbo + sbi->mft.lbo;
    1187                 len = sbi->record_size;

If run is NULL then "clen" is uninitialized.

    1188         } else if (!run_lookup_entry(run, vcn, &lcn, &clen, &idx)) {
    1189                 err = -ENOENT;
    1190                 goto out;
    1191         } else {
    1192                 if (lcn == SPARSE_LCN) {
    1193                         err = -EINVAL;
    1194                         goto out;
    1195                 }
    1196 
    1197                 lbo = ((u64)lcn << cluster_bits) + off;
    1198                 len = ((u64)clen << cluster_bits) - off;
    1199         }
    1200 
    1201         off = lbo & (blocksize - 1);
    1202         if (nb) {
    1203                 nb->off = off;
    1204                 nb->bytes = bytes;
    1205         }
    1206 
    1207         if (ra && !ra->ra_pages)
    1208                 file_ra_state_init(ra, mapping);
    1209 
    1210         for (;;) {
    1211                 u32 len32 = len >= bytes ? bytes : len;
    1212                 sector_t block = lbo >> sb->s_blocksize_bits;
    1213 
    1214                 if (ra) {
    1215                         pgoff_t index = lbo >> PAGE_SHIFT;
    1216                         if (!ra_has_index(ra, index)) {
    1217                                 page_cache_sync_readahead(mapping, ra, NULL,
    1218                                                           index, 1);
    1219                                 ra->prev_pos = (loff_t)index << PAGE_SHIFT;
    1220                         }
    1221                 }
    1222 
    1223                 do {
    1224                         u32 op = blocksize - off;
    1225 
    1226                         if (op > len32)
    1227                                 op = len32;
    1228 
    1229                         bh = ntfs_bread(sb, block);
    1230                         if (!bh) {
    1231                                 err = -EIO;
    1232                                 goto out;
    1233                         }
    1234 
    1235                         if (buf) {
    1236                                 memcpy(buf, bh->b_data + off, op);
    1237                                 buf = Add2Ptr(buf, op);
    1238                         }
    1239 
    1240                         if (!nb) {
    1241                                 put_bh(bh);
    1242                         } else if (nbh >= ARRAY_SIZE(nb->bh)) {
    1243                                 err = -EINVAL;
    1244                                 goto out;
    1245                         } else {
    1246                                 nb->bh[nbh++] = bh;
    1247                                 nb->nbufs = nbh;
    1248                         }
    1249 
    1250                         bytes -= op;
    1251                         if (!bytes)
    1252                                 return 0;
    1253                         len32 -= op;
    1254                         block += 1;
    1255                         off = 0;
    1256 
    1257                 } while (len32);
    1258 
--> 1259                 vcn_next = vcn + clen;
                                          ^^^^
Used uninitalized here.

    1260                 if (!run_get_entry(run, ++idx, &vcn, &lcn, &clen) ||

But also if we pass a NULL run to run_get_entry() it will crash.  I'm
a bit confused by this code.

    1261                     vcn != vcn_next) {
    1262                         err = -ENOENT;
    1263                         goto out;
    1264                 }
    1265 
    1266                 if (lcn == SPARSE_LCN) {
    1267                         err = -EINVAL;
    1268                         goto out;
    1269                 }
    1270 
    1271                 lbo = ((u64)lcn << cluster_bits);
    1272                 len = ((u64)clen << cluster_bits);
    1273         }
    1274 
    1275 out:
    1276         if (!nbh)
    1277                 return err;
    1278 
    1279         while (nbh) {
    1280                 put_bh(nb->bh[--nbh]);
    1281                 nb->bh[nbh] = NULL;
    1282         }
    1283 
    1284         nb->nbufs = 0;
    1285         return err;
    1286 }

regards,
dan carpenter

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [bug report] fs/ntfs3: Add initialization of super block
  2026-02-06 13:41 ` [bug report] fs/ntfs3: Add initialization of super block Dan Carpenter
@ 2026-02-09 10:20   ` Konstantin Komarov
  0 siblings, 0 replies; 5+ messages in thread
From: Konstantin Komarov @ 2026-02-09 10:20 UTC (permalink / raw)
  To: Dan Carpenter; +Cc: ntfs3, linux-kernel

On 2/6/26 14:41, Dan Carpenter wrote:

> [ Smatch checking is paused while we raise funding.  #SadFace
>    https://lore.kernel.org/all/aTaiGSbWZ9DJaGo7@stanley.mountain/ -dan ]
>
> Hello Konstantin Komarov,
>
> Commit 82cae269cfa9 ("fs/ntfs3: Add initialization of super block")
> from Aug 13, 2021 (linux-next), leads to the following Smatch static
> checker warning:
>
> fs/ntfs3/fsntfs.c:1260 ntfs_read_run_nb_ra() error: we previously assumed 'run' could be null (see line 1178)
> fs/ntfs3/fsntfs.c:1259 ntfs_read_run_nb_ra() error: uninitialized symbol 'clen'.
> fs/ntfs3/fsntfs.c:1260 ntfs_read_run_nb_ra() error: uninitialized symbol 'idx'.
>
> fs/ntfs3/fsntfs.c
>      1161 int ntfs_read_run_nb_ra(struct ntfs_sb_info *sbi, const struct runs_tree *run,
>      1162                         u64 vbo, void *buf, u32 bytes, struct ntfs_buffers *nb,
>      1163                         struct file_ra_state *ra)
>      1164 {
>      1165         int err;
>      1166         struct super_block *sb = sbi->sb;
>      1167         struct address_space *mapping = sb->s_bdev->bd_mapping;
>      1168         u32 blocksize = sb->s_blocksize;
>      1169         u8 cluster_bits = sbi->cluster_bits;
>      1170         u32 off = vbo & sbi->cluster_mask;
>      1171         u32 nbh = 0;
>      1172         CLST vcn_next, vcn = vbo >> cluster_bits;
>      1173         CLST lcn, clen;
>      1174         u64 lbo, len;
>      1175         size_t idx;
>      1176         struct buffer_head *bh;
>      1177
>      1178         if (!run) {
>      1179                 /* First reading of $Volume + $MFTMirr + $LogFile goes here. */
>      1180                 if (vbo > MFT_REC_VOL * sbi->record_size) {
>      1181                         err = -ENOENT;
>      1182                         goto out;
>      1183                 }
>      1184
>      1185                 /* Use absolute boot's 'MFTCluster' to read record. */
>      1186                 lbo = vbo + sbi->mft.lbo;
>      1187                 len = sbi->record_size;
>
> If run is NULL then "clen" is uninitialized.
>
>      1188         } else if (!run_lookup_entry(run, vcn, &lcn, &clen, &idx)) {
>      1189                 err = -ENOENT;
>      1190                 goto out;
>      1191         } else {
>      1192                 if (lcn == SPARSE_LCN) {
>      1193                         err = -EINVAL;
>      1194                         goto out;
>      1195                 }
>      1196
>      1197                 lbo = ((u64)lcn << cluster_bits) + off;
>      1198                 len = ((u64)clen << cluster_bits) - off;
>      1199         }
>      1200
>      1201         off = lbo & (blocksize - 1);
>      1202         if (nb) {
>      1203                 nb->off = off;
>      1204                 nb->bytes = bytes;
>      1205         }
>      1206
>      1207         if (ra && !ra->ra_pages)
>      1208                 file_ra_state_init(ra, mapping);
>      1209
>      1210         for (;;) {
>      1211                 u32 len32 = len >= bytes ? bytes : len;
>      1212                 sector_t block = lbo >> sb->s_blocksize_bits;
>      1213
>      1214                 if (ra) {
>      1215                         pgoff_t index = lbo >> PAGE_SHIFT;
>      1216                         if (!ra_has_index(ra, index)) {
>      1217                                 page_cache_sync_readahead(mapping, ra, NULL,
>      1218                                                           index, 1);
>      1219                                 ra->prev_pos = (loff_t)index << PAGE_SHIFT;
>      1220                         }
>      1221                 }
>      1222
>      1223                 do {
>      1224                         u32 op = blocksize - off;
>      1225
>      1226                         if (op > len32)
>      1227                                 op = len32;
>      1228
>      1229                         bh = ntfs_bread(sb, block);
>      1230                         if (!bh) {
>      1231                                 err = -EIO;
>      1232                                 goto out;
>      1233                         }
>      1234
>      1235                         if (buf) {
>      1236                                 memcpy(buf, bh->b_data + off, op);
>      1237                                 buf = Add2Ptr(buf, op);
>      1238                         }
>      1239
>      1240                         if (!nb) {
>      1241                                 put_bh(bh);
>      1242                         } else if (nbh >= ARRAY_SIZE(nb->bh)) {
>      1243                                 err = -EINVAL;
>      1244                                 goto out;
>      1245                         } else {
>      1246                                 nb->bh[nbh++] = bh;
>      1247                                 nb->nbufs = nbh;
>      1248                         }
>      1249
>      1250                         bytes -= op;
>      1251                         if (!bytes)
>      1252                                 return 0;
>      1253                         len32 -= op;
>      1254                         block += 1;
>      1255                         off = 0;
>      1256
>      1257                 } while (len32);
>      1258
> --> 1259                 vcn_next = vcn + clen;
>                                            ^^^^
> Used uninitalized here.
>
>      1260                 if (!run_get_entry(run, ++idx, &vcn, &lcn, &clen) ||
>
> But also if we pass a NULL run to run_get_entry() it will crash.  I'm
> a bit confused by this code.
>
>      1261                     vcn != vcn_next) {
>      1262                         err = -ENOENT;
>      1263                         goto out;
>      1264                 }
>      1265
>      1266                 if (lcn == SPARSE_LCN) {
>      1267                         err = -EINVAL;
>      1268                         goto out;
>      1269                 }
>      1270
>      1271                 lbo = ((u64)lcn << cluster_bits);
>      1272                 len = ((u64)clen << cluster_bits);
>      1273         }
>      1274
>      1275 out:
>      1276         if (!nbh)
>      1277                 return err;
>      1278
>      1279         while (nbh) {
>      1280                 put_bh(nb->bh[--nbh]);
>      1281                 nb->bh[nbh] = NULL;
>      1282         }
>      1283
>      1284         nb->nbufs = 0;
>      1285         return err;
>      1286 }
>
> regards,
> dan carpenter

Hello,

Thanks for the Smatch report. I’ll examine the warnings, prepare a fix,
and post a patch.

Regards,
Konstantin


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH] fs/ntfs3: avoid calling run_get_entry() when run == NULL in ntfs_read_run_nb_ra()
  2021-08-24  7:58 [bug report] fs/ntfs3: Add initialization of super block Dan Carpenter
  2021-08-24 10:33 ` Kari Argillander
@ 2026-02-09 15:24 ` Konstantin Komarov
  1 sibling, 0 replies; 5+ messages in thread
From: Konstantin Komarov @ 2026-02-09 15:24 UTC (permalink / raw)
  To: ntfs3
  Cc: linux-kernel, linux-fsdevel, Konstantin Komarov,
	kernel test robot, Dan Carpenter

When ntfs_read_run_nb_ra() is invoked with run == NULL the code later
assumes run is valid and may call run_get_entry(NULL, ...), and also
uses clen/idx without initializing them. Smatch reported uninitialized
variable warnings and this can lead to undefined behaviour. This patch
fixes it.

Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
Closes: https://lore.kernel.org/r/202512230646.v5hrYXL0-lkp@intel.com/
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
---
 fs/ntfs3/fsntfs.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c
index e9c39c62aea4..2ef500f1a9fa 100644
--- a/fs/ntfs3/fsntfs.c
+++ b/fs/ntfs3/fsntfs.c
@@ -1256,6 +1256,12 @@ int ntfs_read_run_nb_ra(struct ntfs_sb_info *sbi, const struct runs_tree *run,
 
 		} while (len32);
 
+		if (!run) {
+			err = -EINVAL;
+			goto out;
+		}
+
+		/* Get next fragment to read. */
 		vcn_next = vcn + clen;
 		if (!run_get_entry(run, ++idx, &vcn, &lcn, &clen) ||
 		    vcn != vcn_next) {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-02-09 15:24 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-08-24  7:58 [bug report] fs/ntfs3: Add initialization of super block Dan Carpenter
2021-08-24 10:33 ` Kari Argillander
2026-02-09 15:24 ` [PATCH] fs/ntfs3: avoid calling run_get_entry() when run == NULL in ntfs_read_run_nb_ra() Konstantin Komarov
     [not found] <caa37f28-a2e8-4e0a-a9ce-a365ce805e4b@stanley.mountain>
2026-02-06 13:41 ` [bug report] fs/ntfs3: Add initialization of super block Dan Carpenter
2026-02-09 10:20   ` Konstantin Komarov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox