diff mbox series

[v10,2/3] block: change annotation of rdb_CylBlocks in affs_hardblocks.h

Message ID 20230615030837.8518-3-schmitzmic@gmail.com (mailing list archive)
State New, archived
Headers show
Series Amiga RDB partition support fixes | expand

Commit Message

Michael Schmitz June 15, 2023, 3:08 a.m. UTC
The Amiga partition parser module uses signed int for partition sector
address and count, which will overflow for disks larger than 1 TB.

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.

This bug was reported originally in 2012, and the fix was created by
the RDB author, Joanne Dow <jdow@earthlink.net>. A patch had been
discussed and reviewed on linux-m68k at that time but never officially
submitted (now resubmitted as patch 1 of this series).

Patch 3 (this series) adds additional error checking and warning
messages. One of the error checks now makes use of the previously
unused rdb_CylBlocks field, which causes a 'sparse' warning
(cast to restricted __be32).

Annotate rdb_CylBlocks field as big endian to shut up the warning.
Add comment to document that the same annotation is going to be
needed for any other fields that may be used by the kernel in
future.

Reported-by: Martin Steigerwald <Martin@lichtvoll.de>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=43511
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Message-ID: <201206192146.09327.Martin@lichtvoll.de>
Cc: <stable@vger.kernel.org> # 5.2
Signed-off-by: Michael Schmitz <schmitzmic@gmail.com>
---
 include/uapi/linux/affs_hardblocks.h | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

Comments

Christoph Hellwig June 15, 2023, 4:17 a.m. UTC | #1
On Thu, Jun 15, 2023 at 03:08:36PM +1200, Michael Schmitz wrote:
> +/* MSch 20230615: any field used by the Linux kernel must be
> + * annotated __be32! If any fields require increase to 64
> + * bit size, rdb_ID _must_ be changed!
> + */

This is a really weird comment.  If you change on-disk format it
is a different format and needs to be marked as such, sure.

And as far as I can tell everything that is a __u32 here should
be an __be32 because it is a big endian on-disk format.  Why
would you change only a single field?
Michael Schmitz June 15, 2023, 4:50 a.m. UTC | #2
Hi Christoph,

thanks for your comments!

Am 15.06.2023 um 16:17 schrieb Christoph Hellwig:
> On Thu, Jun 15, 2023 at 03:08:36PM +1200, Michael Schmitz wrote:
>> +/* MSch 20230615: any field used by the Linux kernel must be
>> + * annotated __be32! If any fields require increase to 64
>> + * bit size, rdb_ID _must_ be changed!
>> + */
>
> This is a really weird comment.  If you change on-disk format it
> is a different format and needs to be marked as such, sure.

I concede this isn't relevant to the matter at hand, and it's something 
that _should_ be obvious. This came up in my off-list discussion with 
Joanne Dow as a caveat for future huge disk sizes, so I thought I'd add 
it to the comment.

> And as far as I can tell everything that is a __u32 here should
> be an __be32 because it is a big endian on-disk format.  Why
> would you change only a single field?

Because that's all I needed, and wanted to avoid excess patch churn. 
Plus (appeal to authority here :-)) it's in keeping with what Al Viro 
did when the __be32 annotations were first added.

I can change all __u32 to __be32 and drop the comment if that's preferred.

Cheers,

	Michael
Christoph Hellwig June 15, 2023, 5:53 a.m. UTC | #3
On Thu, Jun 15, 2023 at 04:50:45PM +1200, Michael Schmitz wrote:
>> And as far as I can tell everything that is a __u32 here should
>> be an __be32 because it is a big endian on-disk format.  Why
>> would you change only a single field?
>
> Because that's all I needed, and wanted to avoid excess patch churn. Plus 
> (appeal to authority here :-)) it's in keeping with what Al Viro did when 
> the __be32 annotations were first added.
>
> I can change all __u32 to __be32 and drop the comment if that's preferred.

That would be great!
Michael Schmitz June 15, 2023, 7:09 a.m. UTC | #4
Hi Christoph,

Am 15.06.2023 um 17:53 schrieb Christoph Hellwig:
> On Thu, Jun 15, 2023 at 04:50:45PM +1200, Michael Schmitz wrote:
>>> And as far as I can tell everything that is a __u32 here should
>>> be an __be32 because it is a big endian on-disk format.  Why
>>> would you change only a single field?
>>
>> Because that's all I needed, and wanted to avoid excess patch churn. Plus
>> (appeal to authority here :-)) it's in keeping with what Al Viro did when
>> the __be32 annotations were first added.
>>
>> I can change all __u32 to __be32 and drop the comment if that's preferred.
>
> That would be great!

OK, will respin tomorrow.

Cheers,

	Michael
Geert Uytterhoeven June 15, 2023, 7:21 a.m. UTC | #5
Hi Michael,

Thanks for your patch!

On Thu, Jun 15, 2023 at 7:53 AM Christoph Hellwig <hch@lst.de> wrote:
> On Thu, Jun 15, 2023 at 04:50:45PM +1200, Michael Schmitz wrote:
> >> And as far as I can tell everything that is a __u32 here should
> >> be an __be32 because it is a big endian on-disk format.  Why
> >> would you change only a single field?
> >
> > Because that's all I needed, and wanted to avoid excess patch churn. Plus
> > (appeal to authority here :-)) it's in keeping with what Al Viro did when
> > the __be32 annotations were first added.
> >
> > I can change all __u32 to __be32 and drop the comment if that's preferred.
>
> That would be great!

I totally agree with Christoph.

Gr{oetje,eeting}s,

                        Geert
Michael Schmitz June 15, 2023, 7:53 p.m. UTC | #6
Hi Geert,

On 15/06/23 19:21, Geert Uytterhoeven wrote:
> Hi Michael,
>
> Thanks for your patch!
>
> On Thu, Jun 15, 2023 at 7:53 AM Christoph Hellwig <hch@lst.de> wrote:
>> On Thu, Jun 15, 2023 at 04:50:45PM +1200, Michael Schmitz wrote:
>>>> And as far as I can tell everything that is a __u32 here should
>>>> be an __be32 because it is a big endian on-disk format.  Why
>>>> would you change only a single field?
>>> Because that's all I needed, and wanted to avoid excess patch churn. Plus
>>> (appeal to authority here :-)) it's in keeping with what Al Viro did when
>>> the __be32 annotations were first added.
>>>
>>> I can change all __u32 to __be32 and drop the comment if that's preferred.
>> That would be great!
> I totally agree with Christoph.

Thanks - now there's two __s32 fields in that header - one checksum each 
for RDB and PB. No one has so far seen the need for a 'signed big endian 
32 bit' type, and I'd rather avoid adding one to types.h. I'll leave 
those as they are (with the tacit understanding that they are equally 
meant to be big endian).

Cheers,

     Michael

> Gr{oetje,eeting}s,
>
>                          Geert
>
Christoph Hellwig June 16, 2023, 5:48 a.m. UTC | #7
On Fri, Jun 16, 2023 at 07:53:11AM +1200, Michael Schmitz wrote:
> Thanks - now there's two __s32 fields in that header - one checksum each 
> for RDB and PB. No one has so far seen the need for a 'signed big endian 32 
> bit' type, and I'd rather avoid adding one to types.h. I'll leave those as 
> they are (with the tacit understanding that they are equally meant to be 
> big endian).

We have those in a few other pleases and store them as __be32 as well.  The
(implicit) cast to s32 will make them signed again.
Michael Schmitz June 16, 2023, 7:20 a.m. UTC | #8
Hi Christoph,

Am 16.06.2023 um 17:48 schrieb Christoph Hellwig:
> On Fri, Jun 16, 2023 at 07:53:11AM +1200, Michael Schmitz wrote:
>> Thanks - now there's two __s32 fields in that header - one checksum each
>> for RDB and PB. No one has so far seen the need for a 'signed big endian 32
>> bit' type, and I'd rather avoid adding one to types.h. I'll leave those as
>> they are (with the tacit understanding that they are equally meant to be
>> big endian).
>
> We have those in a few other pleases and store them as __be32 as well.  The
> (implicit) cast to s32 will make them signed again.

Where's that cast to s32 hidden? I've only seen

#define __be32_to_cpu(x) ((__force __u32)(__be32)(x))

which would make the checksums unsigned if __be32 was used.

Whether the checksum code uses signed or unsigned math would require 
inspection of the Amiga partitioning tool source which I don't have, so 
I've kept __s32 to be safe.

Thanks for reviewing v11!

Cheers,

	Michael
Christoph Hellwig June 16, 2023, 7:25 a.m. UTC | #9
On Fri, Jun 16, 2023 at 07:20:52PM +1200, Michael Schmitz wrote:
> Am 16.06.2023 um 17:48 schrieb Christoph Hellwig:
>> On Fri, Jun 16, 2023 at 07:53:11AM +1200, Michael Schmitz wrote:
>>> Thanks - now there's two __s32 fields in that header - one checksum each
>>> for RDB and PB. No one has so far seen the need for a 'signed big endian 32
>>> bit' type, and I'd rather avoid adding one to types.h. I'll leave those as
>>> they are (with the tacit understanding that they are equally meant to be
>>> big endian).
>>
>> We have those in a few other pleases and store them as __be32 as well.  The
>> (implicit) cast to s32 will make them signed again.
>
> Where's that cast to s32 hidden? I've only seen
>
> #define __be32_to_cpu(x) ((__force __u32)(__be32)(x))
>
> which would make the checksums unsigned if __be32 was used.
>
> Whether the checksum code uses signed or unsigned math would require 
> inspection of the Amiga partitioning tool source which I don't have, so 
> I've kept __s32 to be safe.

Well, the return value of be32_to_cpu is going to be a assigned to a,
presumably signed, variable.  With that you get an implicit cast.
Geert Uytterhoeven June 16, 2023, 7:28 a.m. UTC | #10
Hi Michael,

On Fri, Jun 16, 2023 at 9:21 AM Michael Schmitz <schmitzmic@gmail.com> wrote:
> Am 16.06.2023 um 17:48 schrieb Christoph Hellwig:
> > On Fri, Jun 16, 2023 at 07:53:11AM +1200, Michael Schmitz wrote:
> >> Thanks - now there's two __s32 fields in that header - one checksum each
> >> for RDB and PB. No one has so far seen the need for a 'signed big endian 32
> >> bit' type, and I'd rather avoid adding one to types.h. I'll leave those as
> >> they are (with the tacit understanding that they are equally meant to be
> >> big endian).
> >
> > We have those in a few other pleases and store them as __be32 as well.  The
> > (implicit) cast to s32 will make them signed again.
>
> Where's that cast to s32 hidden? I've only seen
>
> #define __be32_to_cpu(x) ((__force __u32)(__be32)(x))
>
> which would make the checksums unsigned if __be32 was used.
>
> Whether the checksum code uses signed or unsigned math would require
> inspection of the Amiga partitioning tool source which I don't have, so
> I've kept __s32 to be safe.

Unsurprisingly, block/partitions/amiga.c:checksum_block() calculates
a checksum over __be32 words.  The actual signedness of the checksum
field doesn't matter much[*], as using two-complement numbers, you can
just assign a signed value to an unsigned field.
It should definitely be __be32.

[*] I guess it was made signed because the procedure to update the
check goes like this:
  1. set checksum field to zero,
  2. calculate sum,
  3. store negated sum in checksum field.

Gr{oetje,eeting}s,

                        Geert
Michael Schmitz June 16, 2023, 7:45 a.m. UTC | #11
Hi Geert,

Am 16.06.2023 um 19:28 schrieb Geert Uytterhoeven:
> Hi Michael,
>
> On Fri, Jun 16, 2023 at 9:21 AM Michael Schmitz <schmitzmic@gmail.com> wrote:
>> Am 16.06.2023 um 17:48 schrieb Christoph Hellwig:
>>> On Fri, Jun 16, 2023 at 07:53:11AM +1200, Michael Schmitz wrote:
>>>> Thanks - now there's two __s32 fields in that header - one checksum each
>>>> for RDB and PB. No one has so far seen the need for a 'signed big endian 32
>>>> bit' type, and I'd rather avoid adding one to types.h. I'll leave those as
>>>> they are (with the tacit understanding that they are equally meant to be
>>>> big endian).
>>>
>>> We have those in a few other pleases and store them as __be32 as well.  The
>>> (implicit) cast to s32 will make them signed again.
>>
>> Where's that cast to s32 hidden? I've only seen
>>
>> #define __be32_to_cpu(x) ((__force __u32)(__be32)(x))
>>
>> which would make the checksums unsigned if __be32 was used.
>>
>> Whether the checksum code uses signed or unsigned math would require
>> inspection of the Amiga partitioning tool source which I don't have, so
>> I've kept __s32 to be safe.
>
> Unsurprisingly, block/partitions/amiga.c:checksum_block() calculates
> a checksum over __be32 words.  The actual signedness of the checksum
> field doesn't matter much[*], as using two-complement numbers, you can
> just assign a signed value to an unsigned field.
> It should definitely be __be32.
>
> [*] I guess it was made signed because the procedure to update the
> check goes like this:
>   1. set checksum field to zero,
>   2. calculate sum,
>   3. store negated sum in checksum field.

Thanks, that explains why the result of checksum_block() is tested 
against zero. Makes sense now.

Will fix in v12 ...

Cheers,

	Michael



>
> Gr{oetje,eeting}s,
>
>                         Geert
>
Michael Schmitz June 16, 2023, 7:51 a.m. UTC | #12
Hi Christoph,

Am 16.06.2023 um 19:25 schrieb Christoph Hellwig:
>>> We have those in a few other pleases and store them as __be32 as well.  The
>>> (implicit) cast to s32 will make them signed again.
>>
>> Where's that cast to s32 hidden? I've only seen
>>
>> #define __be32_to_cpu(x) ((__force __u32)(__be32)(x))
>>
>> which would make the checksums unsigned if __be32 was used.
>>
>> Whether the checksum code uses signed or unsigned math would require
>> inspection of the Amiga partitioning tool source which I don't have, so
>> I've kept __s32 to be safe.
>
> Well, the return value of be32_to_cpu is going to be a assigned to a,
> presumably signed, variable.  With that you get an implicit cast.

I see - as Geert explained, signed or unsigned doesn't matter for the 
type of checksum algorithm used in this case, so there is no potential 
for confusion once you think about it (which I didn't, obviously).

Cheers,

	Michael
diff mbox series

Patch

diff --git a/include/uapi/linux/affs_hardblocks.h b/include/uapi/linux/affs_hardblocks.h
index 5e2fb8481252..9da5bc607939 100644
--- a/include/uapi/linux/affs_hardblocks.h
+++ b/include/uapi/linux/affs_hardblocks.h
@@ -6,6 +6,11 @@ 
 
 /* Just the needed definitions for the RDB of an Amiga HD. */
 
+/* MSch 20230615: any field used by the Linux kernel must be
+ * annotated __be32! If any fields require increase to 64
+ * bit size, rdb_ID _must_ be changed!
+ */
+
 struct RigidDiskBlock {
 	__u32	rdb_ID;
 	__be32	rdb_SummedLongs;
@@ -32,7 +37,7 @@  struct RigidDiskBlock {
 	__u32	rdb_RDBBlocksHi;
 	__u32	rdb_LoCylinder;
 	__u32	rdb_HiCylinder;
-	__u32	rdb_CylBlocks;
+	__be32	rdb_CylBlocks;
 	__u32	rdb_AutoParkSeconds;
 	__u32	rdb_HighRDSKBlock;
 	__u32	rdb_Reserved4;