Today we are releasing MS09-026 which fixes a vulnerability in the Microsoft Windows RPC (Remote Procedure Call) NDR20 marshalling engine. This component is responsible for preparing data to be sent over the network and then translating it back to what the server or client application uses. NDR20 is specific to 32-bit applications that use RPC to transfer data. RPC's NDR64 marshalling engine is used for 64-bit applications.

This bug in NDR20 only impacts applications which utilize a specific style of structure when defining the RPC interface they use to communicate. The specific style of structure is a non-conformant varying array. More information can be found at http://msdn.microsoft.com/en-us/library/aa373542(VS.85).aspx. Note that this style of structure is uncommon. It is not used by any RPC interface that ships with any supported version of Windows. However, we are still providing a fix as it is a supported style of structure and may be in use somewhere.

So how can a developer know if an RPC interface is affected? The bulletin's FAQ states the following.

  • What RPC applications may be affected by this vulnerability?
    To detect if an application is affected by this issue, users must have access to the IDL file used to compile the client or server application. RPC applications may be vulnerable to this issue if the resulting stub contains a FC_SMVARRAY or FC_LGVARRAY followed by FC_VARIABLE REPEAT and FC_VARIABLE_OFFSET.

These code definitions, FC_SMVARRAY, FC_LGVARRAY, FC_VARIABLE_REPEAT, and FC_VARIABLE_OFFSET, are used in the RPC client and server stubs that are generated at compile time when midl.exe compiles the RPC interface's IDL file, specifically when using the /Oicf switch (http://msdn.microsoft.com/en-us/library/aa367352(VS.85).aspx). Other switches, which are defined in the previous link, also exist. These will generate different formats for the stubs so if in doubt make sure you are using the /Oicf switch.

Using what the bulletin has stated, a developer can examine the *_c.c or *_s.c stubs generated from the IDL with the following steps:

  • Find the MIDL_TYPE_FORMAT_STRING contained in the stub file.
  • Scan down the definition looking for FC_SMVARRAY or FC_LGVARRAY in the line comment.
  • Continue scanning down looking for a FC_VARIABLE_REPEAT followed by a FC_VARIABLE_OFFSET.
  • If those two definitions were found prior to encountering a FC_END definition, the interface is affected.
  • If an FC_END definition was encountered, then that array type is safe, so continue by repeating steps 2 through 4 through the end of the MIDL_TYPE_FORMAT_STRING.

Here is an example MIDL_TYPE_FORMAT_STRING that would be affected by this issue.

static const repro_MIDL_TYPE_FORMAT_STRING repro__MIDL_TypeFormatString =
{
	0,
	{
		NdrFcShort( 0x0 ), /* 0 */
/*  2 */ 
		0x12, 0x8,	/* FC_UP [simple_pointer] */
/*  4 */ 0x8,	/* FC_LONG */
		0x5c,  /* FC_PAD */
/*  6 */ 
		0x16,  /* FC_PSTRUCT */
…
		0x1f,  /* FC_SMVARRAY */
		0x3,   /* 3 */
/* 40 */  NdrFcShort( 0x3c ), /* 60 */
/* 42 */  NdrFcShort( 0x5 ),  /* 5 */
/* 44 */  NdrFcShort( 0xc ),  /* 12 */
/* 46 */  0x28,               /* Corr desc:  parameter, FC_LONG */
		0x0,          /*  */
/* 48 */  NdrFcShort( 0x0 ),  /* x86 Stack size/offset = 0 */
/* 50 */  NdrFcShort( 0x1 ),  /* Corr flags:  early, */
/* 52 */  
		0x4b,         /* FC_PP */
		0x5c,         /* FC_PAD */
/* 54 */                
		0x48,         /* FC_VARIABLE_REPEAT */
		0x4a,         /* FC_VARIABLE_OFFSET */
/* 56 */  NdrFcShort( 0xc ),  /* 12 */
/* 58 */  NdrFcShort( 0x0 ),  /* 0 */
…
/* 74 */  0x12, 0x10,          /* FC_UP [pointer_deref] */
/* 76 */  NdrFcShort( 0xffb6 ),     /* Offset= -74 (2) */
/* 78 */                
		0x5b,          /* FC_END */

Additionally, developers can examine their IDL directly and get an idea if their interface is affected. For affected interfaces, a definition like below will exist, where an array of non-fixed sized structures, shown in blue below, is passed. Notice that the array in green is a varying array (http://msdn.microsoft.com/en-us/library/aa379375(VS.85).aspx) because of it's fixed size but varying number elements contained within.

interface foo
{
                typedef struct
                {
                                int a;
                                int **pp;
                                char *buf;
                }  test;

                void bar([in] int count,
                               [out, length_is(count)] test r[7]);
}

Developers with affected RPC interfaces should strongly encourage their customers to install this patch, especially if the RPC interface is anonymous.

- Nick Finco and Bruce Dang, MSRC Engineering