Search code examples
c#event-logetwetw-eventsource

Escape characters in ETW format strings?


I'm using the new EventSource class to write to the Windows Event log from my applications, and so far it's great. However, there are two things that I observe that are causing problems that are probably related: the format strings passed to the Event attribute don't appear to undergo normal string.Format processing before being written to the event log.

Consider this block:

[Event((int)LogEvent.UserCreated, Keywords=Keywords.Directory, Channel=EventChannel.Operational,
Message="Created username {0} with forum post signature {1} and homepage {2}.")]
public void UserCreated(string username, string signature, string homepageAddress)
{
    WriteEvent((int)LogEvent.UserCreated, username, signature, homepageAddress);
}

A few things occur:

  • If I try to insert a \n into the format string for the message, no newline is printed in the event log.
  • If the signature string contains a newline, the newline is printed naturally in the event log.
  • If the signature or homepageAddress strings contain ETW-like tokens (%1, %2, or %3), then ETW begins replacing those pseudo-tokens with the variables themselves, and I end up with variables nested within themselves.

I assume that if there was an escape character for ETW, it could be used to put newlines in format strings, and would also allow me to pre-process my string values to protect against these sql-injection style bugs.

Does such an escape character exist? How is this usually done?


Solution

  • The translation performed by the EventSource manifest generator is

    {0} -> %1
    ...
    {n} -> %(n+1)
    
    &   -> &
    <   -> &lt;
    >   -> &gt;
    '   -> &apos;
    "   -> &quot;
    

    For reference, the conversion happens in string EventProviderBase.TranslateToManifestConvention(string).

    Then you end up at the message compiler. Escapes are as follows:

    %n[!format_specifier!]  Describes an insert. Each insert is an entry in the 
        Arguments array in the FormatMessage function. The value of n can be a number 
        between 1 and 99. The format specifier is optional. If no value is specified, 
        the default is !s!. For information about the format specifier, see wsprintf. 
        The format specifier can use * for either the precision or the width. When 
        specified, they consume inserts numbered n+1 and n+2.
    
    %0  Terminates a message text line without a trailing newline character. This can 
        be used to build a long line or terminate a prompt message without a trailing 
        newline character.
    
    %.  Generates a single period. This can be used to display a period at the 
        beginning of a line, which would otherwise terminate the message text.
    
    %!  Generates a single exclamation point. This can be used to specify an 
        exclamation point immediately after an insert.
    
    %%  Generates a single percent sign.
    
    %n  Generates a hard line break when it occurs at the end of a line. This can be 
        used with FormatMessage to ensure that the message fits a certain width.
    
    %b  Generates a space character. This can be used to ensure an appropriate number 
        of trailing spaces on a line.
    
    %r  Generates a hard carriage return without a trailing newline character.