Index: VirtualBox-5.1.22/src/VBox/HostDrivers/Support/posix/SUPR3HardenedMain-posix.cpp
===================================================================
--- VirtualBox-5.1.22/src/VBox/HostDrivers/Support/posix/SUPR3HardenedMain-posix.cpp	(revision 115126)
+++ VirtualBox-5.1.22/src/VBox/HostDrivers/Support/posix/SUPR3HardenedMain-posix.cpp	(revision 115307)
@@ -341,6 +341,7 @@
      * Patch 64-bit hosts.
      */
     uint32_t cRipRelMovs = 0;
+    uint32_t cRelCalls = 0;
 
     /* Just use the disassembler to skip 12 bytes or more, we might need to
        rewrite mov instructions using RIP relative addressing. */
@@ -349,7 +350,8 @@
         cbInstr = 1;
         int rc = DISInstr(pbTarget + offJmpBack, DISCPUMODE_64BIT, &Dis, &cbInstr);
         if (   RT_FAILURE(rc)
-            || (Dis.pCurInstr->fOpType & DISOPTYPE_CONTROLFLOW)
+            || (   Dis.pCurInstr->fOpType & DISOPTYPE_CONTROLFLOW
+                && Dis.pCurInstr->uOpcode != OP_CALL)
             || (   Dis.ModRM.Bits.Mod == 0
                 && Dis.ModRM.Bits.Rm  == 5 /* wrt RIP */
                 && Dis.pCurInstr->uOpcode != OP_MOV))
@@ -357,15 +359,23 @@
 
         if (Dis.ModRM.Bits.Mod == 0 && Dis.ModRM.Bits.Rm == 5 /* wrt RIP */)
             cRipRelMovs++;
+        if (   Dis.pCurInstr->uOpcode == OP_CALL
+            && (Dis.pCurInstr->fOpType & DISOPTYPE_RELATIVE_CONTROLFLOW))
+            cRelCalls++;
 
         offJmpBack += cbInstr;
         cbPatchMem += cbInstr;
     }
 
+    /*
+     * Each relative call requires extra bytes as it is converted to a pushq imm32
+     * + mov [RSP+4], imm32 + a jmp qword [$+8 wrt RIP] to avoid clobbering registers.
+     */
+    cbPatchMem += cRelCalls * RT_ALIGN_32(13 + 6 + 8, 8);
     cbPatchMem += 14; /* jmp qword [$+8 wrt RIP] + 8 byte address to jump to. */
     cbPatchMem = RT_ALIGN_32(cbPatchMem, 8);
 
-    /* Allocate suitable exectuable memory available. */
+    /* Allocate suitable executable memory available. */
     bool fConvRipRelMovs = false;
     uint8_t *pbPatchMem = supR3HardenedMainPosixExecMemAlloc(cbPatchMem, pbTarget, cRipRelMovs > 0);
     if (!pbPatchMem)
@@ -396,7 +406,8 @@
         cbInstr = 1;
         int rc = DISInstr(pbTarget + offInsn, DISCPUMODE_64BIT, &Dis, &cbInstr);
         if (   RT_FAILURE(rc)
-            || (Dis.pCurInstr->fOpType & DISOPTYPE_CONTROLFLOW))
+            || (   Dis.pCurInstr->fOpType & DISOPTYPE_CONTROLFLOW
+                && Dis.pCurInstr->uOpcode != OP_CALL))
             return VERR_SUPLIB_UNEXPECTED_INSTRUCTION;
 
         if (   Dis.ModRM.Bits.Mod == 0
@@ -439,6 +450,34 @@
                 pbPatchMem   += sizeof(int32_t);
             }
         }
+        else if (   Dis.pCurInstr->uOpcode == OP_CALL
+                 && (Dis.pCurInstr->fOpType & DISOPTYPE_RELATIVE_CONTROLFLOW))
+        {
+            /* Convert to absolute jump. */
+            uintptr_t uAddr = (uintptr_t)&pbTarget[offInsn + cbInstr] + (intptr_t)Dis.Param1.uValue;
+
+            /* Skip the push instructions till the return address is known. */
+            uint8_t *pbPatchMemPush = pbPatchMem;
+            pbPatchMem += 13;
+
+            *pbPatchMem++ = 0xff; /* jmp qword [$+8 wrt RIP] */
+            *pbPatchMem++ = 0x25;
+            *(uint32_t *)pbPatchMem = (uint32_t)(RT_ALIGN_PT(pbPatchMem + 4, 8, uint8_t *) - (pbPatchMem + 4));
+            pbPatchMem = RT_ALIGN_PT(pbPatchMem + 4, 8, uint8_t *);
+            *(uint64_t *)pbPatchMem = uAddr;
+            pbPatchMem += sizeof(uint64_t);
+
+            /* Push the return address onto stack. Difficult on amd64 without clobbering registers... */
+            uintptr_t uAddrReturn = (uintptr_t)pbPatchMem;
+            *pbPatchMemPush++ = 0x68; /* push imm32 sign-extended as 64-bit*/
+            *(uint32_t *)pbPatchMemPush = RT_LO_U32(uAddrReturn);
+            pbPatchMemPush += sizeof(uint32_t);
+            *pbPatchMemPush++ = 0xc7;
+            *pbPatchMemPush++ = 0x44;
+            *pbPatchMemPush++ = 0x24;
+            *pbPatchMemPush++ = 0x04; /* movl [RSP+4], imm32 */
+            *(uint32_t *)pbPatchMemPush = RT_HI_U32(uAddrReturn);
+        }
         else
         {
             memcpy(pbPatchMem, pbTarget + offInsn, cbInstr);
Index: VirtualBox-5.1.22/src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp
===================================================================
--- VirtualBox-5.1.22/src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp	(revision 115126)
+++ VirtualBox-5.1.22/src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp	(revision 115307)
@@ -86,6 +86,9 @@
 /** The max path length acceptable for a trusted path. */
 #define SUPR3HARDENED_MAX_PATH      260U
 
+/** Enable to resolve symlinks using realpath() instead of cooking our own stuff. */
+#define SUP_HARDENED_VERIFY_FOLLOW_SYMLINKS_USE_REALPATH 1
+
 #ifdef RT_OS_SOLARIS
 # define dirfd(d) ((d)->d_fd)
 #endif
@@ -1091,7 +1094,8 @@
 #endif
 
 
-#if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX)
+#ifndef SUP_HARDENED_VERIFY_FOLLOW_SYMLINKS_USE_REALPATH
+# if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX)
 /**
  * Copies the error message to the error buffer and returns @a rc.
  *
@@ -1104,6 +1108,7 @@
 {
     return supR3HardenedSetErrorN(rc, pErrInfo, 1, pszMsg);
 }
+# endif
 #endif
 
 
@@ -1893,7 +1898,9 @@
     /*
      * Verify each component from the root up.
      */
+#ifndef SUP_HARDENED_VERIFY_FOLLOW_SYMLINKS_USE_REALPATH
     uint32_t                iLoops = 0;
+#endif
     SUPR3HARDENEDFSOBJSTATE FsObjState;
     uint32_t                iComponent = 0;
     while (iComponent < Info.cComponents)
@@ -1915,6 +1922,24 @@
             if (   RT_SUCCESS(rc)
                 && S_ISLNK(FsObjState.Stat.st_mode))
             {
+#if SUP_HARDENED_VERIFY_FOLLOW_SYMLINKS_USE_REALPATH /* Another approach using realpath() and verifying the result when encountering a symlink. */
+                char *pszFilenameResolved = realpath(pszFilename, NULL);
+                if (pszFilenameResolved)
+                {
+                    rc = supR3HardenedVerifyFile(pszFilenameResolved, hNativeFile, fMaybe3rdParty, pErrInfo);
+                    free(pszFilenameResolved);
+                    return rc;
+                }
+                else
+                {
+                    int iErr = errno;
+                    supR3HardenedError(VERR_ACCESS_DENIED, false /*fFatal*/,
+                                       "supR3HardenedVerifyFileFollowSymlinks: Failed to resolve the real path '%s': %s (%d)\n",
+                                       pszFilename, strerror(iErr), iErr);
+                    return supR3HardenedSetError4(VERR_ACCESS_DENIED, pErrInfo,
+                                                  "realpath failed for '", pszFilename, "': ", strerror(iErr));
+                }
+#else
                 /* Don't loop forever. */
                 iLoops++;
                 if (iLoops < 8)
@@ -1989,6 +2014,7 @@
                 else
                     return supR3HardenedSetError3(VERR_TOO_MANY_SYMLINKS, pErrInfo,
                                                   "Too many symbolic links: '", pszFilename, "'");
+#endif
             }
         }
         if (RT_FAILURE(rc))