Merge tag 'jfs-6.14' of github.com:kleikamp/linux-shaggy

Pull jfs updates from David Kleikamp:
 "Various bug fixes and cleanups for JFS"

* tag 'jfs-6.14' of github.com:kleikamp/linux-shaggy:
  jfs: add index corruption check to DT_GETPAGE()
  fs/jfs: consolidate sanity checking in dbMount
  jfs: add sanity check for agwidth in dbMount
  jfs: Prevent copying of nlink with value 0 from disk inode
  fs/jfs: Prevent integer overflow in AG size calculation
  fs/jfs: cast inactags to s64 to prevent potential overflow
  jfs: Fix uninit-value access of imap allocated in the diMount() function
  jfs: fix slab-out-of-bounds read in ea_get()
  jfs: add check read-only before truncation in jfs_truncate_nolock()
  jfs: add check read-only before txBeginAnon() call
  jfs: reject on-disk inodes of an unsupported type
  jfs: Remove reference to bh->b_page
  jfs: Delete a couple tabs in jfs_reconfigure()
This commit is contained in:
Linus Torvalds
2025-03-27 13:17:39 -07:00
7 changed files with 50 additions and 40 deletions

View File

@@ -369,7 +369,7 @@ void jfs_truncate_nolock(struct inode *ip, loff_t length)
ASSERT(length >= 0);
if (test_cflag(COMMIT_Nolink, ip)) {
if (test_cflag(COMMIT_Nolink, ip) || isReadOnly(ip)) {
xtTruncate(0, ip, length, COMMIT_WMAP);
return;
}

View File

@@ -178,41 +178,26 @@ int dbMount(struct inode *ipbmap)
dbmp_le = (struct dbmap_disk *) mp->data;
bmp->db_mapsize = le64_to_cpu(dbmp_le->dn_mapsize);
bmp->db_nfree = le64_to_cpu(dbmp_le->dn_nfree);
bmp->db_l2nbperpage = le32_to_cpu(dbmp_le->dn_l2nbperpage);
if (bmp->db_l2nbperpage > L2PSIZE - L2MINBLOCKSIZE ||
bmp->db_l2nbperpage < 0) {
err = -EINVAL;
goto err_release_metapage;
}
bmp->db_numag = le32_to_cpu(dbmp_le->dn_numag);
if (!bmp->db_numag || bmp->db_numag > MAXAG) {
err = -EINVAL;
goto err_release_metapage;
}
bmp->db_maxlevel = le32_to_cpu(dbmp_le->dn_maxlevel);
bmp->db_maxag = le32_to_cpu(dbmp_le->dn_maxag);
bmp->db_agpref = le32_to_cpu(dbmp_le->dn_agpref);
if (bmp->db_maxag >= MAXAG || bmp->db_maxag < 0 ||
bmp->db_agpref >= MAXAG || bmp->db_agpref < 0) {
err = -EINVAL;
goto err_release_metapage;
}
bmp->db_aglevel = le32_to_cpu(dbmp_le->dn_aglevel);
bmp->db_agheight = le32_to_cpu(dbmp_le->dn_agheight);
bmp->db_agwidth = le32_to_cpu(dbmp_le->dn_agwidth);
bmp->db_agstart = le32_to_cpu(dbmp_le->dn_agstart);
bmp->db_agl2size = le32_to_cpu(dbmp_le->dn_agl2size);
if (bmp->db_agl2size > L2MAXL2SIZE - L2MAXAG ||
bmp->db_agl2size < 0) {
err = -EINVAL;
goto err_release_metapage;
}
if (((bmp->db_mapsize - 1) >> bmp->db_agl2size) > MAXAG) {
if ((bmp->db_l2nbperpage > L2PSIZE - L2MINBLOCKSIZE) ||
(bmp->db_l2nbperpage < 0) ||
!bmp->db_numag || (bmp->db_numag > MAXAG) ||
(bmp->db_maxag >= MAXAG) || (bmp->db_maxag < 0) ||
(bmp->db_agpref >= MAXAG) || (bmp->db_agpref < 0) ||
!bmp->db_agwidth ||
(bmp->db_agl2size > L2MAXL2SIZE - L2MAXAG) ||
(bmp->db_agl2size < 0) ||
((bmp->db_mapsize - 1) >> bmp->db_agl2size) > MAXAG) {
err = -EINVAL;
goto err_release_metapage;
}
@@ -3403,7 +3388,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks)
oldl2agsize = bmp->db_agl2size;
bmp->db_agl2size = l2agsize;
bmp->db_agsize = 1 << l2agsize;
bmp->db_agsize = (s64)1 << l2agsize;
/* compute new number of AG */
agno = bmp->db_numag;
@@ -3666,8 +3651,8 @@ void dbFinalizeBmap(struct inode *ipbmap)
* system size is not a multiple of the group size).
*/
inactfree = (inactags && ag_rem) ?
((inactags - 1) << bmp->db_agl2size) + ag_rem
: inactags << bmp->db_agl2size;
(((s64)inactags - 1) << bmp->db_agl2size) + ag_rem
: ((s64)inactags << bmp->db_agl2size);
/* determine how many free blocks are in the active
* allocation groups plus the average number of free blocks

View File

@@ -117,7 +117,8 @@ do { \
if (!(RC)) { \
if (((P)->header.nextindex > \
(((BN) == 0) ? DTROOTMAXSLOT : (P)->header.maxslot)) || \
((BN) && ((P)->header.maxslot > DTPAGEMAXSLOT))) { \
((BN) && (((P)->header.maxslot > DTPAGEMAXSLOT) || \
((P)->header.stblindex >= DTPAGEMAXSLOT)))) { \
BT_PUTPAGE(MP); \
jfs_error((IP)->i_sb, \
"DT_GETPAGE: dtree page corrupt\n"); \

View File

@@ -74,6 +74,11 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, bool abnr)
int rc;
int xflag;
if (isReadOnly(ip)) {
jfs_error(ip->i_sb, "read-only filesystem\n");
return -EIO;
}
/* This blocks if we are low on resources */
txBeginAnon(ip->i_sb);
@@ -253,6 +258,11 @@ int extRecord(struct inode *ip, xad_t * xp)
{
int rc;
if (isReadOnly(ip)) {
jfs_error(ip->i_sb, "read-only filesystem\n");
return -EIO;
}
txBeginAnon(ip->i_sb);
mutex_lock(&JFS_IP(ip)->commit_mutex);

View File

@@ -102,7 +102,7 @@ int diMount(struct inode *ipimap)
* allocate/initialize the in-memory inode map control structure
*/
/* allocate the in-memory inode map control structure. */
imap = kmalloc(sizeof(struct inomap), GFP_KERNEL);
imap = kzalloc(sizeof(struct inomap), GFP_KERNEL);
if (imap == NULL)
return -ENOMEM;
@@ -456,7 +456,7 @@ struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary)
dp += inum % 8; /* 8 inodes per 4K page */
/* copy on-disk inode to in-memory inode */
if ((copy_from_dinode(dp, ip)) != 0) {
if ((copy_from_dinode(dp, ip) != 0) || (ip->i_nlink == 0)) {
/* handle bad return by returning NULL for ip */
set_nlink(ip, 1); /* Don't want iput() deleting it */
iput(ip);
@@ -3029,14 +3029,23 @@ static void duplicateIXtree(struct super_block *sb, s64 blkno,
*
* RETURN VALUES:
* 0 - success
* -ENOMEM - insufficient memory
* -EINVAL - unexpected inode type
*/
static int copy_from_dinode(struct dinode * dip, struct inode *ip)
{
struct jfs_inode_info *jfs_ip = JFS_IP(ip);
struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
int fileset = le32_to_cpu(dip->di_fileset);
jfs_ip->fileset = le32_to_cpu(dip->di_fileset);
switch (fileset) {
case AGGR_RESERVED_I: case AGGREGATE_I: case BMAP_I:
case LOG_I: case BADBLOCK_I: case FILESYSTEM_I:
break;
default:
return -EINVAL;
}
jfs_ip->fileset = fileset;
jfs_ip->mode2 = le32_to_cpu(dip->di_mode);
jfs_set_inode_flags(ip);

View File

@@ -389,8 +389,8 @@ static int jfs_reconfigure(struct fs_context *fc)
if (!ctx->newLVSize) {
ctx->newLVSize = sb_bdev_nr_blocks(sb);
if (ctx->newLVSize == 0)
pr_err("JFS: Cannot determine volume size\n");
if (ctx->newLVSize == 0)
pr_err("JFS: Cannot determine volume size\n");
}
rc = jfs_extendfs(sb, ctx->newLVSize, 0);
@@ -766,7 +766,7 @@ static ssize_t jfs_quota_write(struct super_block *sb, int type,
}
lock_buffer(bh);
memcpy(bh->b_data+offset, data, tocopy);
flush_dcache_page(bh->b_page);
flush_dcache_folio(bh->b_folio);
set_buffer_uptodate(bh);
mark_buffer_dirty(bh);
unlock_buffer(bh);

View File

@@ -559,11 +559,16 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size)
size_check:
if (EALIST_SIZE(ea_buf->xattr) != ea_size) {
int size = clamp_t(int, ea_size, 0, EALIST_SIZE(ea_buf->xattr));
if (unlikely(EALIST_SIZE(ea_buf->xattr) > INT_MAX)) {
printk(KERN_ERR "ea_get: extended attribute size too large: %u > INT_MAX\n",
EALIST_SIZE(ea_buf->xattr));
} else {
int size = clamp_t(int, ea_size, 0, EALIST_SIZE(ea_buf->xattr));
printk(KERN_ERR "ea_get: invalid extended attribute\n");
print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1,
ea_buf->xattr, size, 1);
printk(KERN_ERR "ea_get: invalid extended attribute\n");
print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1,
ea_buf->xattr, size, 1);
}
ea_release(inode, ea_buf);
rc = -EIO;
goto clean_up;