Fix loading of NI images on SELinux
authorJan Vorlicek <janvorli@microsoft.com>
Sat, 23 Apr 2016 19:15:29 +0000 (12:15 -0700)
committerJan Vorlicek <janvorli@microsoft.com>
Sat, 23 Apr 2016 21:42:58 +0000 (14:42 -0700)
This change fixes a problem that prevents us to load crossgen-ed managed
assemblies on SELinux when running in confined mode.
The problem was that when we load these images, we also apply relocations
to their sections and so we temporarily switch section protection from
RX to RW and then back. And the switching back (RW -> RX) is something
that SELinux doesn't allow.
The fix is to switch to RWX before applying to relocations for sections
that are RX, since it is allowed then to switch them back to RX.
One more change was needed to get the original protection of the section
before relocation so that we can set it back later. The PE files are
not mapped using VirtualXXXX functions in the PAL and so VirtualProtect
doesn't return the proper original protection, but a fixed value instead.
So for PAL, we derive the original protection from the section attributes.

src/vm/peimagelayout.cpp

index 80d2b87..b5d50b5 100644 (file)
@@ -93,6 +93,40 @@ PEImageLayout* PEImageLayout::Map(HANDLE hFile, PEImage* pOwner)
 }
 
 #ifdef FEATURE_PREJIT
+
+#ifdef FEATURE_PAL
+DWORD SectionCharacteristicsToPageProtection(UINT characteristics)
+{
+    _ASSERTE((characteristics & VAL32(IMAGE_SCN_MEM_READ)) != 0);
+    DWORD pageProtection;
+
+    if ((characteristics & VAL32(IMAGE_SCN_MEM_WRITE)) != 0)
+    {
+        if ((characteristics & VAL32(IMAGE_SCN_MEM_EXECUTE)) != 0)
+        {
+            pageProtection = PAGE_EXECUTE_READWRITE;
+        }
+        else
+        {
+            pageProtection = PAGE_READWRITE;
+        }
+    }
+    else
+    {
+        if ((characteristics & VAL32(IMAGE_SCN_MEM_EXECUTE)) != 0)
+        {
+            pageProtection = PAGE_EXECUTE_READ;
+        }
+        else
+        {
+            pageProtection = PAGE_READONLY;
+        }
+    }
+
+    return pageProtection;
+}
+#endif // FEATURE_PAL
+
 //To force base relocation on Vista (which uses ASLR), unmask IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
 //(0x40) for OptionalHeader.DllCharacteristics
 void PEImageLayout::ApplyBaseRelocations()
@@ -154,9 +188,21 @@ void PEImageLayout::ApplyBaseRelocations()
             // Unprotect the section if it is not writable
             if (((pSection->Characteristics & VAL32(IMAGE_SCN_MEM_WRITE)) == 0))
             {
+                DWORD dwNewProtection = PAGE_READWRITE;
+#ifdef FEATURE_PAL
+                if (((pSection->Characteristics & VAL32(IMAGE_SCN_MEM_EXECUTE)) != 0))
+                {
+                    // On SELinux, we cannot change protection that doesn't have execute access rights
+                    // to one that has it, so we need to set the protection to RWX instead of RW
+                    dwNewProtection = PAGE_EXECUTE_READWRITE;
+                }
+#endif // FEATURE_PAL
                 if (!ClrVirtualProtect(pWriteableRegion, cbWriteableRegion,
-                                       PAGE_READWRITE, &dwOldProtection))
+                                       dwNewProtection, &dwOldProtection))
                     ThrowLastError();
+#ifdef FEATURE_PAL
+                dwOldProtection = SectionCharacteristicsToPageProtection(pSection->Characteristics);
+#endif // FEATURE_PAL
             }
         }