Live data from Hacker News

size_t-to-int vulnerability in Linux’s filesystem layer

openwall.com

81–90 of 280 posts

Re: size_t-to-int vulnerability in Linux’s filesystem layer

#81
post #63

Earlier quoted context omitted.

Right, this is a small infelicity in Rust, it is easier to write let x = size as i32; ... even if what you meant was closer to let x: i32 = size.try_into().expect("We are 100% sure size is small enough to fit into x"); But at least it isn't C or C++ where you might accidentally write x = size; ... and the compiler doesn't even warn you that size is bigger than x and you need to think about what you intended. It's rea…

> and the compiler doesn't even warn you that size is bigger than x That's not true tho, compiler with reasonable flags set will definitely warn you and if you really don't like this kind of code you can force compiler to issue an error instead

Fair point although it seems "reasonable" varies from one platform to another, it doesn't warn out of the box for me but people have reported MSVC gets warnings here.

Re: size_t-to-int vulnerability in Linux’s filesystem layer

#82
post #72
post #63

Earlier quoted context omitted.

> and the compiler doesn't even warn you that size is bigger than x That's not true tho, compiler with reasonable flags set will definitely warn you and if you really don't like this kind of code you can force compiler to issue an error instead

What flags you have in mind? Because this code doesn't generate any warning with GCC 11.1.0 with -Wall -Wextra: int main(void) { int some_int = 1234567; char c = some_int; return c; }

-Wall -Wextra -Wpedantic does not enable all diagnostics.

This is GNU's idea of "all".

Contrast to Clang's -Weverything, which will.

Re: size_t-to-int vulnerability in Linux’s filesystem layer

#83
post #7

This kind of issue is the reason why some more modern languages like Rust or Go do not have implicit narrowing conversions. For instance, on Rust, trying to simply pass an usize (Rust's equivalent of size_t) to a function which expects an i32 (Rust's equivalent of int) will not compile; the programmer has to write "size as i32" (Rust's equivalent of "(int) size"), which makes it explicit that it might truncate the va…

This wouldn't be a problem if "int" was defined as the same size as size_t. The solution is probably to change all those functions to take a parameter of size_t instead of int.

IMHO one should always be using C99 types instead of int, but Linux predates that.

Also, shouldn't that implicit conversion cause a compiler warning?

Re: size_t-to-int vulnerability in Linux’s filesystem layer

#84
post #72
post #63

Earlier quoted context omitted.

> and the compiler doesn't even warn you that size is bigger than x That's not true tho, compiler with reasonable flags set will definitely warn you and if you really don't like this kind of code you can force compiler to issue an error instead

What flags you have in mind? Because this code doesn't generate any warning with GCC 11.1.0 with -Wall -Wextra: int main(void) { int some_int = 1234567; char c = some_int; return c; }

Clang-tidy has a check for it: https://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidel...

Re: size_t-to-int vulnerability in Linux’s filesystem layer

#85
post #26

Earlier quoted context omitted.

Rust doesn't allow them either: https://play.rust-lang.org/?version=stable&mode=debug&editio... Adding .into() works though, which is the recommended method if the conversion can be statically guaranteed (otherwise try_into should be used, which will become easier in the 2021 edition as the TryInto trait will become part of the prelude).

into() does not work from size. It's rather frustrating in practice. https://stackoverflow.com/questions/62832438/why-is-rusts-us...

Yeah, that is frustrating since there are no platforms where that would fail today, and it's hard to imagine why we would ever want one with 256bit pointers.

We don't even use full 64bit pointers today on x64.

Re: size_t-to-int vulnerability in Linux’s filesystem layer

#86
post #68
post #3

Earlier quoted context omitted.

AFAIK most compilers by default will output a warning in this case.

They can't warn by default, because on some platforms long->int isnt a narrowing conversion.

The compiler knows what platform it's compiling the code for, though.

Re: size_t-to-int vulnerability in Linux’s filesystem layer

#87
post #7

This kind of issue is the reason why some more modern languages like Rust or Go do not have implicit narrowing conversions. For instance, on Rust, trying to simply pass an usize (Rust's equivalent of size_t) to a function which expects an i32 (Rust's equivalent of int) will not compile; the programmer has to write "size as i32" (Rust's equivalent of "(int) size"), which makes it explicit that it might truncate the va…

This wouldn't be a problem if "int" was defined as the same size as size_t. The solution is probably to change all those functions to take a parameter of size_t instead of int. IMHO one should always be using C99 types instead of int, but Linux predates that. Also, shouldn't that implicit conversion cause a compiler warning?

so you mean int_fastX_t or int_leastX_t?

Re: size_t-to-int vulnerability in Linux’s filesystem layer

#88
post #78

Earlier quoted context omitted.

As a interesting side note: The "as" operator is often considered to have been a mistake. Both because of unchecked casts and because of "doing to much". So I wouldn't be surprised if in the (very) long term there will be a rust edition deprecating `as` casts (after we have alternatives to all cast done with `as`, which are: Pointer casts, dyn casts/explicit coercion and truncating integer casts, for some we already…

I would prefer not to see that happen, I'm fine with as and the safer options as they are currently. It would be a big job to update all the code in the wild when you want to move to the newer edition.

You don't need to do that. Rust editions are fully backwards-compatible, since they can depend on code from different editions.

Re: size_t-to-int vulnerability in Linux’s filesystem layer

#89
post #2

> Unfortunately, this size_t is also passed to functions whose size argument is an int (a signed 32-bit integer), not a size_t. Is this the type of things that could be caught by a linter or strict compilation rules? This seems to be to be a failure of the type system.

Yes, it is the type of thing caught by a linter or strict compilation rules.

https://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidel...

But strict compilation rules (eg, clang's -Weverything) mainly only work if you treat them as errors (so -Werror), and then some of those strict are then also questionable at best, and just outright annoyingly wrong at worst. For example, unused parameter warnings on virtual methods are a waste of time to deal with. It's not a symptom of a bug most of the time, so it being an error just generates workaround churn or you end up just disabling the warning and then maybe that bites you the few times it would have pointed out an actual issue.

Beyond the blanket ones like clang's -Weverything, it can otherwise be a job to keep up with compiler upgrades and the vast number of warning options they have.

Re: size_t-to-int vulnerability in Linux’s filesystem layer

#90
post #47

Earlier quoted context omitted.

Haha, yeah JS integers "can grow". Kind of. And then they bite you in the worst way possible. Especially when combined with cryptography (e.g. nonces). Try this: >> const x = 288230376151711740; >> x == x + 1 true Or this: >> 2\*1024 Infinity JS doesn't even have integers. It only has floats. JS is by far the worst language I know of when it comes to integer support. If you want a better example of arbitrary precisio…

Neat trick. Math.pow(2, 53) == Math.pow(2, 53) + 1 This is a bit clearer I think. The addition just barely overflows the 53 mantissa bits of the IEEE 754 double precision floating point number. By the way, JS has BigInts these days, which are supported by all major browsers: https://caniuse.com/bigint >> const x = 288230376151711740n; >> x == x + 1n false

  2**53 == 2**53+1
^^ even more clear.

That's why Number.isSafeInteger(a) exists.

Integers up to +/- 9007199254740991 (Number.MAX_SAFE_INTEGER) are fine.

Post reply on HN