From ea9a59c551f8b022d2f44dc67789748389883ac0 2015-03-21 14:31:07 From: Bradley M. Kuhn Date: 2015-03-21 14:31:07 Subject: [PATCH] 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. --- diff --git a/www/conservancy/static/linux-compliance/vmware-lawsuit-faq.html b/www/conservancy/static/linux-compliance/vmware-lawsuit-faq.html index 2efa3375dac203e91c5bd99c3292aa9a47959b70..c91a2988cee951fb89b1c5e9f710cf8cb9182845 100644 --- a/www/conservancy/static/linux-compliance/vmware-lawsuit-faq.html +++ b/www/conservancy/static/linux-compliance/vmware-lawsuit-faq.html @@ -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 “vmkernel” in a tightly coupled manner.

-
Is Conservancy proposing a “shim layer” as a viable solution for GPL compliance?
@@ -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. -
Can you give a specific example, with code, showing how +
Can you give a specific example, with code, showing how VMware combined Linux source code with their binary-only components?

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.

-

Example of “vmkernel”'s combination with Linux code

-

As one example, examine the file +

Example of “vmkernel”'s combination with Linux code

+

Our example begins with examination of the file called vmkdrivers/src_92/vmklinux_92/vmware/linux_pci.c, which can be found in the “Open Source” release for ESXi 5.5.0 Update 2 (5.5U2). A small excerpt from that file, found in the function LinuxPCIDeviceRemoved(), reads as follows:

-if (unlikely(
-  /* NOTE: vmk_PCIGetDeviceName is defined in vmvisor64-vmkernel */
-  vmk_PCIGetDeviceName(vmkDev, vmkDevName, sizeof(vmkDevName)-1) != VMK_OK))
+#include 
+[...]
+/*
+ * This function [...] is modelled after pci_remove_device, the function which would
+ * be called in a linux system.
+ */
+static void
+LinuxPCIDeviceRemoved(vmk_PCIDevice vmkDev)
 {
-    vmkDevName[0] = 0;
-}
+   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);
 
+

Combination of “vmkernel” code with “vmkdrivers”

+

The function, vmk_PCIGetDeviceName() must be defined, with an implementation, for this code above to work, or even compile. Inside BLD/build/HEADERS/vmkapi-current-all-public/vmkernel64/release/device/vmkapi_pci_incompat.h, @@ -286,28 +297,131 @@ VMKAPI_MODULE_CALL_VOID(pciDevExt->moduleID,

… which indicated these binary file contains the function body for vmk_PCIGetDeviceName.

-

Finally, after detailed searching, Conservancy found no evidence that any +

Furthermore, after detailed searching, Conservancy found no evidence that any other code (other than modified Linux code) makes calls to vmk_PCIGetDeviceName. This provides a strong indication that this function's primary purpose is to combine Linux code with “vmkernel”. Conservancy also found other functions where similar analysis yields similar results as above.

+

Linux's struct pci combined with LinuxPCIDeviceRemoved()

+ +

Having established the direct and close combination + of vmk_PCIGetDeviceName + and LinuxPCIDeviceRemoved(), focus now on the + quoted code from LinuxPCIDeviceRemoved(). That code, note + that one of the local variables is struct pci_dev *linuxDev;. + A definition of pci_dev is found in + vmkdrivers/src_92/include/linux/pci.h (which + is #include'd above) reads: +

+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__) */
+  };
+

+ +

These structures, and based on those from Linux itself + (a + similar version of this file can be seen in Linux 2.6.24), and as can + be seen above, have been modified to work with “vmkernel”

+ +

In LinuxPCIDeviceRemoved(), we saw a macro called with a + variable, linuxDev which was of type struct pci. + Thus, the combination of code from Linux's pci.h + and VMware's vmware/linux_pci.c is very tightly coupled and + interdependent.

+ +

VMKAPI_MODULE_CALL_VOID macro calls driver's code

+ +

The + file BLD/build/HEADERS/vmkapi-current-all-public/vmkernel64/release/base/vmkapi_module.h + contains the macro definition of VMKAPI_MODULE_CALL_VOID, + which is quoted below (with debug lines removed): +

+#define VMKAPI_MODULE_CALL_VOID(moduleID, function, args...)  \
+do {                                                    \
+    vmk_ModInfoStack modStack;                          \
+    vmk_ModulePushId(moduleID, function, &modStack);    \
+    (function)(args);                                   \
+    )                                                   \
+    vmk_ModulePopId();                                  \
+} while(0)
+
+ +

When the macro is expanded, it means that (function)(args) is + actually expanded to linuxDev->driver->remove(linuxDev). + Therefore, we see LinuxPCIDeviceRemoved(), makes directs calls + to a driver's remove() function, by combining with Linux's struct + pci, 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.

+ +

Combination of the tg3 driver with “vmkernel”

+ +

VMware includes a file vmkdrivers/src_9/drivers/net/tg3/tg3.c + in their source release. This file appears to be Linux's tg3 driver. It + includes a definition of the struct pci_dev for this device, + which reads: +

+static struct pci_driver tg3_driver = {
+[...]
+        .remove         = __devexit_p(tg3_remove_one),
+
+

+ +

Therefore, when the code in LinuxPCIDeviceRemoved() + calls linuxDev->driver->remove(linuxDev), the code ultimately + called (in the case where a tg3 card is driven by the kernel) + is tg3_remove_one(), which is found in tg3.c and + comes directly from Linux.

+ +

(Note: __devexit_p is a straightforward macro found + in vmkdrivers/src_92/include/linux/init.h (which also comes + from Linux) that will simply expand to its first argument in this + case.)

+ +

VMware distribution of binary version of tg3.c

+ +

VMware furthermore distributes a modified version of tg.c in + binary form. This can be found in usr/lib/vmware/vmkmod/tg3, + which is extracted by un-vmtar'ing the file net_tg3.v00 (found + on the ESXi 5.5U2 installer ISO image). Conservancy has confirmed that + file is a compiled version of tg3.c

+ +

Conclusions

+

Given this evidence and related contextual clues, the only logical conclusions are:

-