![]() |
|
Message-ID: <CAEoi9W7U8DymJtorgkpoeTZhw2KqAhwJjaaj+M16pK9rXw_m8w@mail.gmail.com> Date: Mon, 29 Sep 2025 14:02:17 -0400 From: Dan Cross <crossd@...il.com> To: oss-security@...ts.openwall.com Subject: Re: How to do secure coding and create secure software On Mon, Sep 29, 2025 at 12:49 PM Dan Cross <crossd@...il.com> wrote: > [snip] > For example, in your original email, you mention validating the length > of a 0-terminated C string. You suggest that one may use the `strnlen` > function to do this, since there's no guarantee that an input buffer > actually contains a 0 terminator (i.e., it may not be a string). > Further you say, "For example, you can specify that the minimum length > of a string argument should be 1 and the maximum length of the string > argument should be 1024." You then write, "The code will be 'len = > strnlen(str, 1025); if (len == 1025) { return error; }'". Well, now > we have an ambiguity; C defines "the string" as containing the 0 > terminating byte (cf eg C18, sec 7.1.1 para 1: "A string is a > contiguous sequence of characters terminated by and including the > first null character"). `strlen`, on the other hand, returns the > number of characters before the terminating zero, which is not the > same thing. Did you really mean the maximum length of the string, or > did you mean its size? > > Suppose that you truly meant that the maximum length, e.g., as would > be returned by `strlen`, should be 1024; then that string's _size_ > could be up to 1025, as for a maximally sized string the terminating > null character would be the 1025'th char. But this code returns an > error on the value 1025; clearly this rejects a maximum length string. Oops, and I'm off by one myself here: if b[1024]==0, then the return value of `strnlen` is 1024, not 1025. But regardless, the subsequent point stands: the function, as written, is ambiguous with respect to length and size. - Dan C. > Reading between the lines, it appears what you mean is that the > string's maximum _size_ is 1024, as the code clearly intends to find > the terminating zero within the first 1024 characters, which would > yield a maximum length of 1023, not 1024. But in that case, you're > looking at up to 1025 characters, one beyond the size of the string: > consider what happens in the case of a pointer that points to 1024 > bytes of validly mapped memory, but those 1024 bytes end on a page > boundary, and the subsequent page is unmapped. > > In either case, your example code appears to exhibit a classic > off-by-one error, and can be tricked into either looking beyond the > end of a valid memory object (if max len == 1023 and max size == > 1024), or failing to properly accept valid strings (if max len == 1024 > and max size == 1025). The error here is in assuming that the return > value of `strnlen`, as you have used it, is enough to robustly > establish that the string ends within the acceptable bounds. > > Sure, this is easy enough to fix in this case (hint: read up on the > `memchr` function). But beyond that simple error, C provides you with > _no way_ to determine whether a given `char *`, when provided as an > argument to an arbitrary function, points into a valid object of your > arbitrarily chosen length. So already your advice is impossible to > follow in the general case. > > > Now, coming to the above point number 2: > > > > An example of openssh is given that it first does authentication and then it does encryption and this is insecure. I will investigate this and reply later. > > Another area you don't touch on at all are TOCTOU bugs. > > I suggest, perhaps, studying a bit more. > > - Dan C.
Powered by blists - more mailing lists
Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.