Appendix H: SDL SAL Recommendations for Native Win32 Code

The Standard Source Code Annotation Language (SAL), a technology from Microsoft Research that is actively embraced by Windows and Office, is a powerful addition to C/C++ source code to help find bugs, especially security vulnerabilities. SAL can help find more vulnerabilities than the present set of static analysis tools can find. A major benefit of SAL is that developers need only annotate their headers to provide benefit for others. For example, most C runtime and Windows headers that ship with Visual Studio 2005 and later are annotated. Windows Development Kit headers are also annotated.

All products developed using SDL should use a subset of SAL to help find deeper issues such as buffer overrun issues. Microsoft teams such as Office and Windows are using SAL beyond the requirements of SDL.

On This Page

SAL Details
SDL Recommendations
SAL in Practice
Tools Usage
Top Severity Warnings to Triage for Fixing
Benefits of SAL
Resources
Summary

SAL Details

SAL is primarily used as a method to help tools, such as the Visual C++ /analyze compiler option to find bugs by knowing more about a function interface. For the purposes of this appendix, SAL can document three properties of a function:

  • Whether a pointer can be NULL

  • How much space can be written to a buffer

  • How much can be read from a buffer (potentially including NULL termination)

At a high level, things become more complicated because there are two implementations of SAL:

  • __declspec syntax (VS2005 and VS2008)

  • Attribute syntax (VS2008)

Each of these implementations maps onto lower-level primitives that are too verbose for typical use. Therefore, developers should use macros that define commonly used combinations in a more concise form. C or C++ should add the following to their precompiled headers:

  • 
    #include “sal.h”
    

SDL Recommendations

  • Start with new code only. Microsoft strongly recommends that you also plan to annotate old code.

  • All function prototypes that accept buffers in internal header files you create should be SAL annotated.

  • If you create public headers, you should annotate all function prototypes that read or write to buffers.

SAL in Practice

All examples uses the __declspec form.

A classic example is that of a function that takes a buffer and a buffer size as arguments. You know that the two arguments are closely connected, but the compiler and the source code analysis tools do not know that. SAL helps bridge that gap.

A list of common SAL annotations, with examples can be found at on Michael Howard’s blog.

The following code demonstrates this benefit by annotating a writeable buffer named buf:


void FillString(
  TCHAR* buf,
  int cchBuf,
  TCHAR ch) {
  for (int i = 0; i < cchBuf; i++)
    buf[i] = ch;
}

cchBuf is the character count of buf. Adding SAL helps link the two arguments together:


void FillString(
  __out_ecount(cchBuf) TCHAR* buf,
  int cchBuf,
  TCHAR ch) {
  for (int i = 0; i < cchBuf; i++)
    buf[i] = ch;
}

If you compile this code for Unicode, a potential buffer overrun exists when you call this code:


TCHAR buf[MAX_PATH];
FillString(buf, sizeof(buf), '\0');

sizeof is a byte count, not a character count. The programmer should have used countof.

In the __out_ecount macro, __out means the buffer is an “out” buffer and is written to by the functions. The buffer size, in elements, is _ecount(cchBuf). Note that this function cannot handle a NULL buf, if it could, then the following macro could be used: __out_ecount_opt(cchBuf), where _opt means optional.

The following example shows a function that reads to a buffer and writes to another.


void CopyRange(__in_ecount(cchFrom) const char *from, 
size_t cchFrom, 
__out_ecount(cchTo) char *to, 
size_t cchTo);

Tools Usage

To take advantage of SAL, make sure you compile your code with version of VC++ 2005 or VC++ 2008 that support the /analyze compile-time flag.

Top Severity Warnings to Triage for Fixing

6029     Possible buffer overrun in call to <function>: use of unchecked value

6053     Call to <function>: may not zero-terminate string <variable>

6057     Buffer overrun due to number of characters/number of bytes mismatch in call to

<function>

6059     Incorrect length parameter in call to <function>: pass the number of remaining

characters, not the buffer size of <variable>

6200     Index <name> is out of valid index range <min> to <max> for non-stack buffer

<variable>

6201     Buffer overrun for <variable>, which is possibly stack allocated: index <name> is out of

valid index range <min> to <max>

6202     Buffer overrun for <variable>, which is possibly stack allocated, in call to <function>:

length <size> exceeds buffer size <max>

6203     Buffer overrun for buffer <variable> in call to <function>: length <size> exceeds buffer

size

6204     Possible buffer overrun in call to <function>: use of unchecked parameter <variable>

6209     Using “sizeof<variable1>” as parameter <number> in call to <function> where

<variable2> may be an array of wide characters; did you intend to use character count

rather than byte count?

6248     Setting a SECURITY_DESCRIPTOR’s DACL to NULL will result in an unprotected object

6383     buffer overrun due to conversion of an element count into a byte count

Benefits of SAL

Because SAL provides more function interface information to the compiler toolset, SAL will find more bugs earlier and with less noise.

Resources

More detailed SAL information can be found in chapter 1 of Writing Secure Code for Windows Vista from Howard and LeBlanc and at Howard’s blog.

Summary

  • Microsoft recommends that you start by annotating new code only. As time permits, existing code should be annotated also.

  • You should use SAL for all functions that write to buffers.

  • You should consider using SAL for all functions that read from buffers.

  • The SDL requirement does not mandate either SAL macro syntax. Use attribute or __declspec as you see fit.

  • Annotate the function prototypes in headers that you create.

  • If you consume public headers, you must use only annotated headers.

Content Disclaimer

This documentation is not an exhaustive reference on the SDL process as practiced at Microsoft. Additional assurance work may be performed by product teams (but not necessarily documented) at their discretion. As a result, this example should not be considered as the exact process that Microsoft follows to secure all products.

This documentation is provided “as-is.” Information and views expressed in this document, including URL and other Internet website references, may change without notice. You bear the risk of using it.

This documentation does not provide you with any legal rights to any intellectual property in any Microsoft product. You may copy and use this document for your internal, reference purposes.

© 2012 Microsoft Corporation. All rights reserved.

Licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported