Improve FAQ entry: VMware violation tech example

Add additional information and details about the technical details of
the VMware violation.  This extends the existing example with more
detail and improves various other parts related in the FAQ.
This commit is contained in:
Bradley M. Kuhn 2015-03-21 10:31:07 -04:00
parent 83c97a0029
commit ea9a59c551

View file

@ -180,7 +180,6 @@ Code, and for which (at least some) source code is provided.
whole was developed by modifying Linux code in tandem with
modifications to &ldquo;vmkernel&rdquo; in a tightly coupled manner.</p>
</dd>
<dt id="shim-meaningless">Is Conservancy proposing a &ldquo;shim
layer&rdquo; as a viable solution for GPL compliance?</dt>
@ -190,7 +189,7 @@ Code, and for which (at least some) source code is provided.
technological manipulation that changes the outcome of a
combined/derivative work analysis.</dd>
<dt>Can you give a <em>specific</em> example, with code, showing how
<dt id="example">Can you give a <em>specific</em> example, with code, showing how
VMware combined Linux source code with their binary-only components?</dt>
<dd><p>There are numerous examples available that show this. The
@ -213,27 +212,39 @@ Code, and for which (at least some) source code is provided.
Hellwig's copyrights; VMware incorporated Linux code copyrighted by
many others as well into their kernel.</p>
<h4>Example of &ldquo;vmkernel&rdquo;'s combination with Linux code</h4>
<p>As one example, examine the file
<h3>Example of &ldquo;vmkernel&rdquo;'s combination with Linux code</h3>
<p>Our example begins with examination of the file
called <code>vmkdrivers/src_92/vmklinux_92/vmware/linux_pci.c</code>,
which can be found in the &ldquo;Open Source&rdquo; release for
ESXi 5.5.0 Update 2 (5.5U2). A small excerpt from that file, found in the
function <code>LinuxPCIDeviceRemoved()</code>, reads as follows:</p>
<pre>
if (unlikely(
/* NOTE: vmk_PCIGetDeviceName is defined in vmvisor64-vmkernel */
vmk_PCIGetDeviceName(vmkDev, vmkDevName, sizeof(vmkDevName)-1) != VMK_OK))
{
vmkDevName[0] = 0;
}
#include <linux/pci.h>
[...]
/*
* This function [...] is modelled after pci_remove_device, the function which would
* be called in a linux system.
*/
static void
LinuxPCIDeviceRemoved(vmk_PCIDevice vmkDev)
{
LinuxPCIDevExt *pciDevExt;
struct pci_dev *linuxDev;
[...]
if (unlikely(
vmk_PCIGetDeviceName(vmkDev, vmkDevName, sizeof(vmkDevName)-1) != VMK_OK))
{
vmkDevName[0] = 0;
}
[...]
/* VMKAPI_MODULE_CALL_VOID is a macro calling driver's remove() here */
VMKAPI_MODULE_CALL_VOID(pciDevExt->moduleID,
linuxDev->driver->remove,
linuxDev);
</pre>
<h4>Combination of &ldquo;vmkernel&rdquo; code with &ldquo;vmkdrivers&rdquo;</h4>
<p>The function, <code>vmk_PCIGetDeviceName()</code> must be defined, with an
implementation, for this code above to work, or even compile.
Inside <code>BLD/build/HEADERS/vmkapi-current-all-public/vmkernel64/release/device/vmkapi_pci_incompat.h</code>,
@ -286,28 +297,131 @@ VMKAPI_MODULE_CALL_VOID(pciDevExt->moduleID,
<p>&hellip; which indicated these binary file contains the function body
for <code>vmk_PCIGetDeviceName</code>.</p>
<p>Finally, after detailed searching, Conservancy found no evidence that any
<p>Furthermore, after detailed searching, Conservancy found no evidence that any
other code (other than modified Linux code) makes calls
to <code>vmk_PCIGetDeviceName</code>. This provides a strong indication
that this function's primary purpose is to combine Linux code with
&ldquo;vmkernel&rdquo;. Conservancy also found other functions where similar analysis
yields similar results as above.</p>
<h4>Linux's <code>struct pci</code> combined with <code>LinuxPCIDeviceRemoved()</code></h4>
<p>Having established the direct and close combination
of <code>vmk_PCIGetDeviceName</code>
and <code>LinuxPCIDeviceRemoved()</code>, focus now on the
quoted code from <code>LinuxPCIDeviceRemoved()</code>. That code, note
that one of the local variables is <code>struct pci_dev *linuxDev;</code>.
A definition of <code>pci_dev</code> is found in
<code>vmkdrivers/src_92/include/linux/pci.h</code> (which
is <code>#include</code>'d above) reads:
<pre>
struct pci_dev {
[...]
struct pci_driver *driver; /* which driver has allocated this device */
[...]
truct pci_driver {
char *name;
[...]
void (*remove) (struct pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */
[...]
#if defined(__VMKLNX__)
/* 2008: Update from Linux source */
u8 revision; /* PCI revision, low byte of class word */
#endif /* defined(__VMKLNX__) */
};
</pre></p>
<p>These structures, and based on those from Linux itself
(<a href="http://lxr.free-electrons.com/source/include/linux/pci.h?v=2.6.24">a
similar version of this file can be seen in Linux 2.6.24</a>), and as can
be seen above, have been modified to work with &ldquo;vmkernel&rdquo;</p>
<p>In <code>LinuxPCIDeviceRemoved()</code>, we saw a macro called with a
variable, <code>linuxDev</code> which was of type <code>struct pci</code>.
Thus, the combination of code from Linux's <code>pci.h</code>
and VMware's <code>vmware/linux_pci.c</code> is very tightly coupled and
interdependent.</p>
<h4><code>VMKAPI_MODULE_CALL_VOID</code> macro calls driver's code</code></h4>
<p>The
file <code>BLD/build/HEADERS/vmkapi-current-all-public/vmkernel64/release/base/vmkapi_module.h</code>
contains the macro definition of <code>VMKAPI_MODULE_CALL_VOID</code>,
which is quoted below (with debug lines removed):
<pre>
#define VMKAPI_MODULE_CALL_VOID(moduleID, function, args...) \
do { \
vmk_ModInfoStack modStack; \
vmk_ModulePushId(moduleID, function, &modStack); \
(function)(args); \
) \
vmk_ModulePopId(); \
} while(0)
</pre>
<p>When the macro is expanded, it means that <code>(function)(args)</code> is
actually expanded to <code>linuxDev->driver->remove(linuxDev)</code>.
Therefore, we see <code>LinuxPCIDeviceRemoved()</code>, makes directs calls
to a driver's remove() function, by combining with Linux's <code>struct
pci</code>, and by VMware's introduction of this new calling code.
Conservancy has confirmed many drivers from Linux are incorporated via
these mechanisms; one specific example is discussed next.</p>
<h4>Combination of the tg3 driver with &ldquo;vmkernel&rdquo;</h4>
<p>VMware includes a file <code>vmkdrivers/src_9/drivers/net/tg3/tg3.c</code>
in their source release. This file appears to be Linux's tg3 driver. It
includes a definition of the <code>struct pci_dev</code> for this device,
which reads:
<pre>
static struct pci_driver tg3_driver = {
[...]
.remove = __devexit_p(tg3_remove_one),
</pre>
</p>
<p>Therefore, when the code in <code>LinuxPCIDeviceRemoved()</code>
calls <code>linuxDev->driver->remove(linuxDev)</code>, the code ultimately
called (in the case where a tg3 card is driven by the kernel)
is <code>tg3_remove_one()</code>, which is found in <code>tg3.c</code> and
comes directly from Linux.</p>
<p>(Note: <code>__devexit_p</code> is a straightforward macro found
in <code>vmkdrivers/src_92/include/linux/init.h</code> (which also comes
from Linux) that will simply expand to its first argument in this
case.)</p>
<h4>VMware distribution of binary version of <code>tg3.c</code></h4>
<p>VMware furthermore distributes a modified version of <code>tg.c</code> in
binary form. This can be found in <code>usr/lib/vmware/vmkmod/tg3</code>,
which is extracted by un-vmtar'ing the file <code>net_tg3.v00</code> (found
on the ESXi 5.5U2 installer ISO image). Conservancy has confirmed that
file is a compiled version of <code>tg3.c</code></p>
<h4>Conclusions</h4>
<p>Given this evidence and related contextual clues, the only logical
conclusions are:</p>
<ul><li><code>vmklinux_9</code>, as a binary object, dynamically links
with <code>k.b00</code>, another binary object, to form a single running
binary.</li>
<li>That binary contains code licensed under the GPLv2, and can be
distributed in binary form only under permissions provided under
GPLv2 &mdash; in particular <a href="https://gnu.org/licenses/gpl-2.0.html#section2">GPLv2&sect;2</a> and <a href="https://gnu.org/licenses/gpl-2.0.html#section3">GPLv2&sect;3</a>.</li>
<ul><li><code>vmklinux_9</code>, a binary object, dynamically links with
the binary objects: <code>k.b00</code> and <code>tg3</code> (the
driver built from <code>tg3.c</code>'s source). These three binary
objects together form a single running binary (likely along with many
other binary objects as well).</li>
<li>That single running binary contains code licensed under the GPLv2
&mdash; namely the code derived from <code>tg3.c</code>
and <code>pci.h</code>. Thus, the single running binary may be
distributed in binary form only under permissions provided under GPLv2
&mdash; in
particular <a href="https://gnu.org/licenses/gpl-2.0.html#section2">GPLv2&sect;2</a>
and <a href="https://gnu.org/licenses/gpl-2.0.html#section3">GPLv2&sect;3</a>.</li>
<li>GPLv2&sect;3(a&ndash;b) requires that <q>complete corresponding
machine-readable source code</q> must accompany binary
distributions such as these. GPLv2&sect;3 further states
that <q>for an executable work, complete source code means all the
source code for all modules it contains</q>.</li>
<li>The binary work in question contains modules from <code>k.b00</code> and
<code>vmlinux_9</code>.</li>
<li>The binary work in question contains modules from <code>k.b00</code>,
<code>vmlinux_9</code> and <code>tg3</code>.</li>
<li>VMware did not provide source code for any modules found in
<code>k.b00</code>.</li>
<li>Therefore, VMware failed to comply with the GPLv2, as such
@ -315,7 +429,7 @@ for <code>vmk_PCIGetDeviceName</code>.</p>
in <code>k.b00</code>.</li>
</ul>
<p>The above is but one piece of evidence among many, but hopefully it helps
to explain the types of &ldquo;combined work&rdquo; violations found in
to explain some of the &ldquo;combined work&rdquo; violations found in
VMware's ESXi product.</p>
<dt id="verify">How can I verify Conservancy's technical findings above?</dt>