Revision History | |
---|---|
Revision 0.1 | 2003-11-28 |
Revision 0.2 | 2004-01-14 |
fixed/added some links |
Table of Contents
Abstract
This paper gives an overview about ways to implement a buildsystem for rpm-packages and about the current fedora.us buildsystem. The official source of this document is http://www.tu-chemnitz.de/~ensc/fedora.us-build where it can be found in a HTML and PDF format.
There are two critical requirements on the build-system: it must build packages in a reliable manner, and it must be resistant against attacks. Builds without much overhead and buildmaster intervention are other requirements.
There are various ways for the upstream author to attack the buildsystem. Basically, it is to differ between attacks at package-buildtime, and these at the runtime of the package:
Runtime-attacks are the creation of backdoors in the programs (trojans), or to make them doing bad things at certain times (timebombs). On first glance, the runtime case seems to be uninteresting for the buildsystem itself, but as shown below this matters also.
Buildtime-attacks are possible since arbitrary code will be executed by the make-process. So:
There are known cases where buildtime-attacks are triggered by the hostname of the build-machine, so that the build appears unsuspiciously on the machine of QA testers.
Altogether, since complex source-code will be compiled and complex code be executed by the make-system, it would require a full audit to preclude upstream attacks, so this kind can not be detected by the QA.
An attacker could create special crafted (.src).rpm files which are exploiting implementation or design flaws of the rpm-program. So, arbitrary code could be executed on the build-machine or on the machine of QA people, when the package is extracted or queried.
Doing the requested rpm-action after running such code would hide this kind attack effectively. QA will not protect against this kind of attack.
A packager could set the SUID bit of programs which were never designed to run with root privileges and untrusted input. Doing so, backdoors could be created.
Such an attack can and must be detected by QA and/or automatic QA tools like rpmlint.
There are two categories of attacks: those which are attacking the build-machine itself, and those which are modifying the content of packages. In the chapter about bad upstream sources, most of the attacks against the build-machine were mentioned already, and on a compromised build-machine it would be easy to do anything -- inclusive the modification of packages. Therefore, only the aspects of package-modifications will be discussed in this section.
To do reliable builds, certain dependencies must be fulfilled which will lead to the installation of other, untrusted packages. As mentioned in the section called “Attacks from upstream author”, limiting the requirements to packages of trusted packagers will not work since good src.rpms can create bad binary rpms.
At the installation of a package, rpm-scriptlets will be executed with root privileges, so that chroot's can be broken or files like libraries or programs be replaced. Since the replacement of files or the usage of chroot are common and valid operations for rpm, it is impossible to forbid these operations. Therefore, when the first untrusted package is installed, the build-root must be assumed as compromised.
Now, when a build happens in such an hostile environment, injected code can be executed (e.g. by calling a replaced make program or a program using a prepared /lib/libc.so.6). It will be possible, that the build-results can be modified in such a manner that the created binary package carries the same malicious code as the original code. So, entire dependency-trees can be infected. Yet worse, when using the same build-environment for every package, the entire distribution will be infected.
As an example, Figure 1, “Infection of build-tree vs. infection of build-environment” shows the build of the MagicPoint, kdebase, kdb, xine, ee and xemacs packages inclusive their dependencies (in this order). Malicious code which replaces /lib/libc.so.6 will be assumed in arts. The first image shows what happens when for each package an own build-system will be used, the second one shows the case when each build reuses the same build-system. The blue node marks the origin of the infection, the red ones the infected packages. The black arrows are symbolizing the BuildRequires:, the gray ones the build-order.
To prevent attacks and to have a reliable buildsystem, it must have the following properties: