Hello Linux maintainers! I hope this message finds you well. Apologies for taking up your time. I recently noticed that the bug I reported (https://lore.kernel.org/linux-xfs/CAEJPjCvT3Uag-pMTYuigEjWZHn1sGMZ0GCjVVCv29tNHK76Cgg@xxxxxxxxxxxxxx/) has been fixed and merged into the main branch—thank you for your hard work! I was wondering if it would be possible to receive a CVE number for this issue. I'm not familiar with how Linux handles CVE assignments. I would greatly appreciate it if you could either assign a CVE or simply reply to this email. Thank you! Best regards, Tong 刘通 <lyutoon@xxxxxxxxx> 于2024年5月6日周一 20:39写道: > > Hello! > > Thank you for promptly fixing this issue. May I ask if it's possible > to assign a CVE to this vulnerability? > Once again, thank you for your efforts in fixing this vulnerability! > > Wish you all the best. > > Tong > > > 刘通 <lyutoon@xxxxxxxxx> 于2024年5月6日周一 20:24写道: > > > > Hello! > > > > Thank you for promptly fixing this issue. May I ask if it's possible to assign a CVE to this vulnerability? > > Once again, thank you for your efforts in fixing this vulnerability! > > > > Wish you all the best. > > > > Tong > > > > Christoph Hellwig <hch@xxxxxx> 于2024年4月29日周一 14:15写道: > >> > >> xfs_bmapi_write can return 0 without actually returning a mapping in > >> mval in two different cases: > >> > >> 1) when there is absolutely no space available to do an allocation > >> 2) when converting delalloc space, and the allocation is so small > >> that it only covers parts of the delalloc extent before the > >> range requested by the caller > >> > >> Callers at best can handle one of these cases, but in many cases can't > >> cope with either one. Switch xfs_bmapi_write to always return a > >> mapping or return an error code instead. For case 1) above ENOSPC is > >> the obvious choice which is very much what the callers expect anyway. > >> For case 2) there is no really good error code, so pick a funky one > >> from the SysV streams portfolio. > >> > >> This fixes the reproducer here: > >> > >> https://lore.kernel.org/linux-xfs/CAEJPjCvT3Uag-pMTYuigEjWZHn1sGMZ0GCjVVCv29tNHK76Cgg@mail.gmail.com0/ > >> > >> which uses reserved blocks to create file systems that are gravely > >> out of space and thus cause at least xfs_file_alloc_space to hang > >> and trigger the lack of ENOSPC handling in xfs_dquot_disk_alloc. > >> > >> Note that this patch does not actually make any caller but > >> xfs_alloc_file_space deal intelligently with case 2) above. > >> > >> Signed-off-by: Christoph Hellwig <hch@xxxxxx> > >> Reported-by: 刘通 <lyutoon@xxxxxxxxx> > >> Reviewed-by: Darrick J. Wong <djwong@xxxxxxxxxx> > >> --- > >> fs/xfs/libxfs/xfs_attr_remote.c | 1 - > >> fs/xfs/libxfs/xfs_bmap.c | 46 ++++++++++++++++++++++++++------- > >> fs/xfs/libxfs/xfs_da_btree.c | 20 ++++---------- > >> fs/xfs/scrub/quota_repair.c | 6 ----- > >> fs/xfs/scrub/rtbitmap_repair.c | 2 -- > >> fs/xfs/xfs_bmap_util.c | 31 +++++++++++----------- > >> fs/xfs/xfs_dquot.c | 1 - > >> fs/xfs/xfs_iomap.c | 8 ------ > >> fs/xfs/xfs_reflink.c | 14 ---------- > >> fs/xfs/xfs_rtalloc.c | 2 -- > >> 10 files changed, 57 insertions(+), 74 deletions(-) > >> > >> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c > >> index a8de9dc1e998a3..beb0efdd8f6b83 100644 > >> --- a/fs/xfs/libxfs/xfs_attr_remote.c > >> +++ b/fs/xfs/libxfs/xfs_attr_remote.c > >> @@ -625,7 +625,6 @@ xfs_attr_rmtval_set_blk( > >> if (error) > >> return error; > >> > >> - ASSERT(nmap == 1); > >> ASSERT((map->br_startblock != DELAYSTARTBLOCK) && > >> (map->br_startblock != HOLESTARTBLOCK)); > >> > >> diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c > >> index 6053f5e5c71eec..f19191d6eade7e 100644 > >> --- a/fs/xfs/libxfs/xfs_bmap.c > >> +++ b/fs/xfs/libxfs/xfs_bmap.c > >> @@ -4217,8 +4217,10 @@ xfs_bmapi_allocate( > >> } else { > >> error = xfs_bmap_alloc_userdata(bma); > >> } > >> - if (error || bma->blkno == NULLFSBLOCK) > >> + if (error) > >> return error; > >> + if (bma->blkno == NULLFSBLOCK) > >> + return -ENOSPC; > >> > >> if (bma->flags & XFS_BMAPI_ZERO) { > >> error = xfs_zero_extent(bma->ip, bma->blkno, bma->length); > >> @@ -4397,6 +4399,15 @@ xfs_bmapi_finish( > >> * extent state if necessary. Details behaviour is controlled by the flags > >> * parameter. Only allocates blocks from a single allocation group, to avoid > >> * locking problems. > >> + * > >> + * Returns 0 on success and places the extent mappings in mval. nmaps is used > >> + * as an input/output parameter where the caller specifies the maximum number > >> + * of mappings that may be returned and xfs_bmapi_write passes back the number > >> + * of mappings (including existing mappings) it found. > >> + * > >> + * Returns a negative error code on failure, including -ENOSPC when it could not > >> + * allocate any blocks and -ENOSR when it did allocate blocks to convert a > >> + * delalloc range, but those blocks were before the passed in range. > >> */ > >> int > >> xfs_bmapi_write( > >> @@ -4525,10 +4536,16 @@ xfs_bmapi_write( > >> ASSERT(len > 0); > >> ASSERT(bma.length > 0); > >> error = xfs_bmapi_allocate(&bma); > >> - if (error) > >> + if (error) { > >> + /* > >> + * If we already allocated space in a previous > >> + * iteration return what we go so far when > >> + * running out of space. > >> + */ > >> + if (error == -ENOSPC && bma.nallocs) > >> + break; > >> goto error0; > >> - if (bma.blkno == NULLFSBLOCK) > >> - break; > >> + } > >> > >> /* > >> * If this is a CoW allocation, record the data in > >> @@ -4566,7 +4583,6 @@ xfs_bmapi_write( > >> if (!xfs_iext_next_extent(ifp, &bma.icur, &bma.got)) > >> eof = true; > >> } > >> - *nmap = n; > >> > >> error = xfs_bmap_btree_to_extents(tp, ip, bma.cur, &bma.logflags, > >> whichfork); > >> @@ -4577,7 +4593,22 @@ xfs_bmapi_write( > >> ifp->if_nextents > XFS_IFORK_MAXEXT(ip, whichfork)); > >> xfs_bmapi_finish(&bma, whichfork, 0); > >> xfs_bmap_validate_ret(orig_bno, orig_len, orig_flags, orig_mval, > >> - orig_nmap, *nmap); > >> + orig_nmap, n); > >> + > >> + /* > >> + * When converting delayed allocations, xfs_bmapi_allocate ignores > >> + * the passed in bno and always converts from the start of the found > >> + * delalloc extent. > >> + * > >> + * To avoid a successful return with *nmap set to 0, return the magic > >> + * -ENOSR error code for this particular case so that the caller can > >> + * handle it. > >> + */ > >> + if (!n) { > >> + ASSERT(bma.nallocs >= *nmap); > >> + return -ENOSR; > >> + } > >> + *nmap = n; > >> return 0; > >> error0: > >> xfs_bmapi_finish(&bma, whichfork, error); > >> @@ -4684,9 +4715,6 @@ xfs_bmapi_convert_delalloc( > >> if (error) > >> goto out_finish; > >> > >> - error = -ENOSPC; > >> - if (WARN_ON_ONCE(bma.blkno == NULLFSBLOCK)) > >> - goto out_finish; > >> if (WARN_ON_ONCE(!xfs_valid_startblock(ip, bma.got.br_startblock))) { > >> xfs_bmap_mark_sick(ip, whichfork); > >> error = -EFSCORRUPTED; > >> diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c > >> index b13796629e2213..16a529a8878083 100644 > >> --- a/fs/xfs/libxfs/xfs_da_btree.c > >> +++ b/fs/xfs/libxfs/xfs_da_btree.c > >> @@ -2297,8 +2297,8 @@ xfs_da_grow_inode_int( > >> struct xfs_inode *dp = args->dp; > >> int w = args->whichfork; > >> xfs_rfsblock_t nblks = dp->i_nblocks; > >> - struct xfs_bmbt_irec map, *mapp; > >> - int nmap, error, got, i, mapi; > >> + struct xfs_bmbt_irec map, *mapp = ↦ > >> + int nmap, error, got, i, mapi = 1; > >> > >> /* > >> * Find a spot in the file space to put the new block. > >> @@ -2314,14 +2314,7 @@ xfs_da_grow_inode_int( > >> error = xfs_bmapi_write(tp, dp, *bno, count, > >> xfs_bmapi_aflag(w)|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG, > >> args->total, &map, &nmap); > >> - if (error) > >> - return error; > >> - > >> - ASSERT(nmap <= 1); > >> - if (nmap == 1) { > >> - mapp = ↦ > >> - mapi = 1; > >> - } else if (nmap == 0 && count > 1) { > >> + if (error == -ENOSPC && count > 1) { > >> xfs_fileoff_t b; > >> int c; > >> > >> @@ -2339,16 +2332,13 @@ xfs_da_grow_inode_int( > >> args->total, &mapp[mapi], &nmap); > >> if (error) > >> goto out_free_map; > >> - if (nmap < 1) > >> - break; > >> mapi += nmap; > >> b = mapp[mapi - 1].br_startoff + > >> mapp[mapi - 1].br_blockcount; > >> } > >> - } else { > >> - mapi = 0; > >> - mapp = NULL; > >> } > >> + if (error) > >> + goto out_free_map; > >> > >> /* > >> * Count the blocks we got, make sure it matches the total. > >> diff --git a/fs/xfs/scrub/quota_repair.c b/fs/xfs/scrub/quota_repair.c > >> index 0bab4c30cb85ab..90cd1512bba961 100644 > >> --- a/fs/xfs/scrub/quota_repair.c > >> +++ b/fs/xfs/scrub/quota_repair.c > >> @@ -77,8 +77,6 @@ xrep_quota_item_fill_bmap_hole( > >> irec, &nmaps); > >> if (error) > >> return error; > >> - if (nmaps != 1) > >> - return -ENOSPC; > >> > >> dq->q_blkno = XFS_FSB_TO_DADDR(mp, irec->br_startblock); > >> > >> @@ -444,10 +442,6 @@ xrep_quota_data_fork( > >> XFS_BMAPI_CONVERT, 0, &nrec, &nmap); > >> if (error) > >> goto out; > >> - if (nmap != 1) { > >> - error = -ENOSPC; > >> - goto out; > >> - } > >> ASSERT(nrec.br_startoff == irec.br_startoff); > >> ASSERT(nrec.br_blockcount == irec.br_blockcount); > >> > >> diff --git a/fs/xfs/scrub/rtbitmap_repair.c b/fs/xfs/scrub/rtbitmap_repair.c > >> index 46f5d5f605c915..0fef98e9f83409 100644 > >> --- a/fs/xfs/scrub/rtbitmap_repair.c > >> +++ b/fs/xfs/scrub/rtbitmap_repair.c > >> @@ -108,8 +108,6 @@ xrep_rtbitmap_data_mappings( > >> 0, &map, &nmaps); > >> if (error) > >> return error; > >> - if (nmaps != 1) > >> - return -EFSCORRUPTED; > >> > >> /* Commit new extent and all deferred work. */ > >> error = xrep_defer_finish(sc); > >> diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c > >> index 53aa90a0ee3a85..2e6f08198c0719 100644 > >> --- a/fs/xfs/xfs_bmap_util.c > >> +++ b/fs/xfs/xfs_bmap_util.c > >> @@ -721,33 +721,32 @@ xfs_alloc_file_space( > >> if (error) > >> goto error; > >> > >> - error = xfs_bmapi_write(tp, ip, startoffset_fsb, > >> - allocatesize_fsb, XFS_BMAPI_PREALLOC, 0, imapp, > >> - &nimaps); > >> - if (error) > >> - goto error; > >> - > >> - ip->i_diflags |= XFS_DIFLAG_PREALLOC; > >> - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); > >> - > >> - error = xfs_trans_commit(tp); > >> - xfs_iunlock(ip, XFS_ILOCK_EXCL); > >> - if (error) > >> - break; > >> - > >> /* > >> * If the allocator cannot find a single free extent large > >> * enough to cover the start block of the requested range, > >> - * xfs_bmapi_write will return 0 but leave *nimaps set to 0. > >> + * xfs_bmapi_write will return -ENOSR. > >> * > >> * In that case we simply need to keep looping with the same > >> * startoffset_fsb so that one of the following allocations > >> * will eventually reach the requested range. > >> */ > >> - if (nimaps) { > >> + error = xfs_bmapi_write(tp, ip, startoffset_fsb, > >> + allocatesize_fsb, XFS_BMAPI_PREALLOC, 0, imapp, > >> + &nimaps); > >> + if (error) { > >> + if (error != -ENOSR) > >> + goto error; > >> + error = 0; > >> + } else { > >> startoffset_fsb += imapp->br_blockcount; > >> allocatesize_fsb -= imapp->br_blockcount; > >> } > >> + > >> + ip->i_diflags |= XFS_DIFLAG_PREALLOC; > >> + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); > >> + > >> + error = xfs_trans_commit(tp); > >> + xfs_iunlock(ip, XFS_ILOCK_EXCL); > >> } > >> > >> return error; > >> diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c > >> index 13aba84bd64afb..43acb4f0d17433 100644 > >> --- a/fs/xfs/xfs_dquot.c > >> +++ b/fs/xfs/xfs_dquot.c > >> @@ -357,7 +357,6 @@ xfs_dquot_disk_alloc( > >> goto err_cancel; > >> > >> ASSERT(map.br_blockcount == XFS_DQUOT_CLUSTER_SIZE_FSB); > >> - ASSERT(nmaps == 1); > >> ASSERT((map.br_startblock != DELAYSTARTBLOCK) && > >> (map.br_startblock != HOLESTARTBLOCK)); > >> > >> diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c > >> index 9ce0f6b9df93e6..60463160820b62 100644 > >> --- a/fs/xfs/xfs_iomap.c > >> +++ b/fs/xfs/xfs_iomap.c > >> @@ -322,14 +322,6 @@ xfs_iomap_write_direct( > >> if (error) > >> goto out_unlock; > >> > >> - /* > >> - * Copy any maps to caller's array and return any error. > >> - */ > >> - if (nimaps == 0) { > >> - error = -ENOSPC; > >> - goto out_unlock; > >> - } > >> - > >> if (unlikely(!xfs_valid_startblock(ip, imap->br_startblock))) { > >> xfs_bmap_mark_sick(ip, XFS_DATA_FORK); > >> error = xfs_alert_fsblock_zero(ip, imap); > >> diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c > >> index 7da0e8f961d351..5ecb52a234becc 100644 > >> --- a/fs/xfs/xfs_reflink.c > >> +++ b/fs/xfs/xfs_reflink.c > >> @@ -430,13 +430,6 @@ xfs_reflink_fill_cow_hole( > >> if (error) > >> return error; > >> > >> - /* > >> - * Allocation succeeded but the requested range was not even partially > >> - * satisfied? Bail out! > >> - */ > >> - if (nimaps == 0) > >> - return -ENOSPC; > >> - > >> convert: > >> return xfs_reflink_convert_unwritten(ip, imap, cmap, convert_now); > >> > >> @@ -499,13 +492,6 @@ xfs_reflink_fill_delalloc( > >> error = xfs_trans_commit(tp); > >> if (error) > >> return error; > >> - > >> - /* > >> - * Allocation succeeded but the requested range was not even > >> - * partially satisfied? Bail out! > >> - */ > >> - if (nimaps == 0) > >> - return -ENOSPC; > >> } while (cmap->br_startoff + cmap->br_blockcount <= imap->br_startoff); > >> > >> return xfs_reflink_convert_unwritten(ip, imap, cmap, convert_now); > >> diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c > >> index b476a876478d93..150f544445ca82 100644 > >> --- a/fs/xfs/xfs_rtalloc.c > >> +++ b/fs/xfs/xfs_rtalloc.c > >> @@ -709,8 +709,6 @@ xfs_growfs_rt_alloc( > >> nmap = 1; > >> error = xfs_bmapi_write(tp, ip, oblocks, nblocks - oblocks, > >> XFS_BMAPI_METADATA, 0, &map, &nmap); > >> - if (!error && nmap < 1) > >> - error = -ENOSPC; > >> if (error) > >> goto out_trans_cancel; > >> /* > >> -- > >> 2.39.2 > >>