Earlier quoted context omitted.
Its weird though because looking through the hackone reports in the slop wiki page there aren't actually reproduction steps. It's basically always just a line of code and an explanation of how a function can be mis-used but not a "make a webserver that has this hardcoded response". So like why doesn't the person iterate with the AI until they understand the bug (and then ultimately discover it doesn't exist)? Like ha…
As long as the number of people newly being convinced that AI generated bounty demands are a good way to make money equals or exceeds the number of people realising it isn't and giving up, the problem remains. Not helped, I imagine, that once you realise it doesn't work, an easy pivot is to start convincing new people that it'll work if they pay you money for a course on it.
No strcpy either
51–60 of 151 posts
Re: No strcpy either
#52This makes a lot of sense but one time I find this gets messy is when there’s times I need to do checks earlier in a dataset’s lifetime. I don’t want to pay to check multiple times, but I don’t want to push the check up and it gets lost in a future refactor.
I’m imagining a metadata for compile time that basically says, “to act on this data it must have been first checked. I don’t care when, so long as it has been by now.” Which I’m imagining is what Rust is doing with a Result type? At that point it stops mattering how close to code a check is, as long as you type distinguish between checked and unchecked?
Re: No strcpy either
#53Take the best case scenario, copying a string where the precise length is unknown but we know it will always fit in, say, 64 bytes.
In earlier days, I would always have used strcpy() for this task, avoiding the "wasteful" extra copies memcpy() would make. It felt efficient, after all you only replace a i But of course it doesn't actually work that way, copying one byte at a time is inefficient so instead we copy as many as possible at once, which is easy to do with just a length check but not so easy if you need to find the null byte. And on top of that you're asking the CPU to predict a branch that depends completely on input data.
Re: No strcpy either
#54Earlier quoted context omitted.
Yeah but fixed width strings don’t need null termination. You know exactly how long the string is. No need to find that null byte.
Good luck though remembering not to pass one to any function that does expect to find a null terminator.
Re: No strcpy either
#55I've always wondered at the motivatons of the various string routines in C - every one of them seems to have some huge caveat which makes them useless. After years I now think it's essential to have a library which records at least how much memory is allocated to a string along with the pointer. Something like this: https://github.com/msteinert/bstring
A library that records how much memory is allocated to a string along with the pointer isn't a necessity.
Most people who write in C professionally are completely used to it although the footgun is (and all of the others are) always there lurking.
You'd generally just see code like this:-
char hostname[20];
...
strncpy( hostname, input, 20 );
hostname[19]=0;
The problem obviously comes if you forget the line to NUL that last byte AND you have a input that is greater than 19 characters long.(It's also very easy to get this wrong, I almost wrote `hostname[20]=0;` first time round.)
I remember debugging a problem 20+ years ago on a customer site with some software that used Sybase Open/Server that was crashing on startup. The underlying TDS communications protocol (https://www.freetds.org/tds.html) had a fixed 30 byte field for the hostname and the customer had a particularly long FQDN that was being copied in without any checks on its length. An easy fix once identified.
Back then though the consequences of a buffer overrun were usually just a mild annoyance like a random crash or something like the Morris worm. Nowadays such a buffer overrun is deadly serious as it can easily lead to data exfiltration, an RCE and/or a complete compromise.
Heartbleed and Mongobleed had nothing to do with C string functions. They were both caused by trusting user supplied payload lengths. (C string functions are still a huge source of problems though.)
Re: No strcpy either
#56Re: No strcpy either
#57Well if you bother looking up that it's originally created for non null-terminated strings, then it kinda makes sense.
The real problem begun when static analyzers started to recommend using it instead of strcpy (the real alternative used to be snprintf, now strlcpy).
Re: No strcpy either
#58Earlier quoted context omitted.
strncpy doesn’t handle overlapping buffers (undefined behavior). Better to use strncpy_s (if you can) as it is safer overall. See: https://en.cppreference.com/w/c/string/byte/strncpy.html . As an aside, this is part of the reason why there are so many C successor languages: you can end up with undefined behavior if you don’t always carefully read the docs.
Back when strncpy was written there was no undefined behaviour (as the compiler interprets it today). The result would depend on the implementation and might differ between invocations, but it was never the "this will not happen" footgun of today. The modern interpretation of undefined behaviour in C is a big blemish on the otherwise excellent standards committee, committed (hah) in the name of extremely dubious perf…
In general, I see two issues at play here:
1. C relies heavily on unsized pointers (vs. fat pointers), which is why strncpy_s had to "break" strncpy in order to improve bounds checks.
2. strncpy memory aliasing restrictions are not encoded in the API and can only be conveyed through docs. This is a footgun.
For (1), Rust APIs of this type operate on sized slices, or in the case of strings, string slices. Zig defines strings as sized byte slices.
For (2), Rust enforces this invariant via the borrow checker by disallowing (at compile-time) a shared slice reference that points to an overlapping mutable slice reference. In other words, an API like this is simply not possible to define in (safe) Rust, which means you (as the user) do not need to pore over the docs for each stdlib function you use looking for memory-related footguns.
Re: No strcpy either
#59I've always wondered at the motivatons of the various string routines in C - every one of them seems to have some huge caveat which makes them useless. After years I now think it's essential to have a library which records at least how much memory is allocated to a string along with the pointer. Something like this: https://github.com/msteinert/bstring
Yet software developed in C, with all of the foibles of its string routines, has been sold and running for years with trillions of USD is total sales. A library that records how much memory is allocated to a string along with the pointer isn't a necessity. Most people who write in C professionally are completely used to it although the footgun is (and all of the others are) always there lurking. You'd generally just…
This doesn't seem very relevant. The same can be said of countless other bad APIs: see years of bad PHP, tons of memory safety bugs in C, and things that have surely led to significant sums of money lost.
> It's also very easy to get this wrong, I almost wrote `hostname[20]=0;` first time round.
Why would you do this separately every single time, then?
The problem with bad APIs is that even the best programmers will occasionally make a mistake, and you should use interfaces (or...languages!) that prevent it from happening in the first place.
The fact we've gotten as far as we have with C does not mean this is a defensible API.
Re: No strcpy either
#60The AI chatbot vulnerability reports part sure is sad to read. Why is this even a thing and isn't opt-in? I dread the idea of starting to get notifications from them in my own projects.
Because humans generate and relay the slop-reports in the hopes of being helpful
And even if not, the motivation is building a reputation as a security “expert”.