One more reason not to trust CMake

So everybody says that CMake is great because it’s faster. Of course CMake achieves speed with an approach different from the one autotools have, that is, they don’t discover features, they apply knowledge. Hey it’s a valid method as any other, if you actually know what you are doing, and if you can keep up with variants and all the rest. Another thing that it does is to avoid the re-linking during the install phase.

Let me try to explain why re-linking exists: when you build a project using libtool, there might be binaries (executables and/or libraries) that depend on shared libraries that are being built in the same source tree. When you run the executables from the source tree, you want them to be used. When you install, as you might be installing just a subtree of the original software, libtool tries to guess if you just installed the library or not (often making mistakes) and if not, it re-links the target, that is, recreates it from scratch to link to the system library. In the case of packages built by ebuild, by the use of DESTDIR, we almost always have the relinking stage in there. Given that GNU ld is slow (and IMHO should be improved, rather than replaced by gold, but that’s material for another post), it’s a very wasteful process indeed, and libtool should be fixed not to perform that stage every time.

One of the things that the relinking stage is supposed to take care is to replace the rpath entries. An rpath entry specify to the runtime linker ( where to find the dependent libraries outside of the usual library paths (that is /etc/ and LD_LIBRARY_PATH). It’s used for non-standard install directories (for instance for internal libraries that should never be linked against) or during the in-tree execution of software, so that the just-built libraries are preferred over the ones in the system already.

So to make the install phase faster in CMake, they decided, with 2.6 series, to avoid the relinking, by messing with the rpath entries directly. It would be all fine and nice if they did it correctly of course.

I reported earlier a bug about cmake creating insecure runpaths in executables starting from version 2.6. Don’t panic, if you’re using Portage, it’s all fine, because the scanelf run that reports the problem also fixes it already. In that bug you can find a link to a discussion from April . The problem was known before 2.6.0 final was released, yet it was not addressed.

So it seems like someone (Alex) used chrpath first. That’s a good choice, there’s a tool out there that does what you need, use it. At the worse you use it wrong and you fix it fine.

But no, that’s not good enough for Kitware, of course, and Brad King decided to replace that with a built-in ELF parser (and editor). Guess what? Mr. King does not know ELF that well, and expected an empty rpath to behave like no rpath at all.

Try these simple commands:

% echo "echo Mr. King does not know ELF" > test-cmake-rpath
% chmod +x test-cmake-rpath
% PATH= test-cmake-rpath

An empty PATH adds the current working directory to it. Which means that the generated ELF files from CMake 2.6 would load any library that is in the current working directory that is named after one of the names in the NEEDED lines of itself and its dependencies. There are a few attack vectors exploiting those; not all of them are exactly easy to apply, most of them don’t cause root vulnerabilities but it’s still not good.

Now of course a mistake, or missing knowledge about a particular meaning of a value in an ELF file is nothing major. Myself I didn’t know about PATH= before a few months ago, but I did know an empty rpath was not good at least.

What is the problem then? The problem is that messing with an ELF attribute like rpath, without knowing ELF files, without knowing the behaviour of and even more importantly without asking to any of the QA team of any of the distributions out there (Gentoo is certainly not the only one who dislikes insecure rpath), is just not something that earns my trust. At all.

And even worse, if the original implementation used chrpath, why not leaving it at that? Given you don’t know enough about ELF files it sounds like a very good idea. It’s not like chrpath is a tremendously exotic tool to have around for distributions.

For your information, this is how chrpath behave, and how it’s difficult to actually misuse:

flame@enterprise mytmpfs % scanelf -r hellow*
ET_EXEC /tmp hellow 
ET_EXEC   -   hellow-2 
ET_EXEC  hellow-3 
flame@enterprise mytmpfs % scan
flame@enterprise mytmpfs % gcc -Wl,-rpath,/tmp hellow.c -o hellow 
flame@enterprise mytmpfs % scanelf -r hellow 
ET_EXEC /tmp hellow 
flame@enterprise mytmpfs % cp hellow hellow-2
flame@enterprise mytmpfs % chrpath -d hellow-2   
flame@enterprise mytmpfs % scanelf -r hellow-2
ET_EXEC   -   hellow-2 
flame@enterprise mytmpfs % cp hellow hellow-3
flame@enterprise mytmpfs % chrpath -r '' hellow-3
hellow-3: RPATH=/tmp
hellow-3: new RPATH: 
flame@enterprise mytmpfs % scanelf -r hellow-3
ET_EXEC  hellow-3 

And this is the easy fix:

flame@enterprise mytmpfs % scanelf -Xr hellow-3
ET_EXEC   -   hellow-3 

Okay now at the end of the day, what can we do about this problem? Well in Gentoo we should disable this behaviour from CMake, let’s make it a bit slower, but safer; even if scanelf is covering our butts, it’s still a patching up something that someone else is continuously screwing up; and it opens the vulnerability when the users build without Portage.

And indeed, if you are building something with CMake 2.6, outside of Portage, you might also want to fix the rpaths of the installed executables and libraries, by issuing scanelf -RXr $path_to_the_installed_tree. Possibly after each time you rebuild your stuff.

To finish, a nice note that shows just how much caring people handling CMake in KDE are …. KDE trunk will require CMake 2.6 on August 4th . Nevermind there is an open security issue related to the code it builds.

Oh the irony, and they say I don’t give enough arguments why I don’t like CMake!