Skip to content

Commit c226964

Browse files
Zhao Mengmengjankara
authored andcommitted
udf: refactor inode_bmap() to handle error
Refactor inode_bmap() to handle error since udf_next_aext() can return error now. On situations like ftruncate, udf_extend_file() can now detect errors and bail out early without resorting to checking for particular offsets and assuming internal behavior of these functions. Reported-by: [email protected] Closes: https://syzkaller.appspot.com/bug?extid=7a4842f0b1801230a989 Tested-by: [email protected] Signed-off-by: Zhao Mengmeng <[email protected]> Suggested-by: Jan Kara <[email protected]> Signed-off-by: Jan Kara <[email protected]> Link: https://patch.msgid.link/[email protected]
1 parent b405c1e commit c226964

File tree

5 files changed

+44
-26
lines changed

5 files changed

+44
-26
lines changed

fs/udf/directory.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir,
246246
{
247247
struct udf_inode_info *iinfo = UDF_I(dir);
248248
int err = 0;
249+
int8_t etype;
249250

250251
iter->dir = dir;
251252
iter->bh[0] = iter->bh[1] = NULL;
@@ -265,9 +266,9 @@ int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir,
265266
goto out;
266267
}
267268

268-
if (inode_bmap(dir, iter->pos >> dir->i_blkbits, &iter->epos,
269-
&iter->eloc, &iter->elen, &iter->loffset) !=
270-
(EXT_RECORDED_ALLOCATED >> 30)) {
269+
err = inode_bmap(dir, iter->pos >> dir->i_blkbits, &iter->epos,
270+
&iter->eloc, &iter->elen, &iter->loffset, &etype);
271+
if (err <= 0 || etype != (EXT_RECORDED_ALLOCATED >> 30)) {
271272
if (pos == dir->i_size)
272273
return 0;
273274
udf_err(dir->i_sb,
@@ -463,6 +464,7 @@ int udf_fiiter_append_blk(struct udf_fileident_iter *iter)
463464
sector_t block;
464465
uint32_t old_elen = iter->elen;
465466
int err;
467+
int8_t etype;
466468

467469
if (WARN_ON_ONCE(iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB))
468470
return -EINVAL;
@@ -477,8 +479,9 @@ int udf_fiiter_append_blk(struct udf_fileident_iter *iter)
477479
udf_fiiter_update_elen(iter, old_elen);
478480
return err;
479481
}
480-
if (inode_bmap(iter->dir, block, &iter->epos, &iter->eloc, &iter->elen,
481-
&iter->loffset) != (EXT_RECORDED_ALLOCATED >> 30)) {
482+
err = inode_bmap(iter->dir, block, &iter->epos, &iter->eloc, &iter->elen,
483+
&iter->loffset, &etype);
484+
if (err <= 0 || etype != (EXT_RECORDED_ALLOCATED >> 30)) {
482485
udf_err(iter->dir->i_sb,
483486
"block %llu not allocated in directory (ino %lu)\n",
484487
(unsigned long long)block, iter->dir->i_ino);

fs/udf/inode.c

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ struct udf_map_rq {
404404

405405
static int udf_map_block(struct inode *inode, struct udf_map_rq *map)
406406
{
407-
int err;
407+
int ret;
408408
struct udf_inode_info *iinfo = UDF_I(inode);
409409

410410
if (WARN_ON_ONCE(iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB))
@@ -416,18 +416,24 @@ static int udf_map_block(struct inode *inode, struct udf_map_rq *map)
416416
uint32_t elen;
417417
sector_t offset;
418418
struct extent_position epos = {};
419+
int8_t etype;
419420

420421
down_read(&iinfo->i_data_sem);
421-
if (inode_bmap(inode, map->lblk, &epos, &eloc, &elen, &offset)
422-
== (EXT_RECORDED_ALLOCATED >> 30)) {
422+
ret = inode_bmap(inode, map->lblk, &epos, &eloc, &elen, &offset,
423+
&etype);
424+
if (ret < 0)
425+
goto out_read;
426+
if (ret > 0 && etype == (EXT_RECORDED_ALLOCATED >> 30)) {
423427
map->pblk = udf_get_lb_pblock(inode->i_sb, &eloc,
424428
offset);
425429
map->oflags |= UDF_BLK_MAPPED;
430+
ret = 0;
426431
}
432+
out_read:
427433
up_read(&iinfo->i_data_sem);
428434
brelse(epos.bh);
429435

430-
return 0;
436+
return ret;
431437
}
432438

433439
down_write(&iinfo->i_data_sem);
@@ -438,9 +444,9 @@ static int udf_map_block(struct inode *inode, struct udf_map_rq *map)
438444
if (((loff_t)map->lblk) << inode->i_blkbits >= iinfo->i_lenExtents)
439445
udf_discard_prealloc(inode);
440446
udf_clear_extent_cache(inode);
441-
err = inode_getblk(inode, map);
447+
ret = inode_getblk(inode, map);
442448
up_write(&iinfo->i_data_sem);
443-
return err;
449+
return ret;
444450
}
445451

446452
static int __udf_get_block(struct inode *inode, sector_t block,
@@ -662,8 +668,10 @@ static int udf_extend_file(struct inode *inode, loff_t newsize)
662668
*/
663669
udf_discard_prealloc(inode);
664670

665-
etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
666-
within_last_ext = (etype != -1);
671+
err = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset, &etype);
672+
if (err < 0)
673+
goto out;
674+
within_last_ext = (err == 1);
667675
/* We don't expect extents past EOF... */
668676
WARN_ON_ONCE(within_last_ext &&
669677
elen > ((loff_t)offset + 1) << inode->i_blkbits);
@@ -2401,13 +2409,15 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos)
24012409
return (elen >> 30);
24022410
}
24032411

2404-
int8_t inode_bmap(struct inode *inode, sector_t block,
2405-
struct extent_position *pos, struct kernel_lb_addr *eloc,
2406-
uint32_t *elen, sector_t *offset)
2412+
/*
2413+
* Returns 1 on success, -errno on error, 0 on hit EOF.
2414+
*/
2415+
int inode_bmap(struct inode *inode, sector_t block, struct extent_position *pos,
2416+
struct kernel_lb_addr *eloc, uint32_t *elen, sector_t *offset,
2417+
int8_t *etype)
24072418
{
24082419
unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits;
24092420
loff_t lbcount = 0, bcount = (loff_t) block << blocksize_bits;
2410-
int8_t etype;
24112421
struct udf_inode_info *iinfo;
24122422
int err = 0;
24132423

@@ -2419,19 +2429,19 @@ int8_t inode_bmap(struct inode *inode, sector_t block,
24192429
}
24202430
*elen = 0;
24212431
do {
2422-
err = udf_next_aext(inode, pos, eloc, elen, &etype, 1);
2432+
err = udf_next_aext(inode, pos, eloc, elen, etype, 1);
24232433
if (err <= 0) {
24242434
if (err == 0) {
24252435
*offset = (bcount - lbcount) >> blocksize_bits;
24262436
iinfo->i_lenExtents = lbcount;
24272437
}
2428-
return -1;
2438+
return err;
24292439
}
24302440
lbcount += *elen;
24312441
} while (lbcount <= bcount);
24322442
/* update extent cache */
24332443
udf_update_extent_cache(inode, lbcount - *elen, pos);
24342444
*offset = (bcount + *elen - lbcount) >> blocksize_bits;
24352445

2436-
return etype;
2446+
return 1;
24372447
}

fs/udf/partition.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,9 +282,11 @@ static uint32_t udf_try_read_meta(struct inode *inode, uint32_t block,
282282
sector_t ext_offset;
283283
struct extent_position epos = {};
284284
uint32_t phyblock;
285+
int8_t etype;
286+
int err = 0;
285287

286-
if (inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset) !=
287-
(EXT_RECORDED_ALLOCATED >> 30))
288+
err = inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset, &etype);
289+
if (err <= 0 || etype != (EXT_RECORDED_ALLOCATED >> 30))
288290
phyblock = 0xFFFFFFFF;
289291
else {
290292
map = &UDF_SB(sb)->s_partmaps[partition];

fs/udf/truncate.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,10 +214,12 @@ int udf_truncate_extents(struct inode *inode)
214214
else
215215
BUG();
216216

217-
etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
217+
ret = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset, &etype);
218+
if (ret < 0)
219+
return ret;
218220
byte_offset = (offset << sb->s_blocksize_bits) +
219221
(inode->i_size & (sb->s_blocksize - 1));
220-
if (etype == -1) {
222+
if (ret == 0) {
221223
/* We should extend the file? */
222224
WARN_ON(byte_offset);
223225
return 0;

fs/udf/udfdecl.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,9 @@ extern struct buffer_head *udf_bread(struct inode *inode, udf_pblk_t block,
157157
extern int udf_setsize(struct inode *, loff_t);
158158
extern void udf_evict_inode(struct inode *);
159159
extern int udf_write_inode(struct inode *, struct writeback_control *wbc);
160-
extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *,
161-
struct kernel_lb_addr *, uint32_t *, sector_t *);
160+
extern int inode_bmap(struct inode *inode, sector_t block,
161+
struct extent_position *pos, struct kernel_lb_addr *eloc,
162+
uint32_t *elen, sector_t *offset, int8_t *etype);
162163
int udf_get_block(struct inode *, sector_t, struct buffer_head *, int);
163164
extern int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block,
164165
struct extent_position *epos);

0 commit comments

Comments
 (0)