-
Notifications
You must be signed in to change notification settings - Fork 457
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Linux - PROT_NONE, L1TF mitigation and layer address translation fix #1335
base: develop
Are you sure you want to change the base?
Linux - PROT_NONE, L1TF mitigation and layer address translation fix #1335
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Roughly happy with the concept, but needs to be more accurate on what's linux and what's general Intel. I'm a little concern that we're exposing the guts of the layer and that not that many parameters need to be accessible by the OS/outside the layer (we did name method starting with _
for a reason). If we're happy it's all important and necessary then it's not far off getting merged.
# Mask off the PAT bit | ||
if entry & (1 << 12): | ||
entry -= 1 << 12 | ||
if entry & (1 << linux_constants.PAGE_BIT_PAT_LARGE): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These shouldn't be in linux_constants
if they're for all intel layers? They're presumably defined as part of the architecture and shouldn't change. If they are OS specific then we need to rethink how we access them.
|
||
return page, 1 << (position + 1), self._base_layer | ||
|
||
def pte_pfn(self, entry: int) -> int: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bump to the MINOR version of the framework, at a minimum.
offset, position, 0 | ||
) | ||
|
||
pfn = self.pte_pfn(entry) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the improvement made by these changes? It feels like it just splits things and rejoins them, or is it just for clarity?
# Translation Layer constants | ||
PAGE_BIT_PRESENT = 0 | ||
PAGE_BIT_PSE = 7 # Page Size Extension: 4 MB (or 2MB) page | ||
PAGE_BIT_PROTNONE = 8 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These don't belong in linux unless they're linux specific constants (in which case we need to rethink how they're used based on which OS the layer is constructed on.
|
||
class LinuxMixin(Intel): | ||
@functools.cached_property | ||
def register_mask(self) -> int: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is exposing a lot of additional fields and I just want to make sure the balance is right between things that the OS might actually need to know about, and things that really should only be used internally by the intel layer. At the moment the guts feel like they're on the outside and I want to be sure every single method we expose is worthwhile.
I'd also change TODOs that we know aren't accurate to FIXMEs please, otherwise there'll be no urgency of any kind of improve them and this will all just be adding extra lines for no reason.
This PR introduces improvements and fixes for address translation in the Linux Intel layers
PROT_NONE pages
First, this PR fixes one of the oldest issues in the queue #134, adding support for PROT_NONE protected pages.
Using the @gleeda PoC from their excellent post Using mprotect PROT_NONE on Linux.
$ ./victim PID 2116 buffer at 0x76f63a132000 <= PROT_NONE vma buffer2 at 0x76f63a133000
Before:
After:
Intel Side Channel Vulnerability L1TF mitigation.
In 2018, to mitigate Intel's L1TF (L1 Terminal Fault) vulnerability, that code in Linux kernel was again updated in this commit, incorporating PTE inversion to calculate the PFN. This PR includes support for handling these cases as well.
__PHYSICAL_MASK_SHIFT and _maxphyaddr
While addressing the previous issues, I found that the changes didn't work for older kernels. After further investigation, it turned out the problem was the
physical_mask
and the reason was this commit.In the Linux kernel, the __PHYSICAL_MASK_SHIFT is a mask used to extract the physical address from a PTE. In Volatility3, this is referred to as
_maxphyaddr
.Until kernel version 4.17, Linux x86-64 used a 46-bit mask. With this commit, this was extended to 52 bits, applying to both 4 and 5-level page tables.
We previously used 52 bits for all Intel 64-bit systems, but this produced incorrect results for PROT_NONE pages. Since the mask value is defined by a preprocessor macro, it's difficult to detect the exact bit shift used in the current kernel.
Using 46 bits has proven reliable for our use case, as seen in tools like crashtool. See this and this.