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)

Comments (17)

  1. Steve Biggs says:

    This seems a little over-zealous!  Are you really saying that, for instance iexplore.exe could be categorized differently to iexplore <URL> (i.e. parameterized) and wouldn’t inherit the base flags?

    So, if we, as an LSP company, specified that you had to run a particular app a certain way to get the benefit of the LSP, then ANY difference to the parameters of that app would cause the LSP to be ignored?  Even adding parameters that the LSP provider may not be aware of (such as a -debug option or just a variable parameter such as a URL)?

    Doesn’t this defeat the whole idea of LSPs?

  2. Laurent Michat says:

    What is planned for the compatibility with Windows XP?

    Is it recommended to make 2 builds (one for each platform), or to check the Windows version inside the LSP code?

  3. wndpteam says:

    The main reason for including the arguments in the app category hash is for services. In this case, there are multiple instances of the same EXE name (svchost.exe) where each instance hosts different types of services — some of which require different categorization.

    IE will not be categorized and if you wanted to categorize it you would still require Administrator priviledges. Again, the main reason for categorization is to exclude critical services from loading LSPs (which could result in slower performance or system instability). By including the parameters in the LSP selection process it makes it more difficult for someone to bypass LSPs so I’m not sure I see how that is defeating the idea of LSPs.

    As for compatibility with XP, the LSP binary itself requires no change and will run on both XP and Vista. The only required change is in the LSP installer. You could either check for OS version or simply load ws2_32.dll and try to do a GetProcAddress on the categorization functions.

  4. Laurent Michat says:

    1. Our LSP, like many others, is only used by user applications. Currently we must check the owner of the process, and if it’s ‘SYSTEM’, ‘LOCAL SERVICE’ or ‘NETWORK SERVICE’ and if it is the case to put the LSP in bypass for this process. A flag ‘LSP_APPLICATION’ would be very useful to avoid needless loading, and needless conflicts.

    2. When the sample LSP will be updated ?

  5. wndpteam says:

    Laurent,

    Thanks for your comments.

    To answer number 2: Go to http://connect.microsoft.com and join the Windows Network Developer Platform group.  The updated sample is available from the downloads section once you have joined.

  6. We have made&amp;nbsp;a number of improvements in Winsock for Windows Vista.&amp;nbsp; Recently we have detailed…

  7. Several people have asked for tips on debugging LSPs, and unfortunately there’s no easy method to do

  8. Vishal says:

    The updated sample @ https://connect.microsoft.com/WNDP/Downloads/DownloadDetails.aspx?DownloadID=941&wa=wsignin1.0 on date 02/2006 doesnt has sample code to categorize LSP on Vista.

    WNDPTeam,

    May I request you to update it ?

    Thanks.

    The WinSock team is taking a look at it and will probably add the extra calls to the installer in the sample. — Ari
  9. Viv says:

    I created a tool that can set/get the LSP flags of an application. Some issues:

    1) The categorization functions for applications and LSPs are not declared in the latest Platform SDK. You need to install the Windows SDK for Vista from http://www.microsoft.com/downloads/details.aspx?familyid=C2B1E300-F358-4523-B479-F53D234CDCCF&displaylang=en

    There is stated: “This SDK is designed for use with Windows Vista (which includes Framework 3.0). The Windows SDK for Vista also supports creating applications for Windows XP, Windows Server® 2003 SP1, and Windows Server 2003 R2.”

    which means that windows 2000 is not supported anymore.

    This is unfortunate b/c that means that for your product you either support Windows 2000 and then you can’t categorize your LSP or you categorize the LSP and take your chances with Windows 2000. Is my assumption correct?

    2) If the app was not categorized yet the WSCGetApplicationCategory returns WSASERVICE_NOT_FOUND. I think the documentation is pretty misleading as the WSASERVICE_NOT_FOUND means “The service could not be found based on the Path and Extra parameters.” which makes you think that you misspelled the path or extra.

    Either it returns 0 which is correct (no flag set) or the docu should state that WSASERVICE_NOT_FOUND means that the app was not flagged.

    3) My tests show that the WSCSetApplicationCategory actually _concatenates_ to the already existing flags the new flags. So, if an app was flagged let’s say with LSP_SYSTEM and then a new call of WSCSetApplicationCategory is done with LSP_REDIRECTOR, the app ends up having both flags, not only the one used in the last call of WSCSetApplicationCategory. I think this should also be mentioned in the docu if this is the desired behavior.

    Thanks,

    Viv

    Hi Viv,

    Winsock LSPs still work on Windows 2000. If your application is using the new LSP categorization functions then you’ll have to dynamically load these for the binary to run on versions of Windows prior to Vista.

    Thanks for pointing out the documentation problems. I will work with our doc team to clarify them. As for WSCSetApplicationCategory, yes, the values are concatenated if that application is already categorized. This is to support processes that host multiple “applications” such as Windows services (svchost.exe) in which case each application will call the categorization API for itself.

    Thanks,

    Anthony Jones (MSFT)

  10. Viv says:

    Hi Anthony,

    > Winsock LSPs still work on Windows 2000. If your application is using the new LSP categorization functions then you’ll have to dynamically load these for the binary to run on versions of Windows prior to Vista.

    I agree, but besides that you also need to copy from the new Windows SDK ws2spi.h into your own files the needed (new) stuff:

    1) Definitions for:  WSCGetProviderInfo, WSCGetProviderInfo32, WSCSetProviderInfo, WSCSetProviderInfo32

    2) The declaration for WSC_PROVIDER_INFO_TYPE

    I’m not sure if this is a good idea, as if they get changed one can get into troubles. Or is this the recommended way?

    Thanks,

    Viv

    This is a generic problem for whenever a developer wishes to write code that works for older versions of windows but wants to use new OS APIs. The primary solution I’ve seen is to target the lowest level version of the OS you intend on supporting and then copy relevant parts of the header to a private header for your project and dynamically load the approriate functions. If the functions do not exist in the executing OS (as discovered by the GetProcAddress returning NULL) then you set the function pointer to a dummy function that doesn’t do anything.

    In some cases you can get away with targetting the latest OS version (avoiding the need for that private header) so long as you don’t statically use any functions not available in the targetted previous OS versions. Also, I wouldn’t worry too much about breaking changes to public functions once the first OS with the API ships, since that would break appcompat (private APIs are fair game 🙂 ).

    — Ari

  11. Vishal says:

    See above comment by Ari

    "The WinSock team is taking a look at it and will probably add the extra calls to the installer in the sample. — Ari"

    Hi Ari,

    Can you update this thread once they complete it? It will be a great help if I could get it asap.

    Thanks

  12. Viv says:

    Hi Vishal,

    I don’t use the latest Microsoft sample of the LSP, but the one provided on the Platform SDK 2003, this is why I can’t really put here the exact calls that would match that latest code, but I will write down the guidelines you need to add the code yourself:

    1) If you don’t want to install Windows SDK and build the product using Windows SDK (for instance b/c you still want to fully support Win2k), you should create a private header file with all the needed data copied from windows SDK, like: LSP flag defines, WSC_PROVIDER_INFO_TYPE, WSCSetProviderInfo, WSCGetProviderInfo, WSCSetProviderInfo32, WSCGetProviderInfo32, WSCSetApplicationCategory (optional), WSCGetApplicationCategory (optional). Then, in the same header file you can declare pointer to these functions, eg: typedef __control_entrypoint(DllExport) int (WSPAPI * LPWSCSETPROVIDERINFO)(..)

    2) in the instlsp.cpp, right after the LSP was installed (you have to follow the path to find out in what case the LSP gets installed, in my sample is "else if (bInstall)"), you need to do smth like:

    hModule_ws2 = LoadLibraryA("ws2_32.dll");

    if (hModule_ws2 == NULL)

    {

       printf("nws2_32.dll was not loaded: %dn", GetLastError());

       goto cleanup;

    }

    else // the ws2_32.dll was load succesfully, so get the function’s pointer

       fnWSCSetProviderInfo = (LPWSCSETPROVIDERINFO)GetProcAddress(hModule_ws2, "WSCSetProviderInfo");

    if (fnWSCSetProviderInfo)// if fnWSCSetProviderInfo we are on Vista+, otherwise we are on XP or lower

    {

       int err;

       DWORD lspCategory = LSP_XXXXXX;

       if(SOCKET_ERROR == fnWSCSetProviderInfo(&ProviderGuid, ProviderInfoLspCategories, (PBYTE) &lspCategory, sizeof(lspCategory), 0, &err))

           printf("Categorize the LSP: WSCSetProviderInfo failed: %dn", err);

    }

    This is everything you need to categorize your LSP.

    3) If you also want to print the LSP category when using for instance: instlsp.exe -p -v, you need to do in prnpinfo.cpp in PrintProtocolInfo() smth like:

    if(wsapi->ProtocolChain.ChainLen == 0) // 0 means dummy LSP entry (the category is set only for the dummy entries)

    {

       if (fnWSCGetProviderInfo) // if we are on Vista (if we have a valid pointer to the WSCGetProviderInfo() function, you have to previously obtain this)

       {

           DWORD lspCategory;

           size_t lspCategorySize = sizeof(lspCategory);

           int err;

           if(SOCKET_ERROR == fnWSCGetProviderInfo(&wsapi->ProviderId, ProviderInfoLspCategories, (PBYTE) &lspCategory, &lspCategorySize, 0, &err))

               printf("Get the LSP category: WSCGetProviderInfo failed: %dn", err);

           else

               printf("n    LSP Category: 0x%08xn", lspCategory);

       }

    }

  13. Saurabh says:

    Hi All,

    I have 2 doubts:

    1) When I use the WSCSetProviderInfo function I get a success however I find that my LSP is always loaded.

    I use the following code.

    ============================

           HMODULE hModule_ws2 = LoadLibraryW(L"ws2_32.dll");

           LPWSCSETPROVIDERINFO fnWSCSetProviderInfo;

           LPWSCGETAPPLICATIONGATEGORY fnWSCGetApplicationCategory;

           if (hModule_ws2 == NULL)

           {

               printf("nws2_32.dll was not loaded: %dn", GetLastError());

               goto cleanup;

           }

           else // the ws2_32.dll was load succesfully, so get the function’s pointer

           {

               fnWSCSetProviderInfo = (LPWSCSETPROVIDERINFO)GetProcAddress(hModule_ws2, "WSCSetProviderInfo");

           }

           fnWSCGetApplicationCategory = (LPWSCGETAPPLICATIONGATEGORY)GetProcAddress(hModule_ws2, "WSCGetApplicationCategory");

           if (fnWSCSetProviderInfo && fnWSCGetApplicationCategory)// if fnWSCSetProviderInfo we are on Vista+, otherwise we are on XP or lower

           {

               int err = 0;

               DWORD lspCategory = LSP_INSPECTOR, OutLspCategory;

               if(SOCKET_ERROR == fnWSCSetProviderInfo(&ProviderGuid, ProviderInfoLspCategories, (PBYTE) &lspCategory, sizeof(lspCategory), 0, &err))

                   printf("Categorize the LSP: WSCSetProviderInfo failed: %dn", err);

               printf("Done OK");

    ===============

    I am using Vista…

    I use windbg to get the err etc.. I find that the error is always 0 and return type is 0 as well, however the LSP still keeps loading svchost servcies.exe etc when i try to verify it using tasklist after a restart.

    Please help

    2)

    Also I tried to verify if the svchost etc are classified as LSP_SYSTEM category, however I always get the err as 10108, I think I am messing up the parameters, i am not sure as to what parameter should be passed to svchost.exe. I pass it the following parameters:

    if(SOCKET_ERROR == fnWSCGetApplicationCategory(AppName, wcslen(AppName) , AppParam,wcslen(AppParam) , &OutLspCategory ,&err))

    AppName = "c:windowssystem32svchost.exe"

    AppParam = "-k 784"

    here 784 is my instance id for svchost.exe.

    I think the instance id is incorrect, where do i get the instance id from..?

    I am running

    Vista32 Enterprise 6001 SP1

    Please help

    Sau

  14. Ray says:

    Does anyone know what category is needed to to have Windows Update load your LSP?  I have tried LSP_SYSTEM, but to no avail.  The odd thing is the process name for windows update is wuauclt.exe but it is hosted by svchost.exe.  How do I get this process to load my LSP?  

    Thanks,

    Ray

  15. Ray says:

    Also, are categories known to work on Win 7?  I just cant seem to get my LSP loaded for any system processes.  Even with all of these:

    rCategory=LSP_SYSTEM | LSP_FIREWALL | LSP_REDIRECTOR | LSP_INSPECTOR;

    Thanks for you assistance

    Ray