Live data from Hacker News

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

openwall.com

51–60 of 280 posts

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

#51
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…

D doesn't allow implicit narrowing conversions. The user has to have an explicit cast, like `cast(int) size`. Cast is made into a keyword so all those explicit conversions can be found with a simple grep.

We consider it best practice to try and organize the types such that explicit casts are minimized.

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

#52
post #9

Can we not have one integer type in c that can grow like in js as required and become bigint if too big?

We can do this in software because there's virtually no limit to the abstractions people make, but hardware doesn't work like that. At some point in the software stack we need to draw a line and say this is a 64-bit signed integer that hardware can understand.

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

#54
post #47
post #9

Can we not have one integer type in c that can grow like in js as required and become bigint if too big?

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…

I was working at Twitter when we learned this the hard way. We switched to a separate service for generating tweet IDs (instead of MySQL sequences), which for various distributed systems reasons meant IDs started taking up more bits. And when we stuck those bigger IDs into JSON responses in the API... well, we learned the dumbest lesson possible about the intersection between JSON, JavaScript, and double-precision floating-point. Later that day the "id_str" fields were born.

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

#55
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…

Languages of the same age or older than C, also have explicit narrowing, but apparently that was seen as programming with a straightjacket.

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

#56
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…

The compiler can issue warnings for this.

This os why in C it is a good practice to enable all compiler warnings and to have the compiler treat warnings as errors.

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

#57
post #47
post #9

Can we not have one integer type in c that can grow like in js as required and become bigint if too big?

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

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

#58
post #32
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…

> Some Rust developers argue that even "size as i32" should be avoided, and "size.try_into()" should be used instead, since it forces the programmer to treat an overflow explicitly at runtime, instead of silently wrapping. It's important to still have the option for efficient truncating semantics, though; some software (e.g. emulators) needs to chunk large integers into 2/4/8 smaller ones, and rotation + truncating a…

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 really hard to fix this in C++. Some of the Epoch proponents want to do so using epochs to get there, basically you'd have a "new" epoch of C++ in which narrowing must be explicit, and old code would continue to have implicit narrowing so it doesn't break.

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

#59

Earlier quoted context omitted.

Add Java to that list.

Same for C#. Any narrowing truncation needs to be an explicit cast. Widening is typically allowed implicitly, although in the case of the 'decimal' (128 bit struct representing a 'higher precision' floating point) type you still need an explicit cast from a 'double', since there are cases where that conversion can still change the value or fail (i.e. Infinity/NaN)

Microsoft is considering turning on by default checked arithmetic in the 2022 Visual Studio templates, by the way.

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

#60
post #8

I love the little nugget in the mitigations section. You can plug the hole for a normal filesystem, but then FUSE filesystems have an additional problem: "if an attacker FUSE-mounts a long directory (longer than 8MB), then systemd exhausts its stack, crashes, and therefore crashes the entire operating system (a kernel panic)." If there's one place other than the kernel where truly defensive programming should be appl…

Wait how does a user space daemon exhausting its stack lead to a kernel panic?
Post reply on HN