Path: ...!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Kaz Kylheku <433-929-6894@kylheku.com> Newsgroups: comp.lang.c Subject: Re: A Famous Security Bug Date: Thu, 21 Mar 2024 20:21:14 -0000 (UTC) Organization: A noiseless patient Spider Lines: 70 Message-ID: <20240321131621.321@kylheku.com> References: <20240320114218.151@kylheku.com> <20240321211306.779b21d126e122556c34a346@gmail.moc> Injection-Date: Thu, 21 Mar 2024 20:21:14 -0000 (UTC) Injection-Info: dont-email.me; posting-host="8a88f4f3d1bb162453330ac9f4d394b5"; logging-data="2546182"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18EWlZNvykcYP4fzip3Yzm7wZiybQRpVF4=" User-Agent: slrn/pre1.0.4-9 (Linux) Cancel-Lock: sha1:AZ6UDuabQAurTEXyAezQsAk2b1A= Bytes: 3607 On 2024-03-21, Anton Shepelev wrote: > Kaz Kylheku to Stefan Ram: > >> > > A "famous security bug": >> > > >> > > void f( void ) >> > > { char buffer[ MAX ]; >> > > /* . . . */ >> > > memset( buffer, 0, sizeof( buffer )); } >> > > >> > > . Can you see what the bug is? >> >> I don't know about "the bug", but conditions can be >> identified under which that would have a problem >> executing, like MAX being in excess of available automatic >> storage. >> >> If the /*...*/ comment represents the elision of some >> security sensitive code, where the memset is intended to >> obliterate secret information, of course, that >> obliteration is not required to work. >> >> After the memset, the buffer has no next use, so the all >> the assignments performed by memset to the bytes of buffer >> are dead assignments that can be elided. >> >> To securely clear memory, you have to use a function for >> that purpose that is not susceptible to optimization. > > I think this behavior (of a C compiler) rather stupid. In a > low-level imperative language, the compiled program shall > do whatever the programmer commands it to do. If he > commands it to clear the buffer, it shall clear the buffer. > This optimisation is too high-level, too counter-inituitive, > even deceitful. The optimiser is free to perform the task > in the fastest manner possible, but it shall not ignore the > programmer's order to zero-fill the buffer, especially > without emitting a warning about (potentially!) redundant > code, which it is the programmer's reponsibility to confirm > and remove. If C compilers warned about every piece of dead code that is eliminated, you'd be up to your ears in diagnostics all day. Then there is the question of how to silence them on a case-by-case basis: I did want /that/ code to be eliminated, but not that one. If you do want the code deleted, that doesn't always mean you can do it yoruself. What gets eliminated can be target dependent: switch (sizeof (long)) { case 4: ... case 8: .. } Eliminating dead stores is a very basic dataflow-driven optimization. Because memset is part of the C language, the compiler knows exactly what effect it has (that it's equivalent to setting all the bytes to zero, like a sequence of assignments). If you don't want a call to be optimized away, call your own function in another translation unit. (And don't turn on nonconforming cross-translation-unit optimizations.) -- TXR Programming Language: http://nongnu.org/txr Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal Mastodon: @Kazinator@mstdn.ca