Fix a regression in the lazytime code that was introduced in v6.1-rc1,

and a use-after-free that can be triggered by a maliciously corrupted
 file system.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEEK2m5VNv+CHkogTfJ8vlZVpUNgaMFAmN+1NoACgkQ8vlZVpUN
 gaNY8Qf/ZJyI8JZTEyrd7KxM1S6eDwUth1kYsQQtqQojd5tTqYOsslSiTp2Yw+LI
 4Gw75tDiMA6CYt+BuvbbgOk36YXaPW69sB+uParL/hgK005R50raQZ7oMdjQba4Z
 ODa+x27r5SVZIrcEAcHX15+BcjeCDZ/e5RMsV37ww+LsKNlnWNYn4o3S6eIv1ERo
 0iqgasbaaATCy37gStRvtnbsyPWDdwL5XlJg0XnqFLzo6Yz1NMcXaxEZehyCaCSc
 SixkjSR1gafQu/0ZTdVaH1vXQPmFwCEMOGONdbb+FrQGnIBFv/kvgXeTKTkjOP1+
 2GV7UgdPXeUNECTrMBieEpxsLqpcZw==
 =8ya6
 -----END PGP SIGNATURE-----

Merge tag 'ext4_for_linus_stable2' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4

Pull ext4 fixes from Ted Ts'o:
 "Fix a regression in the lazytime code that was introduced in v6.1-rc1,
  and a use-after-free that can be triggered by a maliciously corrupted
  file system"

* tag 'ext4_for_linus_stable2' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
  fs: do not update freeing inode i_io_list
  ext4: fix use-after-free in ext4_ext_shift_extents
This commit is contained in:
Linus Torvalds 2022-11-24 10:22:42 -08:00
commit 6fd2152fd1
2 changed files with 32 additions and 16 deletions

View file

@ -5184,6 +5184,7 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
* and it is decreased till we reach start.
*/
again:
ret = 0;
if (SHIFT == SHIFT_LEFT)
iterator = &start;
else
@ -5227,14 +5228,21 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
ext4_ext_get_actual_len(extent);
} else {
extent = EXT_FIRST_EXTENT(path[depth].p_hdr);
if (le32_to_cpu(extent->ee_block) > 0)
if (le32_to_cpu(extent->ee_block) > start)
*iterator = le32_to_cpu(extent->ee_block) - 1;
else
/* Beginning is reached, end of the loop */
else if (le32_to_cpu(extent->ee_block) == start)
iterator = NULL;
/* Update path extent in case we need to stop */
while (le32_to_cpu(extent->ee_block) < start)
else {
extent = EXT_LAST_EXTENT(path[depth].p_hdr);
while (le32_to_cpu(extent->ee_block) >= start)
extent--;
if (extent == EXT_LAST_EXTENT(path[depth].p_hdr))
break;
extent++;
iterator = NULL;
}
path[depth].p_ext = extent;
}
ret = ext4_ext_shift_path_extents(path, shift, inode,

View file

@ -1712,18 +1712,26 @@ static int writeback_single_inode(struct inode *inode,
wb = inode_to_wb_and_lock_list(inode);
spin_lock(&inode->i_lock);
/*
* If the inode is now fully clean, then it can be safely removed from
* its writeback list (if any). Otherwise the flusher threads are
* responsible for the writeback lists.
* If the inode is freeing, its i_io_list shoudn't be updated
* as it can be finally deleted at this moment.
*/
if (!(inode->i_state & I_DIRTY_ALL))
inode_cgwb_move_to_attached(inode, wb);
else if (!(inode->i_state & I_SYNC_QUEUED)) {
if ((inode->i_state & I_DIRTY))
redirty_tail_locked(inode, wb);
else if (inode->i_state & I_DIRTY_TIME) {
inode->dirtied_when = jiffies;
inode_io_list_move_locked(inode, wb, &wb->b_dirty_time);
if (!(inode->i_state & I_FREEING)) {
/*
* If the inode is now fully clean, then it can be safely
* removed from its writeback list (if any). Otherwise the
* flusher threads are responsible for the writeback lists.
*/
if (!(inode->i_state & I_DIRTY_ALL))
inode_cgwb_move_to_attached(inode, wb);
else if (!(inode->i_state & I_SYNC_QUEUED)) {
if ((inode->i_state & I_DIRTY))
redirty_tail_locked(inode, wb);
else if (inode->i_state & I_DIRTY_TIME) {
inode->dirtied_when = jiffies;
inode_io_list_move_locked(inode,
wb,
&wb->b_dirty_time);
}
}
}