Better handling of integer wraparound in the kernel
Better handling of integer wraparound in the kernel
Posted Feb 7, 2024 8:24 UTC (Wed) by milesrout (subscriber, #126894)In reply to: Better handling of integer wraparound in the kernel by tialaramex
Parent article: Better handling of integer wraparound in the kernel
"You can only shoot yourself in the foot if you hold it wrong"
"Only incorrect programs have this problem" is the exact issue Rust is meant to prevent. What's the point of Rust if it doesn't prevent one of the most common sources of vulnerabilities?
Posted Feb 7, 2024 10:48 UTC (Wed)
by atnot (guest, #124910)
[Link]
> What's the point of Rust if it doesn't prevent one of the most common sources of vulnerabilities?
The main reason overflows lead to vulnerabilities is by breaking bounds checks. Since bounds checks are still applied by the compiler in a safe after whatever math you did, there's not really any way to turn it into a memory vulnerability. Unless you're manually writing bound checks in unsafe Rust, which is honestly pretty rare.
Posted Feb 7, 2024 10:56 UTC (Wed)
by farnz (subscriber, #17727)
[Link] (2 responses)
The different fully-defined behaviours are, in practice, not a common source of vulnerabilities; by default, in production, you get wrapping (2s complement wrapping if signed), in development you get panics.
This differs from the issue in C, where overflow is a common source of vulnerabilities since it's not defined for signed integers, and thus the compiler is allowed to surprise a developer.
Posted Feb 7, 2024 11:36 UTC (Wed)
by Wol (subscriber, #4433)
[Link] (1 responses)
Okay, okay, that's being optimistic, but that is the likely course of events ...
Cheers,
Posted Feb 7, 2024 12:07 UTC (Wed)
by farnz (subscriber, #17727)
[Link]
That's one component of it; the other is that if it does wrap, you're not going to be surprised by the resulting behaviour, whereas in C, you can get weirdness where overflowing signed arithmetic does unexpected things. Taking the following code as an example:
In standard C semantics, because arithmetic overflow is undefined, it is legal for all four comparisons to evaluate to true, and thus for all four printfs to print. In Rust semantics, because of the wraparound rule. c will be equal to (the equivalent of) INT_MAX - 4, and thus only the b < c condition is true.
This, in turn, means that you're less likely to be surprised by the result in Rust, since it's at least internally consistent, even if it's not what you intended. And thus, if you use the result of the arithmetic operation to do something like indexing an array, instead of the compiler being able to go "well, clearly c should be zero here, so I can elide the bounds check", the compiler does the bounds check and panics for a different reason (index out of bounds). You've now got an "impossible" error, and can debug it.
Note that this relies on Rust's memory safety guarantees around indexing; if you used pointer arithmetic with c instead, you could get an out-of-bounds read, and hence have trouble. The only thing that helps here is that pointer dereferencing is unsafe, and hence if you get unexpected SIGSEGVs or similar, that's one of the first places you'll look.
Better handling of integer wraparound in the kernel
Better handling of integer wraparound in the kernel
Better handling of integer wraparound in the kernel
Wol
Better handling of integer wraparound in the kernel
int a = 5;
int b = INT_MIN;
int c = b - a;
if (c < b) {
printf("c less than b\n");
}
if (b < c) {
printf("b less than c\n");
}
if (c == 0) {
printf("c is zero\n");
}
if (b == c) {
printf("b equals c\n");
}
