mbox

[GIT,PULL] bug fix for devicetree memory parsing

Message ID CACxGe6vFHADzsE7_69B+jjT3kwX_3kOdUBzjtSVEYETwR7HY3Q@mail.gmail.com
State New
Headers show

Pull-request

git://git.secretlab.ca/git/linux tags/dt-for-linus

Message

Grant Likely July 6, 2014, 9:37 a.m. UTC
Hi Linus,

Can you pull this bug fix into your tree please?

Thanks,
g.

The following changes since commit a497c3ba1d97fc69c1e78e7b96435ba8c2cb42ee:

  Linux 3.16-rc2 (2014-06-21 19:02:54 -1000)

are available in the git repository at:

  git://git.secretlab.ca/git/linux tags/dt-for-linus

for you to fetch changes up to a67a6ed15513541579d38bcbd127e7be170710e5:

  of: Check for phys_addr_t overflows in early_init_dt_add_memory_arch
(2014-06-26 17:28:28 +0100)

----------------------------------------------------------------
Devicetree bugfixe for v3.16

Important bug fix for parsing 64-bit addresses on 32-bit platforms.
Without this patch the kernel will try to use memory ranges that cannot
be reached.

----------------------------------------------------------------
Laura Abbott (1):
      of: Check for phys_addr_t overflows in early_init_dt_add_memory_arch

 drivers/of/fdt.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Comments

Linus Torvalds July 6, 2014, 7:24 p.m. UTC | #1
On Sun, Jul 6, 2014 at 2:37 AM, Grant Likely <grant.likely@linaro.org> wrote:
>
> Can you pull this bug fix into your tree please?

I took it, but I think both your explanation and the patch itself is
actually crap. It may fix the issue, but it's seriously confused.

Your explanation says that it's a 32-bit platform issue. No it's not.
Most 32-bit configurations still have a 64-bit phys_addr_t (ie
PAE/LPAE etc).

And the code is crap, because it uses ULONG_MAX etc in ways that
simply make no f*cking sense. And why does it care about sizeof?

Why does the code not just do something like

  #define MAX_PHYS_ADDR ((phys_addr_t) ~0)

and then do

  if (base > MAX_PHYS_ADDR || base + size > MAX_PHYS_ADDR)
    ...

and be done with it? All those sizeof tests are completely pointless.
If it turns out that phys_addr_t is the same size as u64, then the
tests will never be true, and the compiler will happily optimize them
away.

So I think this fixes a problem, but it's all ugly as hell. I ended up
pulling it because I'm lazy and don't have a machine to test a proper
fix on anyway, but I hope this can get cleaned up. And more
importantly, I hope maintainers will spend a bit more time thinking
about things like this. It's not just that the code is unnecessarily
complex, it's WRONG. Comparing things to "ULONG_MAX" makes absolutely
zero sense, since "ULONG_MAX" has nothing to do with anything. It's
just stupid and misleading, and it just so happens to work by random
luck because it so *happens* that phys_addr_t is smaller than "u64"
only when ULONG_MAX happens to be the same size. But even that is not
guaranteed (ie some stupid broken architecture might have a 32-bit
physical address space despite having a 64-bit "long")

                Linus
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Grant Likely July 7, 2014, 12:52 a.m. UTC | #2
On Sun, Jul 6, 2014 at 8:24 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
> On Sun, Jul 6, 2014 at 2:37 AM, Grant Likely <grant.likely@linaro.org> wrote:
>>
>> Can you pull this bug fix into your tree please?
>
> I took it, but I think both your explanation and the patch itself is
> actually crap. It may fix the issue, but it's seriously confused.
>
> Your explanation says that it's a 32-bit platform issue. No it's not.
> Most 32-bit configurations still have a 64-bit phys_addr_t (ie
> PAE/LPAE etc).
>
> And the code is crap, because it uses ULONG_MAX etc in ways that
> simply make no f*cking sense. And why does it care about sizeof?
>
> Why does the code not just do something like
>
>   #define MAX_PHYS_ADDR ((phys_addr_t) ~0)
>
> and then do
>
>   if (base > MAX_PHYS_ADDR || base + size > MAX_PHYS_ADDR)
>     ...

Sure. I'll make sure a cleanup patch gets written and queued up.

g.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
Linus Torvalds July 8, 2014, 5:55 p.m. UTC | #3
On Sun, Jul 6, 2014 at 12:24 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> Why does the code not just do something like
>
>   #define MAX_PHYS_ADDR ((phys_addr_t) ~0)
>
> and then do
>
>   if (base > MAX_PHYS_ADDR || base + size > MAX_PHYS_ADDR)

Actually, there's an even better model, which is to just check if a
value fits in a type.

You could do something like

  #define FITS(type, value) ((value) == (type)(value))

and then you can just use

    if (!FITS(phys_addr_t, base) || !FITS(phys_addr_t, base+size))

instead. The compiler will trivially turn the comparisons into no-ops
if the type is sufficient to hold the value.

We already do this in a few places, it might even be worth it making a
generic macro. People have been confused by the "x == x" kind of
comparisons before, see for example fs/buffer.c:grow_buffers(), which
does

        index = block >> sizebits;
        if (unlikely(index != block >> sizebits)) {

where "index" is a pgoff_t, but "block >> sizebits" is a sector_t, so
that comparison actually checks that "block >> sizebits" fits in the
type, even though it looks like it compares the same computed value
against itself.

           Linus
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/