Share via


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

  • Anonymous
    February 10, 2006
    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?
  • Anonymous
    February 10, 2006
    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?
  • Anonymous
    February 10, 2006
    The comment has been removed
  • Anonymous
    February 12, 2006
  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 ?
  • Anonymous
    February 24, 2006
    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.

  • Anonymous
    February 24, 2006
    We have made&amp;nbsp;a number of improvements in Winsock for Windows Vista.&amp;nbsp; Recently we have detailed...

  • Anonymous
    October 05, 2006
    Several people have asked for tips on debugging LSPs, and unfortunately there’s no easy method to do

  • Anonymous
    January 02, 2008
    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

  • Anonymous
    January 10, 2008
    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)
  • Anonymous
    January 11, 2008
    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
  • Anonymous
    January 25, 2008
    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

  • Anonymous
    February 08, 2008
    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);    } }
  • Anonymous
    June 10, 2008
    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

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

  • Anonymous
    July 05, 2008
    PingBack from http://winprogger.com/?p=74

  • Anonymous
    January 21, 2009
    PingBack from http://www.keyongtech.com/2557964-catagorizing-lsps

  • Anonymous
    January 28, 2010
    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

  • Anonymous
    January 28, 2010
    The comment has been removed