8

Our product includes several DLLs built from open source into files with default names as delivered by the open source developers. We're careful to install the files in our own directories and we carefully manage the search path (only for our processes) to keep the loader happy.

Another developer -- a towering intellect -- decided it would be easier to install their own build of some of the same open source into C:\WINDOWS under the same default DLL filenames. Consequently, when we launch a process which depends on these open source DLLs, the system searches C:\WINDOWS before our directories and finds the DLLs installed by the other developer. And they are, of course, incompatible.

Ideas which have occurred to me so far:

  • rename all our DLLs to avoid the default names, which would only make it less likely we would encounter collisions
  • load all our DLLs by full path so the loader captures their names into RAM and doesn't search anywhere else the next time they are requested

For various reasons, neither of these options is palatable at the moment.

What else can we do to defend ourselves against the towering intellects of the world?

Integer Poet
  • 747
  • 5
  • 19
  • 1
    If you use recent versions of MSVC, doesn't the manifest/assembly information guarantee that it won't attempt to load the incorrect DLLs? – Kaleb Pederson Mar 11 '10 at 21:55
  • 1
    Are you loading your DLLs implicitly (via linking with an import LIB) or explicitly (via LoadLibrary)? If the latter, can you provide a full path to your DLLs? – Scott Smith Mar 11 '10 at 21:56
  • Kaleb, we're using VS2005, and it does generate manifests, but it seems to do so only for DLLs which it knows are delivered into SxS. Ours aren't. It may be that we can do something with manifests anyway; I'll look into that. – Integer Poet Mar 11 '10 at 21:58
  • Scott, we're loading them implicitly. – Integer Poet Mar 11 '10 at 21:59
  • Interface-incompatible versions of the same dll deployed directly into C:\Windows? Feels like the bad ol' days. – Greg D Mar 11 '10 at 22:00
  • Yeah -- hence the mention of towering intellect. I'm actually grateful the interfaces are incompatible, because if it had only been the implementation, it might have taken us forever to figure out. – Integer Poet Mar 11 '10 at 22:13

4 Answers4

5

You've got only two options: deploy the DLL in the same directory as the EXE (that's where Windows looks first) or using manifests and deploy the DLL to the Windows side-by-side cache. I don't think the latter option is common in the Open Source world but it is the only real fix if you want to share DLLs between different apps.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Yeah, the latest documentation (which by the way seems to be at http://msdn2.microsoft.com/en-us/library/ms972822.aspx) doesn't mention the EXE's directory, but I just did an experiment which I think establishes that. – Integer Poet Mar 11 '10 at 22:17
  • Better documentation here: http://msdn.microsoft.com/en-us/library/ms682586(VS.85).aspx – Integer Poet Mar 11 '10 at 22:40
3

To add to the already excellent answers, you have a couple more choices:

The preferred solution(s) to this problem, supported since Windows XP, is to turn your dll's into a win32 assembly (They don't have to be .NET but the documentation on creating win32 assemblies with strong names is appallingly light so its easy to get confused and think this is a .NET only technology).

An assembly is noting more complicated than a folder (With the name of the assembly) containing the dlls and a .manifest (With the name of the assembly) that contains an assemblyIdentiy element, and a number of file nodes for each dll in the assembly.

Assembly based searching works even when dlls are statically linked!

  • The easiest option is to create unversioned assemblies and store them in the same folder as your .exe files (Assuming all your exe's are in a single folder).

If the exe's are in different folders, then there are two ways to access shared assemblies:

  • You can store your assemblies in a private alternate location if you expect your application to be used on Windows 7 and higher. Create a app.exe.config file for each of your exe's, and point a probing privatePath element to a common folder where you are storing the assemblies.

  • If you are ok with requiring administrative access to perform installs, (via MSI's) then you can deal with the appallingly bad documentation (well, absent documentation) that deals with giving your assemblies a strong name, and then store the assembly in WinSxS.

If you can't, or do not want to bundle your dlls as assemblies then this page covers dll search order

Using functions like SetDllDirectory are only going to help for dlls loaded dynamically at runtime (via LoadLibrary).

Dll search order used to be:

  1. Directory containing the process exe
  2. Current directory
  3. various windows folders
  4. PATH

Which you could have used to your advantage - launch each exe, setting the "current" directory to the folder containing the OSS dlls.

With the advent of SafeDllSearchMode the search order now is:

  1. Directory containing the process exe
  2. various windows folders
  3. Current directory
  4. PATH

Meaning theres now less control than ever :( - It goes even faster to the "untrusted" c:\windows & System32 folders.

Again, if the initial dll is being loaded via LoadLibrary, and its the dependent dll's that are the problem, LoadLibraryEx with the LOAD_WITH_ALTERED_SEARCH_PATH flag will cause the following search order (Assuming you pass a full path to LoadLibraryEx) :-

  1. Directory part of the Dll path passed to LoadLibraryEx
  2. various windows folders
  3. Current directory
  4. PATH
Community
  • 1
  • 1
Chris Becke
  • 34,244
  • 12
  • 79
  • 148
1

The directory from which the application loaded is normally the first directory searched when you load a DLL. You can, however, use SetDllDirectory to get the "alternate search order". In this case, the directory you specify to SetDllDirectory gets searched first.

There is also a SafeDllSearchMode that affects this to a degree. Turning it on excludes the current directory from the search.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • The trouble with SetDllDirectory is that the value isn't inherited by child processes. We have many child and grandchild (and probably deeper) processes. SafeDllSearchMode does sound intriguing and I'm looking into it. – Integer Poet Mar 11 '10 at 23:04
  • `SafeDllSearchMode` does not remove the current directory from the search path. Rather, it moves the current directory toward the end of the places to look. That can help. If you're trying to load a system library or one installed with your executable, you're all set. But if you're doing a `LoadLibrary` to determine whether a DLL exists, then that still leaves you open to a preload attack. – Adrian McCarthy May 04 '10 at 22:18
0

Maybe just compile them to a static library?

Why not?

Also, the current directory, where the exe is activated from is searched before c:\windows.

shoosh
  • 76,898
  • 55
  • 205
  • 325
  • We have many, many EXEs. Compiling the DLLs statically into all of them would make them prohibitively large. As well, there are multiple teams involved which operate on cooperative schedules and the DLLs provide a way to manage deliverables. – Integer Poet Mar 11 '10 at 23:05
  • And, by the way, the current directory is NOT searched before system directories as of XP SP1 and Server 2003 UNLESS you do something with SetDllDirectory which is unclear from the available documentation. (If I were to take this approach, I would just pass the current directory to eliminate all doubt.) However, I think what you really meant is that the EXE's parent directory is searched first, and that is indeed true. – Integer Poet Mar 12 '10 at 01:30
  • Yes, that's what I was saying. why doesn't that solve your problem? – shoosh Mar 12 '10 at 23:25
  • The DLLs aren't located in the same directory as the EXEs. – Integer Poet Mar 13 '10 at 03:13