Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fs: jfs: fix shift-out-of-bounds in dbAllocAG

Syzbot found a crash : UBSAN: shift-out-of-bounds in dbAllocAG. The
underlying bug is the missing check of bmp->db_agl2size. The field can
be greater than 64 and trigger the shift-out-of-bounds.

Fix this bug by adding a check of bmp->db_agl2size in dbMount since this
field is used in many following functions. The upper bound for this
field is L2MAXL2SIZE - L2MAXAG, thanks for the help of Dave Kleikamp.
Note that, for maintenance, I reorganized error handling code of dbMount.

Reported-by: syzbot+15342c1aa6a00fb7a438@syzkaller.appspotmail.com
Signed-off-by: Dongliang Mu <mudongliangabcd@gmail.com>
Signed-off-by: Dave Kleikamp <dave.kleikamp@oracle.com>

authored by

Dongliang Mu and committed by
Dave Kleikamp
898f7066 bbb8ceb5

+16 -6
+16 -6
fs/jfs/jfs_dmap.c
··· 155 155 struct bmap *bmp; 156 156 struct dbmap_disk *dbmp_le; 157 157 struct metapage *mp; 158 - int i; 158 + int i, err; 159 159 160 160 /* 161 161 * allocate/initialize the in-memory bmap descriptor ··· 170 170 BMAPBLKNO << JFS_SBI(ipbmap->i_sb)->l2nbperpage, 171 171 PSIZE, 0); 172 172 if (mp == NULL) { 173 - kfree(bmp); 174 - return -EIO; 173 + err = -EIO; 174 + goto err_kfree_bmp; 175 175 } 176 176 177 177 /* copy the on-disk bmap descriptor to its in-memory version. */ ··· 181 181 bmp->db_l2nbperpage = le32_to_cpu(dbmp_le->dn_l2nbperpage); 182 182 bmp->db_numag = le32_to_cpu(dbmp_le->dn_numag); 183 183 if (!bmp->db_numag) { 184 - release_metapage(mp); 185 - kfree(bmp); 186 - return -EINVAL; 184 + err = -EINVAL; 185 + goto err_release_metapage; 187 186 } 188 187 189 188 bmp->db_maxlevel = le32_to_cpu(dbmp_le->dn_maxlevel); ··· 193 194 bmp->db_agwidth = le32_to_cpu(dbmp_le->dn_agwidth); 194 195 bmp->db_agstart = le32_to_cpu(dbmp_le->dn_agstart); 195 196 bmp->db_agl2size = le32_to_cpu(dbmp_le->dn_agl2size); 197 + if (bmp->db_agl2size > L2MAXL2SIZE - L2MAXAG) { 198 + err = -EINVAL; 199 + goto err_release_metapage; 200 + } 201 + 196 202 for (i = 0; i < MAXAG; i++) 197 203 bmp->db_agfree[i] = le64_to_cpu(dbmp_le->dn_agfree[i]); 198 204 bmp->db_agsize = le64_to_cpu(dbmp_le->dn_agsize); ··· 218 214 BMAP_LOCK_INIT(bmp); 219 215 220 216 return (0); 217 + 218 + err_release_metapage: 219 + release_metapage(mp); 220 + err_kfree_bmp: 221 + kfree(bmp); 222 + return err; 221 223 } 222 224 223 225