Re: [PATCH v7 2/2] block: add overflow checks for Amiga partition support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Michael Schmitz - 15.10.18, 04:32:27 CEST:
> The Amiga partition parser module uses signed int for partition sector
> address and count, which will overflow for disks larger than 1 TB.

Did this go in? I did not find anything in git log. I wonder whether I 
can close the bug report mentioned below.

Best,
Martin

> Use u64 as type for sector address and size to allow using disks up to
> 2 TB without LBD support, and disks larger than 2 TB with LBD. The
> RBD format allows to specify disk sizes up to 2^128 bytes (though
> native OS limitations reduce this somewhat, to max 2^68 bytes), so
> check for u64 overflow carefully to protect against overflowing
> sector_t.
> 
> Bail out if sector addresses overflow 32 bits on kernels without LBD
> support.
> 
> This bug was reported originally in 2012, and the fix was created by
> the RDB author, Joanne Dow <jdow@xxxxxxxxxxxxx>. A patch had been
> discussed and reviewed on linux-m68k at that time but never officially
> submitted (now resubmitted as separate patch).
> This patch adds additional error checking and warning messages.
> 
> Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=43511
> Reported-by: Martin Steigerwald <Martin@xxxxxxxxxxxx>
> Message-ID: <201206192146.09327.Martin@xxxxxxxxxxxx>
> Signed-off-by: Michael Schmitz <schmitzmic@xxxxxxxxx>
> Reviewed-by: Geert Uytterhoeven <geert@xxxxxxxxxxxxxx>
> 
> ---
> 
> Changes from RFC:
> 
> - use u64 instead of sector_t, since that may be u32 without LBD
> support - check multiplication overflows each step - 3 u32 values may
> exceed u64! - warn against use on AmigaDOS if partition data overflow
> u32 sector count. - warn if partition CylBlocks larger than what's
> stored in the RDSK header. - bail out if we were to overflow sector_t
> (32 or 64 bit).
> 
> Changes from v1:
> 
> Kars de Jong:
> - use defines for magic offsets in DosEnvec struct
> 
> Geert Uytterhoeven:
> - use u64 cast for multiplications of u32 numbers
> - use array3_size for overflow checks
> - change pr_err to pr_warn
> - discontinue use of pr_cont
> - reword log messages
> - drop redundant nr_sects overflow test
> - warn against 32 bit overflow for each affected partition
> - skip partitions that overflow sector_t size instead of aborting scan
> 
> Changes from v2:
> 
> - further trim 32 bit overflow test
> - correct duplicate types.h inclusion introduced in v2
> 
> Changes from v3:
> 
> - split off sector address type fix for independent review
> - change blksize to unsigned
> - use check_mul_overflow() instead of array3_size()
> - rewrite checks to avoid 64 bit divisions in check_mul_overflow()
> 
> Changes from v5:
> 
> Geert Uytterhoeven:
> - correct ineffective u64 cast to avoid 32 bit mult. overflow
> - fix mult. overflow in partition block address calculation
> 
> Changes from v6:
> 
> Geert Uytterhoeven:
> - don't fail hard on partition block address overflow
> ---
>  block/partitions/amiga.c | 111
> +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 89
> insertions(+), 22 deletions(-)
> 
> diff --git a/block/partitions/amiga.c b/block/partitions/amiga.c
> index 7ea9540..d1b1535 100644
> --- a/block/partitions/amiga.c
> +++ b/block/partitions/amiga.c
> @@ -11,11 +11,19 @@
>  #define pr_fmt(fmt) fmt
> 
>  #include <linux/types.h>
> +#include <linux/mm_types.h>
> +#include <linux/overflow.h>
>  #include <linux/affs_hardblocks.h>
> 
>  #include "check.h"
>  #include "amiga.h"
> 
> +/* magic offsets in partition DosEnvVec */
> +#define NR_HD	3
> +#define NR_SECT	5
> +#define LO_CYL	9
> +#define	HI_CYL	10
> +
>  static __inline__ u32
>  checksum_block(__be32 *m, int size)
>  {
> @@ -32,9 +40,12 @@ int amiga_partition(struct parsed_partitions
> *state) unsigned char *data;
>  	struct RigidDiskBlock *rdb;
>  	struct PartitionBlock *pb;
> -	sector_t start_sect, nr_sects;
> -	int blk, part, res = 0;
> -	int blksize = 1;	/* Multiplier for disk block size */
> +	u64 start_sect, nr_sects;
> +	sector_t blk, end_sect;
> +	u32 cylblk;		/* rdb_CylBlocks = 
nr_heads*sect_per_track */
> +	u32 nr_hd, nr_sect, lo_cyl, hi_cyl;
> +	int part, res = 0;
> +	unsigned int blksize = 1;	/* Multiplier for disk block size */
>  	int slot = 1;
>  	char b[BDEVNAME_SIZE];
> 
> @@ -44,8 +55,8 @@ int amiga_partition(struct parsed_partitions *state)
> data = read_part_sector(state, blk, &sect);
>  		if (!data) {
>  			if (warn_no_part)
> -				pr_err("Dev %s: unable to read RDB block 
%d\n",
> -				       bdevname(state->bdev, b), blk);
> +				pr_err("Dev %s: unable to read RDB block 
%llu\n",
> +				       bdevname(state->bdev, b), (u64) 
blk);
>  			res = -1;
>  			goto rdb_done;
>  		}
> @@ -61,13 +72,13 @@ int amiga_partition(struct parsed_partitions
> *state) *(__be32 *)(data+0xdc) = 0;
>  		if (checksum_block((__be32 *)data,
>  				be32_to_cpu(rdb->rdb_SummedLongs) & 
0x7F)==0) {
> -			pr_err("Trashed word at 0xd0 in block %d ignored 
in checksum
> calculation\n", -			       blk);
> +			pr_err("Trashed word at 0xd0 in block %llu ignored 
in checksum
> calculation\n", +			       (u64) blk);
>  			break;
>  		}
> 
> -		pr_err("Dev %s: RDB in block %d has bad checksum\n",
> -		       bdevname(state->bdev, b), blk);
> +		pr_err("Dev %s: RDB in block %llu has bad checksum\n",
> +		       bdevname(state->bdev, b), (u64) blk);
>  	}
> 
>  	/* blksize is blocks per 512 byte standard block */
> @@ -83,12 +94,17 @@ int amiga_partition(struct parsed_partitions
> *state) blk = be32_to_cpu(rdb->rdb_PartitionList);
>  	put_dev_sector(sect);
>  	for (part = 1; blk>0 && part<=16; part++, put_dev_sector(sect)) 
{
> -		blk *= blksize;	/* Read in terms partition table 
understands */
> +		/* Read in terms partition table understands */
> +		if (check_mul_overflow(blk, (sector_t) blksize, &blk)) {
> +			pr_err("Dev %s: overflow calculating partition 
block %llu!
> Skipping partitions %u and beyond\n", +				
bdevname(state->bdev, b),
> (u64) blk, part);
> +			break;
> +		}
>  		data = read_part_sector(state, blk, &sect);
>  		if (!data) {
>  			if (warn_no_part)
> -				pr_err("Dev %s: unable to read partition 
block %d\n",
> -				       bdevname(state->bdev, b), blk);
> +				pr_err("Dev %s: unable to read partition 
block %llu\n",
> +				       bdevname(state->bdev, b), (u64) 
blk);
>  			res = -1;
>  			goto rdb_done;
>  		}
> @@ -99,19 +115,70 @@ int amiga_partition(struct parsed_partitions
> *state) if (checksum_block((__be32 *)pb,
> be32_to_cpu(pb->pb_SummedLongs) & 0x7F) != 0 ) continue;
> 
> -		/* Tell Kernel about it */
> +		/* RDB gives us more than enough rope to hang ourselves 
with,
> +		 * many times over (2^128 bytes if all fields max out).
> +		 * Some careful checks are in order, so check for 
potential
> +		 * overflows.
> +		 * We are multiplying four 32 bit numbers to one 
sector_t!
> +		 */
> +
> +		nr_hd   = be32_to_cpu(pb->pb_Environment[NR_HD]);
> +		nr_sect = be32_to_cpu(pb->pb_Environment[NR_SECT]);
> +
> +		/* CylBlocks is total number of blocks per cylinder */
> +		if (check_mul_overflow(nr_hd, nr_sect, &cylblk)) {
> +			pr_err("Dev %s: heads*sects %u overflows u32, 
skipping
> partition!\n", +				bdevname(state->bdev, b), 
cylblk);
> +			continue;
> +		}
> +
> +		/* check for consistency with RDB defined CylBlocks */
> +		if (cylblk > be32_to_cpu(rdb->rdb_CylBlocks)) {
> +			pr_warn("Dev %s: cylblk %u > rdb_CylBlocks %u!\n",
> +				bdevname(state->bdev, b), cylblk,
> +				be32_to_cpu(rdb->rdb_CylBlocks));
> +		}
> +
> +		/* RDB allows for variable logical block size -
> +		 * normalize to 512 byte blocks and check result.
> +		 */
> +
> +		if (check_mul_overflow(cylblk, blksize, &cylblk)) {
> +			pr_err("Dev %s: partition %u bytes per cyl. 
overflows u32,
> skipping partition!\n", +				bdevname(state->bdev, 
b), part);
> +			continue;
> +		}
> +
> +		/* Calculate partition start and end. Limit of 32 bit on 
cylblk
> +		 * guarantees no overflow occurs if LBD support is 
enabled.
> +		 */
> +
> +		lo_cyl = be32_to_cpu(pb->pb_Environment[LO_CYL]);
> +		start_sect = ((u64) lo_cyl * cylblk);
> +
> +		hi_cyl = be32_to_cpu(pb->pb_Environment[HI_CYL]);
> +		nr_sects = (((u64) hi_cyl - lo_cyl + 1) * cylblk);
> 
> -		nr_sects = ((sector_t) be32_to_cpu(pb-
>pb_Environment[10])
> -			   + 1 - be32_to_cpu(pb->pb_Environment[9])) *
> -			   be32_to_cpu(pb->pb_Environment[3]) *
> -			   be32_to_cpu(pb->pb_Environment[5]) *
> -			   blksize;
>  		if (!nr_sects)
>  			continue;
> -		start_sect = (sector_t) be32_to_cpu(pb-
>pb_Environment[9]) *
> -			     be32_to_cpu(pb->pb_Environment[3]) *
> -			     be32_to_cpu(pb->pb_Environment[5]) *
> -			     blksize;
> +
> +		/* Warn user if partition end overflows u32 (AmigaDOS 
limit) */
> +
> +		if ((start_sect + nr_sects) > UINT_MAX) {
> +			pr_warn("Dev %s: partition %u (%llu-%llu) needs 64 
bit device
> support!\n", +				bdevname(state->bdev, b), part,
> +				start_sect, start_sect + nr_sects);
> +		}
> +
> +		if (check_add_overflow(start_sect, nr_sects, &end_sect)) {
> +			pr_err("Dev %s: partition %u (%llu-%llu) needs LBD 
device support,
> skipping partition!\n", +				bdevname(state->bdev, 
b), part,
> +				start_sect, (u64) end_sect);
> +			continue;
> +		}
> +
> +		/* Tell Kernel about it */
> +
>  		put_partition(state,slot++,start_sect,nr_sects);
>  		{
>  			/* Be even more informative to aid mounting */


-- 
Martin





[Index of Archives]     [Linux RAID]     [Linux SCSI]     [Linux ATA RAID]     [IDE]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Device Mapper]

  Powered by Linux