Bareflank / extended_apis_example_hook

deprecated

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Question] Allocate additional pages

no-realm opened this issue · comments

commented

Hi,

I am trying to allocate an additional page/entry identical to an already existing page/entry.
Also, how can I swap between them?

I would need to know more about what your trying to do to understand your question. As for swapping EPT entries in an already existing tree, we don't have any code to do that today outside of creating a second EPT tree like we do in this example as that is the approach done most of time so that you can leverage VE latter on.

commented

What I am basically trying to archive is tlb splitting.
I plan on doing it like this:

I have one EPT with 2m or 4k identity mapping (4k doesn't seem to work though).
Then I either preallocate some pages, or allocate them on demand.
When the client requests a hook, the passed virtual address gets translated to a physical address, for which I get the corresponding page with gpa_to_epte.
Then I copy the contents of the data page to a preallocated or newly allocated code page.
Read/Write access is given to the data page and only execute access to the code page.
When an ept violation happens, I check for which page and if the page is 'hooked' I switch between them correspondingly.

We actually did TLB splitting with MoRE: https://github.com/ainfosec/MoRE

At some point, we want to convert this to the newer Bareflank hypervisor. The hypervisor that was used here is an older one (almost 10 years old) based on some work from Shawn Embelton. Take a look at Jacob's approach as this worked really well.

commented

I mostly know what I want to do, but not how to do it with this hypervisor.

At the moment I have this here, but it causes my system to freeze.
tlb.zip

Edit: It seems to be caused by this line (exit_handler_hook.h):

std::memcpy(g_code_pointer, reinterpret_cast<void*>(func_phys_2m), ept::pd::size_bytes);

Couple of notes (quick glance at the code):

  • The memcpy that your making uses the physical address of memory as the "src", which you cannot do since paging is enabled. If you want to copy the contents of a physical page, you first have to map that physical page into memory, and use the virtual address as your "src"
  • I noticed that your using g_mm->alloc(). I'm impressed that you have learned the APIs so well. I would however suggest using new/delete or even better yet, std::make_unique to allocate your memory instead of directly calling into the memory manager.

Hope that helps.

commented

Ah, ok. I will try to come up with something 😄

commented

Hi, I had to work on some other projects, so this got a bit delayed.
Anyway, I think that I am very close to completing this, but I can't seem to get memcpy to work 🙁

This is basically how I planned on doing it:

auto &&func_virt = regs.r03;
auto &&aligned_4k_virt = func_virt & ~(ept::pt::size_bytes - 1);
auto &&code_page = std::make_unique<unsigned char[]>(ept::pt::size_bytes);
auto &&code_virtptr = reinterpret_cast<void*>(&code_page[0]);
std::memcpy(code_virtptr, reinterpret_cast<void*>(aligned_4k_virt), ept::pt::size_bytes);

I omitted the rest of the code to keep it simple, but when I try to do it like I wrote above, it freezes my PC.
Any idea why?

I also tried to just copy 8 bytes but that also didn't work:

auto &&func_phys = bfn::virt_to_phys_with_cr3(func_virt, cr3);
auto &&aligned_4k_phys = func_phys & ~(ept::pt::size_bytes - 1);

uintptr_t dst = 0;
std::memcpy(&dst, reinterpret_cast<void*>(aligned_4k_virt), sizeof(dst)); // does not work
std::memcpy(&dst, reinterpret_cast<void*>(aligned_4k_phys), sizeof(dst)); // does not work
bfdebug << "dst: " << view_as_pointer(dst) << bfendl;

You have to map the memory into the VMM's CR3 if your going to copy. The virtual address is the host OS's virtual address, not the VMM's. To map memory, please see the following:

https://github.com/Bareflank/hypervisor/blob/master/bfvmm/include/memory_manager/map_ptr_x64.h

commented

Which one? The newly allocated memory or the "src" memory?
Maybe you could provide me with a little example for how I can allocate a new page and then copy the contents of the old page to the new one?

The newly allocated memory is VMM memory, so it's already mapped. The "src" memory belongs to the host OS (i.e. a guest VM), and thus doesn't have a page table mapping in the VMM.

commented

Ok, when I try to use the following, I get an error when I compile, since I only provide 3 args when 4 are needed.

auto &&vmm_map = bfn::make_unique_map_x64<unsigned char>(func_virt_4k, cr3, ept::pt::size_bytes);

But the example also only shows 3 args and I honestly don't know what is meant with:

/// @param pat the pat msr associated with the provided cr3

ha.... yeah... the docs for that need to be updated. The PAT refers to the Page Attribution Table, which basically defines how the host OS has setup it's caching types. To prevent really weird issues with caching, we need to know how the memory is mapped so that we do not mess up the cache, so what you need to provide is the guest's PAT. To be honest.... we should probably setup and example of this so that it's clear as to how this all works, but for now, you can see the code here:

https://github.com/Bareflank/hypervisor/blob/master/bfvmm/src/exit_handler/src/exit_handler_intel_x64.cpp#L494

commented

I have managed to get my TLB-Split implementation working, so I will close this issue.
Thanks for your support! ^^

congrats man, that's awesome

commented

@rianquinn Just wanted to let you know that my code is now public: tlb-split
You can take a look at it if you want to.
If you spot any issues, feel free to report them ^^