linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Linus Torvalds <torvalds@linux-foundation.org>
To: "Theodore Ts'o" <tytso@mit.edu>
Cc: Kees Cook <keescook@chromium.org>,
	Justin Stitt <justinstitt@google.com>,
	 Peter Zijlstra <peterz@infradead.org>,
	Mark Rutland <mark.rutland@arm.com>,
	 linux-hardening@vger.kernel.org, linux-kernel@vger.kernel.org,
	 llvm@lists.linux.dev
Subject: Re: [RFC] Mitigating unexpected arithmetic overflow
Date: Thu, 9 May 2024 08:38:28 -0700	[thread overview]
Message-ID: <CAHk-=wgKyP2ffZPa6aKYtytzzFibiNVN5MS=D2cn7_UGCECKdw@mail.gmail.com> (raw)
In-Reply-To: <20240509140854.GF3620298@mit.edu>

On Thu, 9 May 2024 at 07:09, Theodore Ts'o <tytso@mit.edu> wrote:
>
> struct ext2_super {
>        ...
>        __u32    time_lo;
>        __u32    time_high;
>        ...
> }
>
>         time_t  now;
>
>         sb->time_low = now;
>         sb->time_high = now >> 32;
>
> This is obviously (to a human) correct,

Actually, it's not correct at all.

If time_t is 32-bit, that "now >> 32" is broken due to how C shifts
are defined. For a 32-bit type, only shifts of 0-31 bits are
well-defined (due to hardware differences).

> but because of stupid compiler
> tricks, in order to silence compiler-level and ubsan complaints, this
> got turned into:
>
>         sb->time_low = now & 0xffffffff;
> #if (SIZEOF_TIME_T > 4)
>         sb->time_high = (now >> 32) & EXT4_EPOCH_MASK;
> #else
>         sb->time_high = 0;
> #endi

This is the wrong solution.

But the solution to the undefined shift isn't some #ifdef.

The idiomatic C solution is to do

        high_bits = (all_bits >> 16) >> 16;

which works even if 'all_bits' is 32 bit, and the compiler will know
this idiom, and turn it into just 0.

Going the other way is similar:

        all_bits = low_bits + ((u64) high_bits << 16) << 16);

and again, the compiler will recognize this idiom and do the right
thing (and if 'all_bits' is only 32-bit, the compiler will optimize
the high bit noise away).

And yes, this is not great, but there you have it: C was designed to
be a high-level assembler, and you see the effects of "this is how
many hardware shifters work". The shift instructions on many (most?)
architectures end up being limited to the word width.

We actually have some helpers for this in <linux/wordpart.h>:

  #define upper_32_bits(n) ((u32)(((n) >> 16) >> 16))
  #define lower_32_bits(n) ((u32)((n) & 0xffffffff))

but we don't have that "combine 32 bits into 64 bits" helper. Maybe
worth adding.

                Linus

  reply	other threads:[~2024-05-09 15:38 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-05-07 23:27 [RFC] Mitigating unexpected arithmetic overflow Kees Cook
2024-05-08 12:22 ` David Laight
2024-05-08 23:43   ` Kees Cook
2024-05-08 17:52 ` Linus Torvalds
2024-05-08 19:44   ` Kees Cook
2024-05-08 20:07     ` Linus Torvalds
2024-05-08 22:54       ` Kees Cook
2024-05-08 23:47         ` Linus Torvalds
2024-05-09  0:06           ` Linus Torvalds
2024-05-09  0:23           ` Linus Torvalds
2024-05-09  6:11           ` Kees Cook
2024-05-09 14:08             ` Theodore Ts'o
2024-05-09 15:38               ` Linus Torvalds [this message]
2024-05-09 17:54                 ` Al Viro
2024-05-09 18:08                   ` Linus Torvalds
2024-05-09 18:39                     ` Linus Torvalds
2024-05-09 18:48                       ` Al Viro
2024-05-09 19:15                         ` Linus Torvalds
2024-05-09 19:28                           ` Al Viro
2024-05-09 21:06                 ` David Laight
2024-05-18  5:11             ` Matthew Wilcox
2024-05-09 21:23           ` David Laight
2024-05-12  8:03           ` Martin Uecker
2024-05-12 16:09             ` Linus Torvalds
2024-05-12 19:29               ` Martin Uecker
2024-05-13 18:34               ` Kees Cook
2024-05-15  7:36           ` Peter Zijlstra
2024-05-15 17:12             ` Justin Stitt
2024-05-16  7:45               ` Peter Zijlstra
2024-05-16 13:30             ` Kees Cook
2024-05-16 14:09               ` Peter Zijlstra
2024-05-16 19:48                 ` Justin Stitt
2024-05-16 20:07                   ` Kees Cook
2024-05-16 20:51                   ` Theodore Ts'o
2024-05-17 21:15                     ` Kees Cook
2024-05-18  2:51                       ` Theodore Ts'o
2024-05-17 22:04                   ` Fangrui Song
2024-05-18 13:08               ` David Laight
2024-05-15  7:57           ` Peter Zijlstra
2024-05-17  7:45       ` Jonas Oberhauser
2024-05-11 16:19 ` Dan Carpenter
2024-05-13 19:43   ` Kees Cook
2024-05-14  8:45     ` Dan Carpenter
2024-05-18 15:39       ` David Laight

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAHk-=wgKyP2ffZPa6aKYtytzzFibiNVN5MS=D2cn7_UGCECKdw@mail.gmail.com' \
    --to=torvalds@linux-foundation.org \
    --cc=justinstitt@google.com \
    --cc=keescook@chromium.org \
    --cc=linux-hardening@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=llvm@lists.linux.dev \
    --cc=mark.rutland@arm.com \
    --cc=peterz@infradead.org \
    --cc=tytso@mit.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).