Live data from Hacker News

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

openwall.com

91–100 of 280 posts

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

#91
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.

I don't see it as a big job. Am I wrong?

Imagine there's a suitable narrow::() function introduced which has the same consequence, always narrowing, if your data was too wide it may drop important stuff on the floor, and narrow() just says that's too bad.

Rust 2030 can introduce narrow::(), warn for narrowing as usage and then Rust 2035 can error for as. The Rust 2030 -> 2035 conversion software can consume code that does { x as y } and write { x.narrow::() } instead. This code is not better but it's still working in Rust 2035 and this explicit narrow() function is less tempting for new programmers than as IMO.

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

#92
post #72

Earlier quoted context omitted.

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.

keep in mind though that -Weverything is not intended to be used in production: https://quuxplusone.github.io/blog/2018/12/06/dont-use-wever...

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

#93

I've always thought implicit parameter conversion in general (narrowing or otherwise) was fraught at worst, and code smell at best. If some function takes a size_t, why are you passing something other than a size_t to it? If your eventual call into "code you don't control" takes type X, make sure the value that you eventually pass is type X all the way through the code you do control. Even casting is kind of the lazy…

And it's not just parameter passing. It can apply to anything that acts like an assignment. That includes assignment (of course), parameter passing, and returning a value from a function.

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

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

In swift:

    //  a is a UInt64
    let a = Int.random(in: 0..

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

#95
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?

Linux apparently provides a similarly named set of sized integer types to Rust, ie: s8 u8 s16 u16 s32 u32 s64 u64

But of course getting C programmers to use these integer types rather than the ones they grew up with isn't easy.

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

#96
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?

> This wouldn't be a problem if "int" was defined as the same size as size_t.

That would lead to a hole in the type sequence (char > IMHO one should always be using C99 types instead of int, but Linux predates that.

On the other hand, on Linux "long" has always been defined as the same size as size_t, so using "long" instead of "int" everywhere could also be an option.

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

#97
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; }

>What flags you have in mind?

-Wconversion

https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

This is common knowledge for ages. Any cursory Google search returns countless answers.

Take this post made over a decade ago.

https://stackoverflow.com/questions/1730255/gcc-shouldnt-a-w...

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

#98
post #33

Earlier quoted context omitted.

It warns if you add -Wconversion. Unfortunately, that flag generates lots of false positives (at least in gcc), so using it isn't always a good idea.

What kind of false positives are you seeing with gcc? Personally I have never seen gcc spitting out a false positive. IMO it's always a good idea to explicitly downcast even if you know that it's 'safe'. That way someone else will see instantly what's going on. The fact that Rust requires it should tell us something.

For example, I've just reported this: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101537

You can find more cases in the bugtracker. To be fair, it seems many of them were fixed in recent releases.

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

#100
post #32

Earlier quoted context omitted.

> 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 rea…

[deleted]
Post reply on HN