23

_s functions, such as scanf_s, printf_s seems to be optional standard. MSVC has implemented these functions, but gcc hasn't.

Is there specific reason for not implementing secure functions? Is scanf of glibc secure enough?

suhdonghwi
  • 955
  • 1
  • 7
  • 20
  • 8
    This may provide some light on the Annex K situation: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1967.htm – Christian Gibbons Jun 06 '18 at 15:58
  • 10
    Their conclusion: *The design of the Bounds checking interfaces, though well-intentioned, suffers from far too many problems to correct. Using the APIs has been seen to lead to worse quality, less secure software than relying on established approaches or modern technologies. More effective and less intrusive approaches have become commonplace and are often preferred by users and security experts alike. Therefore, we propose that Annex K be either removed from the next revision of the C standard, or deprecated and then removed.* – Christian Gibbons Jun 06 '18 at 16:01
  • 1
    Weren't the Annex K functions a Microsoft initiative to begin with? Or at least one that MS was deeply involved with? – John Bollinger Jun 06 '18 at 16:03
  • What version of `gcc` are you using? I have version 4.7.2 and it knows about the safe `_s` versions. – lurker Jun 06 '18 at 16:11
  • 1
    @lurker: Where are you using GCC? The problem is actually in the C library. If you're using GCC on Windows and it is set up to know about the functions in the Microsoft C RunTime (CRT), then you'd be able to use them. If you're not on Windows, the functions are not generally available in the local C library. You can find a few add-on implementations, but they're not necessarily complete. See the N1967 paper for more details about what is (un)available. – Jonathan Leffler Jun 06 '18 at 16:15
  • @JonathanLeffler under MINGW64, which I was wondering might be providing some "extras"? So yeah, must be that Windows is providing the extra goods. – lurker Jun 06 '18 at 16:24
  • 4
    @JohnBollinger: More or less. The Annex K `*_s()` functions are closely related to, but critically different from, the `*_s()` functions that Microsoft added to MSVC. Yes, I believe Microsoft was instrumental in getting the TR 24731-1 report produced, but the result was different in key aspects from what MS had already released in the wilds, and backwards compatibility then became a problem. MS couldn't conform to the standard easily because it would break their backwards compatibility promises. – Jonathan Leffler Jun 06 '18 at 16:24
  • 1
    @lurker: That makes sense. My understanding of MinGW is that it has GCC running on Windows making maximal use of the Windows services and libraries. It therefore provides access to the MS CRT functions, including the `*_s()` functions — useful to know. However, it emphasizes the difference between 'compiler' and 'libraries', and also doesn't transfer to most other environments. The `*_s()` functions are essentially not available except on the MS platform. – Jonathan Leffler Jun 06 '18 at 16:26
  • @JonathanLeffler I understand the difference between the library and the compiler and it's worth emphasizing here. At first I assumed that along with a given version of `gcc` it came with an associated specific library set (that it was "all part of the package"), which evidently is not the case. – lurker Jun 06 '18 at 16:29
  • Also note that glibc's `scanf` implementation does include the Posix/TR-24731-2 memory allocation modifier (`m`), which is in many ways a superior interface. – rici Jun 06 '18 at 18:07

1 Answers1

24

The _s functions are optional (Annex K of the C11 standard). They're widely regarded as 'not very beneficial'.

In the answers to my question Do you use the TR-24731 "safe" functions?, you can find information about where there are problems with the standard specification — such as crucial differences between the standard and Microsoft's implementation. TR 24731-1 was a technical report from the C standard committee. The report was incorporated almost verbatim — with an extra, previously omitted, function, memset_s() — in the C11 standard as (optional but 'normative') Annex K. There's also TR 24731-2 for a different set of functions — without the _s suffix. It ran into resistance for a different set of reasons.

Also, there is a proposal before the C Standard Committee that the functions defined in Annex K should be removed from the next revision of the standard:

That paper is a straightforward and compelling read of the reasons why the TR-24731 (*_s()) functions have not been widely implemented.

Key reasons include:

  • The problem is only spotted once, then fixed, and then the *_s() function is unnecessary.
  • This makes it very hard to test the *_s() functions, or the code which uses them.
  • It isn't easy to integrate the new functions into old code (which is where there'd be most benefit).
  • The functions inherently slow down software with extensive but redundant checking.

See the paper for more details. The paper ends with the section:

Suggested Technical Corrigendum

Despite more than a decade since the original proposal and nearly ten years since the ratification of ISO/IEC TR 24731-1:2007, and almost five years since the introduction of the Bounds checking interfaces into the C standard, no viable conforming implementations has emerged. The APIs continue to be controversial and requests for implementation continue to be rejected by implementers.

The design of the Bounds checking interfaces, though well-intentioned, suffers from far too many problems to correct. Using the APIs has been seen to lead to worse quality, less secure software than relying on established approaches or modern technologies. More effective and less intrusive approaches have become commonplace and are often preferred by users and security experts alike.

Therefore, we propose that Annex K be either removed from the next revision of the C standard, or deprecated and then removed.


Annex K was not removed from C17. Two new papers from the standards committee (ISO JTC1/SC22/WG14) discuss Annex K (and are in favour of retaining the functions):


2023-03-05: It looks as though C23 will retain Annex K as an optional part of the standard. However, there is a new function, memset_explicit(), which does the job that memset_s() does — the optimizer is not allowed to skip the code, even if the variable set is not used again.

void *memset_explicit(void *s, int c, size_t n);

Description
2 The memset_explicit function copies the value of c (converted to an unsigned char into each of the first n characters of the object pointed to by s. The purpose of this function is to make sensitive information stored in the object inaccessible380).

380) The intention is that the memory store is always performed (i.e., never elided), regardless of optimizations. This is in contrast to calls to the memset function (7.26.6.1).

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 1
    Honestly the only part of Annex K that should always be implemented is `memset_s` and only to support security sensitive code. That said it would be nice to have a `strtok` replacement that's cross platform too. – Mgetz Jun 27 '18 at 16:07
  • @Mgetz: Use `strtok_r()` on Unix and `strtok_s()` on Windows; they're otherwise compatible. Or, if you prefer, always call `strtok_s()` and use `static inline char *strtok_s(char **ptr, const char *delim) { return strtok_r(ptr, delim); }` on Unix. – Jonathan Leffler Jun 27 '18 at 16:12
  • 1
    Oh I've done that, for `strtok` it would just be nice to have it be part of the standard rather than a happy happenstance. I do stand by the need for a `memset_s` that can't be optimized away though. – Mgetz Jun 27 '18 at 16:14
  • 3
    @Mgetz: I went and looked at C11 [§7.24.6.1 The `memset` function](http://port70.net/~nsz/c/c11/n1570.html#7.24.6.1) and [§K.3.7.4.1 The `memset_s` function](http://port70.net/~nsz/c/c11/n1570.html#K.3.7.4.1) and the useful difference is indeed the requirement: _Unlike `memset`, any call to the `memset_s` function shall be evaluated strictly according to the rules of the abstract machine as described in (5.1.2.3). That is, any call to the `memset_s` function shall assume that the memory indicated by `s` and `n` may be accessible in the future and thus must contain the values indicated by `c`._ – Jonathan Leffler Jun 27 '18 at 16:20
  • 3
    That requirement means that calls to `memset_s()` may not be optimized away, even if the variable being set is not referenced again. That, in turn, allows a programmer to ensure that passwords are nullified when no longer needed, and other similar operations. The extra argument isn't really necessary; the extra semantics related to (non-)optimization most certainly are helpful in a small but significant set of use cases. – Jonathan Leffler Jun 27 '18 at 16:22
  • 2
    @JonathanLeffler: More important than a particular `memset_s` function, I think, would be a general means of forcing the compiler to synchronize the states of abstract-machine objects and the state of memory seen by the CPU. Using an ordinary `memset` followed by a force synchronization would be equivalent to `memset_s`, but security-conscious code needs synchronization for other purposes as well. For example, something like `unsigned u = *p; if (u < ARRAY_SIZE) array[u]++;` could introduce a security vulnerability if `*p` gets loaded once for the compare and again for the indexing step. – supercat Jun 28 '18 at 19:29
  • 1
    regarding `memset_s()`, I was searching for it as PVS Studio mentions it. With glibc `explicit_bzero()` implements that functionality. https://man7.org/linux/man-pages/man3/explicit_bzero.3.html Note that `bzero()` is deprecated, but not `explicizt_bzero()`. – lnksz Apr 11 '22 at 14:22
  • As I understand, the `_s` functions are _not_ part of the C standard library. Is that correct? – pmor Apr 18 '22 at 16:18
  • @pmor — they are documented in "optional" [Annex K](https://port70.net/~nsz/c/c11/n1570.html#K) as stated in the first paragraph. They are a part of the standard C library, but an implementation can claim conformance to the standard without implementing the Annex K functions because they are an optional feature. (It's unlikely that anyone would implement only some of Annex K — with the possible exception of the `memset_s()` function. – Jonathan Leffler Apr 18 '22 at 16:22
  • Annex K functions are not just "optional", but "optional _extensions_" (K.2 Scope, 1). However, per "K.2 Scope": "Subclause K.3 should be read as if it were merged into the parallel structure of named subclauses of clause 7". – pmor Apr 18 '22 at 16:44