Categorizing LSPs and Applications

In Windows Vista there is a new method for categorizing both Winsock Layered Service Providers (LSP) and applications themselves such that only certain LSPs will be loaded. There are a couple reasons for adding this functionality. One of the main reasons is certain system critical processes such as WinLogon and LSASS create sockets but do not send any traffic on the network so most LSPs should not be loaded.  A large percentage of the crashes we see are due to buggy LSPs that cause LSASS.EXE to crash and if it crashes the system forces a shutdown. A side affect of these system processes loading LSPs is that these processes never exit so when an LSP is installed or removed, a reboot is required.

 

Secondly, there are some cases where applications may not want to load certain LSPs. For example, some apps may not want to load crypto LSPs so they can communicate with other machines that do not have the cypto LSP installed.

 

Finally, the LSP categories can be used by other LSPs to determine where in the Winsock protocol chain they should install themselves. For years, various LSP developers have wanted a way of knowing how an LSP will behave. For example, an LSP that inspects the data stream would want to be above an LSP that encrypts the data. Of course, this method isn’t fool proof since it relies on 3rd party LSPs to categorize themselves appropriately, but hopefully, the security enhancements in Vista will help prevent users from unintentionally installing malicious LSPs.

 

Winsock has defined nine different types of LSPs:

  1. LSP_SYSTEM – an LSP that should be loaded into system critical processes
  2. LSP_INSPECTOR – an LSP that simply monitors the inbound and outbound traffic but does not the data. An HTTP content filterer is an example of an inspector (as it will deny the request).
  3. LSP_REDIRECTOR – this type of LSP simply modifies the addresses used in Winsock calls.
  4. LSP_PROXY – this LSP redirects Winsock calls to a proxy server as well as instruct the proxy via a control channel to establish outbound connections.
  5. LSP_FIREWALL – an LSP that monitors incoming and outbound connection requests. A firewall LSP should only inspect data and deny request but not actually modify the data.
  6. LSP_INBOUND_MODIFY – filters inbound data
  7. LSP_OUTBOUT_MODIFY – filter outbound data
  8. LSP_CRYPTO_COMPRESS – a crypto or compression LSP can modify both inbound and outbound traffic but also includes and out of band signing/negotiation phase.
  9. LSP_LOCAL_CACHE – an LSP that inspects the contents of a Winsock request and satisfying the request by generating the expected response without the request actually hitting the intended destination.

 

Note that it is possible to categorize an LSP as more than one type. In fact an LSP categorized as LSP_SYSTEM should also be categorized with the type(s) that best describe how it inspects or modifies the Winsock calls.

 

On Vista , the majority of the system critical processes and system services are already registered with the appropriate categories depending on their functionality.

 

Categorizing LSPs

 

There are two new APIs for categorizing an LSP which are defined in ws2spi.h:

 

int

WSPAPI

WSCSetProviderInfo(

    LPGUID lpProviderId,

    WSC_PROVIDER_INFO_TYPE InfoType,

    PBYTE Info,

    size_t InfoSize,

    DWORD Flags,

    LPINT lpErrno

    );

int

WSPAPI

WSCGetProviderInfo(

    LPGUID lpProviderId,

    WSC_PROVIDER_INFO_TYPE InfoType,

    PBYTE Info,

    size_t *InfoSize,

    DWORD Flags,

    LPINT lpErrno

    );

 

In order to categorize an LSP, WSCSetProviderInfo is called that specifies the GUID of the hidden LSP entry (i.e. the LSP entry installed whose ProtocolChain.ChainLen is zero). The WSC_PROVIDER_INFO_TYPE is an enumeration and ProviderInfoLspCategories should be passed. Then a simple DWORD with the appropriate LSP_* flags above is passed as the Info parameter. For example:

 

     DWORD lspCategory = LSP_INBOUND_MODIFY | LSP_OUTBOUND_MODIFY;

     GUID lspGuid = &YOUR_LSP_GUID;

int rc, err;

     rc = WSCSetProviderInfo( &lspGuid, ProviderInfoLspCategories,

(PBYTE) &lspCategory, sizeof(lspCategory), 0, &err);

 

Retrieving the LSP category is similar to setting it but using the WSCGetProviderInfo call.

 

Categorizing Applications

 

The other part of the equation is categorizing applications themselves to specify those LSPs that should be loaded in its process. This is done via the following two functions also defined in ws2spi.h:

 

int

WSPAPI

WSCSetApplicationCategory(

    LPCWSTR Path,

    DWORD PathLength,

    LPCWSTR Extra,

    DWORD ExtraLength,

    DWORD PermittedLspCategories,

    DWORD * pPrevPermLspCat,

    LPINT lpErrno

    );

int

WSPAPI

WSCGetApplicationCategory(

    LPCWSTR Path,

    DWORD PathLength,

    LPCWSTR Extra,

    DWORD ExtraLength,

    DWORD * pPermittedLspCategories,

    LPINT lpErrno

    );

 

In the functions above Path is the full path and executable name while Extra is the arguments passed to that application. The Path argument can contain environment variables as the function calls will expand them as necessary. Note that an application is defined as the full path and executable name as well as any arguments. Thus if the application “c:\foo.exe” is categorized as LSP_PROXY, the application “c:\foo.exe –x 12” is different and would not be considered as allowing LSP_PROXY LSPs.

 

The following code categorizes “foo.exe –x 12”:

 

     rc = WSCSetApplicationCategory(

L”%windir%\\foo.exe”,

lstrlenW(L”%windir%\\foo.exe”),

L”-x 12”,

lstrlenW(L”-x 12”),

LSP_SYSTEM | LSP_FIREWALL | LSP_CRYPTO_COMPRESS,

NULL,

&err

);

 

The pPrevPermLspCat parameter is optional and simply returns the previous categories set for this application if it existed.

 

Determining Which LSPs Get Loaded

 

The final part of LSP categorization is determining which LSPs will be loaded into which processes. When a process loads Winsock, both the application category and the LSP categories for all installed LSPs and the following comparisons made:

  1. If the application is not categorized, allow all LSPs
  2. If both the application and the LSP have assigned categories, all of the following must be true:
    1. At least one of the LSP categories is present in the application’s specified categories
    2. ONLY categories specified in the application’s specified categories are specified in the LSPs categories (i.e. if the app specifies a category is must be in the LSP’s category, but if the app specifies a category that is not present in the LSPs category then that is OK)
    3. If LSP_SYSTEM is present in the application’s category, it MUST be present in the LSP’s categories

 

NOTE: If an LSP is not categorized its category is effectively 0. Basically, for a match to occur all the LSP’s specified categories must be present in the application’s categories (i.e. the app must be a superset of the LSP) – with the caveat that if LSP_SYSTEM is present in the app’s category is must also be present in the LSP’s category.

 

Consider the following example:

            Foo.exe is categorized as LSP_SYSTEM + LSP_FIREWALL + LSP_CRYPTO_COMPRESS

            Bar.exe is categorized as LSP_FIREWALL + LSP_CRYPTO_COMPRESS

 

There are four LSPs installed on the system:

            LSP1: LSP_SYSTEM

            LSP2: 0 (no category set)

            LSP3: LSP_FIREWALL

            LSP4: LSP_SYSTEM + LSP_FIREWALL + LSP_CRYPTO_COMPRESS + LSP_INSPECTOR

 

In this example, Foo.exe would only load LSP1 while Bar.exe would load LSP3.

 

--Anthony Jones (AJones)