Fix buffer overflow and nul-byte replacement in error handling#243
Fix buffer overflow and nul-byte replacement in error handling#243
Conversation
42f9e11 to
08332dc
Compare
| let err_string = e.to_string(); | ||
| out_error_string.copy_from_nonoverlapping(err_string.as_ptr().cast(), err_string.len()); | ||
| out_error_string.add(err_string.len()).write(0); | ||
| let len = err_string |
There was a problem hiding this comment.
Before talking about the new code - I'm a bit confused by the previous code.
Isn't this redundant with what already happens inside _network_open? Why are we "re-copying" the error text?
There was a problem hiding this comment.
I don't think so? The error originates in Rust code (in _network_open()), and we check for an error, returning early to the facade if it does. I don't think we're re-copying anything: we're copying the stringified Rust error message into the libproj buffer.
- Add bounds checking using error_string_max_size before writing error strings - Fix incorrect character replacement: use '\0' (nul byte) instead of '0' (digit) Signed-off-by: Stephan Hügel <shugel@tcd.ie>
a081b87 to
e7b9040
Compare
michaelkirk
left a comment
There was a problem hiding this comment.
This seems like an improvement, good finds!
| let err_string = e.to_string().replace('0', "nought"); | ||
| out_error_string.copy_from_nonoverlapping(err_string.as_ptr().cast(), err_string.len()); | ||
| out_error_string.add(err_string.len()).write(0); | ||
| let err_string = e.to_string().replace('\0', ""); |
There was a problem hiding this comment.
I agree, the previous code was wrong (the character '0' is not the null terminator).
// since this isn't a conversion using CString, nul chars must be manually stripped
This error message is coming from rust code, so the purpose of this code is to detect the situation where some rust developer includes a NULL in their string output, right?
Rust strings can contain NULL (as many times as they want) but it seems absolutely unhinged to do so. If we do want to be protective in this way, I guess we should check on line 164 too?
Also (take it or leave it), could we use the CString handling? I think it'd look something like:
Err(e) => {
let err_string = CString::new(e.to_string()).unwrap_or(c"Error while buildling error message: Unable to report error specifics".into());
let bytes = &err_string.as_bytes_with_nul();
let len = bytes.len().min(error_string_max_size);
out_error_string.copy_from_nonoverlapping(bytes.as_ptr().cast(), len);
0
}Is it "better"? IDK. Interacting with C is such a bummer.
NB: this PR is tool-assisted (Claude Opus 4.5)
CHANGES.mdorCHANGELOG.md