Hey Willy, On 12/7/15, 2:22 PM, "Willy Tarreau" <[email protected]> wrote: >I'm sorry but this is not acceptable. We're hiding a deeper bug somewhere. >Strncpy() is used at other places in the code (a few I agree) and is used >by *a lot* of programs, it's a basic building block. If it's broken in one >version of gcc, it will quickly be fixed, and/or we may have to deploy >workarounds for other places as well. Instead I guess that strncpy() is >detecting a bug that memcpy() doesn't detect so until we find the real >root cause of all of this with a proof that strncpy() contains the real >bug and why it doesn't affect other places, we must not hide it because >I'm pretty sure it will strike back later. Or at least I'd like to see >a pointer to the corresponding bugzilla entry in gcc's bugtracker. I >could imagine one reason being that the sni_keytype would be packed >(for what reason ?) and that the string pointer would start unaligned >and would cause some of strncpy()'s vector optims to fail. But that >sounds extremely strange. By experience when a program dies from such >a small change, it's a latent memory dereference that gets optimized >differently and which manifests itself via memory manipulation functions. >Note that I'm not defending gcc, you might have seen a number of angry >comments from me against it in the code. I just want to be sure we're >addressing the real issue instead of hiding it.
I completely understand where you¹re coming from so lets try to fix this as best as we can. So I followed this to the gcc bugzilla as you suggested and voila: bogus buffer overflow warning and abort on flexible array member in a child object https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60792 Which is exactly what I¹m doing. This isn¹t a bug though, just a different use pattern than what GCC allows for. In this case, the suggestion was to use memcpy. I feel that my patch does exactly what is suggested in that thread. > >(...) > >I'm seeing a buffer overflow in the code prior to the bug seeing the >crash, >though its unlikely to trigger but it's here : > > for (i = 0; i < trash.size; i++) { > > if (!str[i]) > > break; > > trash.str[i] = tolower(str[i]); > > } > > trash.str[i] = 0; > > >As you can see, if you don't find a 0 in the trash, it will overwrite the >first character not part of the trash buffer. This pattern I copied from other code in HAProxy, so I thought it would be acceptable. Also, I¹m not sure what you mean by "don't find a 0 in the trash". It¹s looking through str for the null terminator, which came from reading the CN/SAN. > >(...) > >@@ -1808,7 +1808,10 @@ static void >ssl_sock_populate_sni_keytypes_hplr(const char *str, struct eb_root > if (!node) { > /* CN not found in tree */ > s_kt = malloc(sizeof(struct sni_keytype) + i + 1); >- strncpy((char *)s_kt->name.key, trash.str, i); >+ /* Using memcpy here instead of strncpy. >+ * strncpy will cause sig_abrt errors under certain version of >gcc >with -O2 >+ */ >+ memcpy(s_kt->name.key, trash.str, i); > s_kt->name.key[i] = 0; > s_kt->keytypes = 0; > ebst_insert(sni_keytypes, &s_kt->name); > >It might be useful to display s_kt, s_kt->name.key, sizeof(struct >sni_keytype) >and i at this place to understand what upsets gcc/strncpy(). If we have to >switch to memcpy() (which I prefer in general), you can remove the manual >addition of the trailing 0 by adding 1 to the size of the memcpy() since >it's guaranteed to cover the zero. Given the above, did you still want me to remove the code to add the trailing 0? -Dave

