|
|
Subscribe / Log in / New account

Better handling of integer wraparound in the kernel

Better handling of integer wraparound in the kernel

Posted Feb 7, 2024 10:56 UTC (Wed) by farnz (subscriber, #17727)
In reply to: Better handling of integer wraparound in the kernel by milesrout
Parent article: Better handling of integer wraparound in the kernel

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.


to post comments

Better handling of integer wraparound in the kernel

Posted Feb 7, 2024 11:36 UTC (Wed) by Wol (subscriber, #4433) [Link] (1 responses)

In other words, as I read it, you shouldn't get wrapping in production because it will have panic'd and been fixed in testing.

Okay, okay, that's being optimistic, but that is the likely course of events ...

Cheers,
Wol

Better handling of integer wraparound in the kernel

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:


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");
}

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.


Copyright © 2025, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds