RE: [RFC][PATCHES v2] checksum stuff

From: David Laight
Date: Fri Dec 08 2023 - 07:04:52 EST


From: Al Viro
> Sent: 06 December 2023 22:44
>
> On Wed, Dec 06, 2023 at 11:10:45AM +0000, David Laight wrote:
>
> > Do we?
> > I've not seen any justification for this at all.
> > IIRC the ICMPv4 reply code needs the checksum function return 0xffff
> > for all-zero input.
> >
> > So the correct and simple fix is to initialise the sum to 0xffff
> > in the checksum function.
>
> You do realize that ICMPv4 reply code is not the only user of those,
> right? Sure, we can special-case it there. And audit the entire
> call tree, proving that no other call chains need the same.
>
> Care to post the analysis? I have the beginnings of that and it's already
> long and convoluted and touches far too many places, all of which will
> have to be watched indefinitely, so that changes in there don't introduce
> new breakage.
>
> I could be wrong. About many things, including the depth of your
> aversion to RTFS. But frankly, until that analysis shows up somewhere,
> I'm going to ignore your usual handwaving.

I've just read RFC 792 and done some experiments.
The kernel ICMP checksum code is just plain broken.

RFC 792 is quite clear that the checksum is the 16-bit ones's
complement of the one's complement sum of the ICMP message
starting with the ICMP Type.

The one's complement sum of 0xfffe and 0x0001 is zero (not the 0xffff
that the adc loop generates.
So it's one's complement is 0xffff not 0x0000.
So the checksum field in an ICMP message should never contain zero.

Now for the experiments...

Run: 'tcpdump -n -x icmp' in one window to trace the icmp messages.
Elsewhere run 'ping -c1 -s2 -p 0000 host'
The last 6 bytes of the ICMP echo request are the ICMP data eg:
0800 c381 347d 0001 0000
cmd sum id seq data
If you repeat the request the 'id' will increase by one or two.
Replace data with the checksum - so ping -c1 -s2 -p c381
You won't be quick enough, the checksum will probably be fffd.
But nearly there...
Repeat but subtract (say) 8 from the old checksum.
Then issue the command a few times and the packet checksum
should go from 0004 down to 0001 then jump to ffff.
But you'll see a 0000 instead of the 0xffff.

Note that the buffer being summed isn't all zeros but the
checksum field is still wrong.

I suspect that the real problem is that the value returned
by csum_fold() should never be put into a packet that is being
transmitted because the domain is [0..0xfffe] not [1..0xffff].

I bet ICMP isn't the only place where a transmitted checksum
ends up being zero.
As I've said before UDP4 treats is as no-checksum (so assume valid)
and UDP6 states the field must not be zero.

David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)