linux-nilfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
  • * [PATCH AUTOSEL 6.0 10/16] nilfs2: fix shift-out-of-bounds due to too large exponent of block size
           [not found] <20221217152821.98618-1-sashal@kernel.org>
           [not found] ` <20221217152821.98618-1-sashal-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
    @ 2022-12-17 15:28 ` Sasha Levin
      1 sibling, 0 replies; 2+ messages in thread
    From: Sasha Levin @ 2022-12-17 15:28 UTC (permalink / raw)
      To: linux-kernel, stable
      Cc: Ryusuke Konishi, Andrew Morton, Sasha Levin, linux-nilfs
    
    From: Ryusuke Konishi <konishi.ryusuke@gmail.com>
    
    [ Upstream commit ebeccaaef67a4895d2496ab8d9c2fb8d89201211 ]
    
    If field s_log_block_size of superblock data is corrupted and too large,
    init_nilfs() and load_nilfs() still can trigger a shift-out-of-bounds
    warning followed by a kernel panic (if panic_on_warn is set):
    
     shift exponent 38973 is too large for 32-bit type 'int'
     Call Trace:
      <TASK>
      dump_stack_lvl+0xcd/0x134
      ubsan_epilogue+0xb/0x50
      __ubsan_handle_shift_out_of_bounds.cold.12+0x17b/0x1f5
      init_nilfs.cold.11+0x18/0x1d [nilfs2]
      nilfs_mount+0x9b5/0x12b0 [nilfs2]
      ...
    
    This fixes the issue by adding and using a new helper function for getting
    block size with sanity check.
    
    Link: https://lkml.kernel.org/r/20221027044306.42774-3-konishi.ryusuke@gmail.com
    Signed-off-by: Ryusuke Konishi <konishi.ryusuke@gmail.com>
    Tested-by: Ryusuke Konishi <konishi.ryusuke@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
     fs/nilfs2/the_nilfs.c | 42 ++++++++++++++++++++++++++++++++++++++----
     1 file changed, 38 insertions(+), 4 deletions(-)
    
    diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c
    index a7c829a7d4f1..2064e6473d30 100644
    --- a/fs/nilfs2/the_nilfs.c
    +++ b/fs/nilfs2/the_nilfs.c
    @@ -193,6 +193,34 @@ static int nilfs_store_log_cursor(struct the_nilfs *nilfs,
     	return ret;
     }
     
    +/**
    + * nilfs_get_blocksize - get block size from raw superblock data
    + * @sb: super block instance
    + * @sbp: superblock raw data buffer
    + * @blocksize: place to store block size
    + *
    + * nilfs_get_blocksize() calculates the block size from the block size
    + * exponent information written in @sbp and stores it in @blocksize,
    + * or aborts with an error message if it's too large.
    + *
    + * Return Value: On success, 0 is returned. If the block size is too
    + * large, -EINVAL is returned.
    + */
    +static int nilfs_get_blocksize(struct super_block *sb,
    +			       struct nilfs_super_block *sbp, int *blocksize)
    +{
    +	unsigned int shift_bits = le32_to_cpu(sbp->s_log_block_size);
    +
    +	if (unlikely(shift_bits >
    +		     ilog2(NILFS_MAX_BLOCK_SIZE) - BLOCK_SIZE_BITS)) {
    +		nilfs_err(sb, "too large filesystem blocksize: 2 ^ %u KiB",
    +			  shift_bits);
    +		return -EINVAL;
    +	}
    +	*blocksize = BLOCK_SIZE << shift_bits;
    +	return 0;
    +}
    +
     /**
      * load_nilfs - load and recover the nilfs
      * @nilfs: the_nilfs structure to be released
    @@ -246,11 +274,15 @@ int load_nilfs(struct the_nilfs *nilfs, struct super_block *sb)
     		nilfs->ns_sbwtime = le64_to_cpu(sbp[0]->s_wtime);
     
     		/* verify consistency between two super blocks */
    -		blocksize = BLOCK_SIZE << le32_to_cpu(sbp[0]->s_log_block_size);
    +		err = nilfs_get_blocksize(sb, sbp[0], &blocksize);
    +		if (err)
    +			goto scan_error;
    +
     		if (blocksize != nilfs->ns_blocksize) {
     			nilfs_warn(sb,
     				   "blocksize differs between two super blocks (%d != %d)",
     				   blocksize, nilfs->ns_blocksize);
    +			err = -EINVAL;
     			goto scan_error;
     		}
     
    @@ -609,9 +641,11 @@ int init_nilfs(struct the_nilfs *nilfs, struct super_block *sb, char *data)
     	if (err)
     		goto failed_sbh;
     
    -	blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size);
    -	if (blocksize < NILFS_MIN_BLOCK_SIZE ||
    -	    blocksize > NILFS_MAX_BLOCK_SIZE) {
    +	err = nilfs_get_blocksize(sb, sbp, &blocksize);
    +	if (err)
    +		goto failed_sbh;
    +
    +	if (blocksize < NILFS_MIN_BLOCK_SIZE) {
     		nilfs_err(sb,
     			  "couldn't mount because of unsupported filesystem blocksize %d",
     			  blocksize);
    -- 
    2.35.1
    
    
    ^ permalink raw reply related	[flat|nested] 2+ messages in thread

  • end of thread, other threads:[~2022-12-17 15:28 UTC | newest]
    
    Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
    -- links below jump to the message on this page --
         [not found] <20221217152821.98618-1-sashal@kernel.org>
         [not found] ` <20221217152821.98618-1-sashal-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
    2022-12-17 15:28   ` [PATCH AUTOSEL 6.0 09/16] nilfs2: fix shift-out-of-bounds/overflow in nilfs_sb2_bad_offset() Sasha Levin
    2022-12-17 15:28 ` [PATCH AUTOSEL 6.0 10/16] nilfs2: fix shift-out-of-bounds due to too large exponent of block size Sasha Levin
    

    This is a public inbox, see mirroring instructions
    for how to clone and mirror all data and code used for this inbox;
    as well as URLs for NNTP newsgroup(s).