Permalink
Browse files

Merge in the kvm_fix.patch

This commit _should_ make everybody (various combinations of 32 and 64bit
bare-metal, xen, kvm) happy. So far in tests there are no crashes. Pushing
this commit to get feedback from others. Crossing my fingers!
  • Loading branch information...
cormander committed Mar 11, 2012
1 parent 5e54744 commit d30730538d042d063b5d4078e35895300278c82e
Showing with 54 additions and 153 deletions.
  1. +3 −10 README
  2. +51 −23 hijacks.c
  3. +0 −120 kvm_fix.patch
View
13 README
@@ -94,7 +94,7 @@ This has been tested on the following systems (x86, both 32 and 64bit):
- RHEL/CentOS 5 (linux-2.6.18)
- RHEL/CentOS 6 (linux-2.6.32)
- RHEL/Centos Xen, both xenU (el5) and pvops (el6)
- - RHEL/CentOS KVM**
+ - RHEL/CentOS KVM
- Ubuntu 10.04 LTS (linux-2.6.32)
- Ubuntu 11.04 (linux-2.6.38)
@@ -103,8 +103,6 @@ on the above systems. It hasn't been tested with linux 3.0 or higher yet, and
preliminary peek reveals changes to the do_execve ABI. I'll likely make the
effort to port it when a major distribution using that kernel comes out.
-** See the BUGS section for some information about tpe with KVM
-
===============================================================================
Compatibility Issues
@@ -141,13 +139,8 @@ way to bypass the trusted path, let me know, and I'll update this code.
BUGS
-This is a list of known bugs:
-
-* KVM virtual machine crash on module load
-
-Some KVM virtual machines crash when tpe is loaded. If this affects you, apply
-the kvm_fix.patch and recompile, and the problem should go away. More
-information about this bug is contained in the header of that patch file.
+There are currently no known bugs. If you discover one, please report it to the
+author.
===============================================================================
View
@@ -71,65 +71,93 @@ void copy_and_fixup_insn(struct insn *src_insn, void *dest,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+#if defined(CONFIG_XEN)
#include <asm/cacheflush.h>
+#endif
-// TODO: this implementation just ignores the flag, not currently sure how to check
-// if the page is already set to read/write
-
-void set_addr_rw(unsigned long addr, bool *flag) {
-
- struct page *pg;
-
- pgprot_t prot;
- pg = virt_to_page(addr);
- prot.pgprot = VM_READ | VM_WRITE;
- change_page_attr(pg, 1, prot);
+// copied from centos5 arch/x86_64/mm/pageattr.c
+static inline pte_t *tpe_lookup_address(unsigned long address, unsigned int *level)
+{
+ pgd_t *pgd = pgd_offset_k(address);
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ if (pgd_none(*pgd))
+ return NULL;
+ pud = pud_offset(pgd, address);
+ if (!pud_present(*pud))
+ return NULL;
+ pmd = pmd_offset(pud, address);
+ if (!pmd_present(*pmd))
+ return NULL;
+ if (pmd_large(*pmd))
+ return (pte_t *)pmd;
+ pte = pte_offset_kernel(pmd, address);
+ if (pte && !pte_present(*pte))
+ pte = NULL;
+ return pte;
}
-void set_addr_ro(unsigned long addr, bool flag) {
+#else
+#define tpe_lookup_address(address, level) lookup_address(address, level);
+#endif
+
+void set_addr_rw(unsigned long addr, bool *flag) {
+#if defined(CONFIG_XEN) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
struct page *pg;
pgprot_t prot;
pg = virt_to_page(addr);
- prot.pgprot = VM_READ;
+ prot.pgprot = VM_READ | VM_WRITE;
change_page_attr(pg, 1, prot);
-
-}
-
#else
-
-void set_addr_rw(unsigned long addr, bool *flag) {
-
unsigned int level;
pte_t *pte;
*flag = true;
- pte = lookup_address(addr, &level);
+ pte = tpe_lookup_address(addr, &level);
+#if !defined(CONFIG_X86_64) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+ if (pte_val(*pte) & _PAGE_RW) *flag = false;
+ else pte_val(*pte) |= _PAGE_RW;
+#else
if (pte->pte & _PAGE_RW) *flag = false;
else pte->pte |= _PAGE_RW;
+#endif
+#endif
}
void set_addr_ro(unsigned long addr, bool flag) {
+#if defined(CONFIG_XEN) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+ struct page *pg;
+
+ pgprot_t prot;
+ pg = virt_to_page(addr);
+ prot.pgprot = VM_READ;
+ change_page_attr(pg, 1, prot);
+#else
unsigned int level;
pte_t *pte;
// only set back to readonly if it was readonly before
if (flag) {
- pte = lookup_address(addr, &level);
+ pte = tpe_lookup_address(addr, &level);
+#if !defined(CONFIG_X86_64) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+ pte_val(*pte) = pte_val(*pte) &~_PAGE_RW;
+#else
pte->pte = pte->pte &~_PAGE_RW;
+#endif
}
+#endif
}
-#endif
-
int symbol_hijack(struct kernsym *sym, const char *symbol_name, unsigned long *code) {
int ret;
View
@@ -1,120 +0,0 @@
-On some KVM virtual machines, insertion of tpe causes the VM to crash. This
-patch appears to fix the issue - but causes xen kernels to crash when inserted.
-Quite the tradeoff, eh?
-
-Since this patch was kind of rushed, I didn't want to put it straight in. Also,
-all my own testing systems are either bare-metal or Xen, so I haven't had much
-by the way of resources to test it beyond the initial "okay we're good now!".
-At some point in the future, I'll get this in so the module works right with
-bare-metal, KVM, and xen kernel environments without having to patch anything.
-
-This patch is a temporary measure until a more permanent solution is put in.
-
-Feedback is appriciated.
-
-diff --git a/hijacks.c b/hijacks.c
-index e565be8..fc7f348 100644
---- a/hijacks.c
-+++ b/hijacks.c
-@@ -71,46 +71,51 @@ void copy_and_fixup_insn(struct insn *src_insn, void *dest,
-
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
-
--#include <asm/cacheflush.h>
--
--// TODO: this implementation just ignores the flag, not currently sure how to check
--// if the page is already set to read/write
--
--void set_addr_rw(unsigned long addr, bool *flag) {
--
-- struct page *pg;
--
-- pgprot_t prot;
-- pg = virt_to_page(addr);
-- prot.pgprot = VM_READ | VM_WRITE;
-- change_page_attr(pg, 1, prot);
-+// copied from centos5 arch/x86_64/mm/pageattr.c
-
-+static inline pte_t *tpe_lookup_address(unsigned long address, unsigned int *level)
-+{
-+ pgd_t *pgd = pgd_offset_k(address);
-+ pud_t *pud;
-+ pmd_t *pmd;
-+ pte_t *pte;
-+ if (pgd_none(*pgd))
-+ return NULL;
-+ pud = pud_offset(pgd, address);
-+ if (!pud_present(*pud))
-+ return NULL;
-+ pmd = pmd_offset(pud, address);
-+ if (!pmd_present(*pmd))
-+ return NULL;
-+ if (pmd_large(*pmd))
-+ return (pte_t *)pmd;
-+ pte = pte_offset_kernel(pmd, address);
-+ if (pte && !pte_present(*pte))
-+ pte = NULL;
-+ return pte;
- }
-
--void set_addr_ro(unsigned long addr, bool flag) {
--
-- struct page *pg;
--
-- pgprot_t prot;
-- pg = virt_to_page(addr);
-- prot.pgprot = VM_READ;
-- change_page_attr(pg, 1, prot);
-+#else
-
--}
-+#define tpe_lookup_address(address, level) lookup_address(address, level);
-
--#else
-+#endif
-
- void set_addr_rw(unsigned long addr, bool *flag) {
-
- unsigned int level;
- pte_t *pte;
-
-+#if defined(CONFIG_XEN) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
-+ return;
-+#else
- *flag = true;
-
-- pte = lookup_address(addr, &level);
-+ pte = tpe_lookup_address(addr, &level);
-
-- if (pte->pte & _PAGE_RW) *flag = false;
-- else pte->pte |= _PAGE_RW;
-+ if (pte_val(*pte) & _PAGE_RW) *flag = false;
-+ else pte_val(*pte) |= _PAGE_RW;
-+#endif
-
- }
-
-@@ -119,17 +124,19 @@ void set_addr_ro(unsigned long addr, bool flag) {
- unsigned int level;
- pte_t *pte;
-
-+#if defined(CONFIG_XEN) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
-+ return;
-+#else
- // only set back to readonly if it was readonly before
- if (flag) {
-- pte = lookup_address(addr, &level);
-+ pte = tpe_lookup_address(addr, &level);
-
-- pte->pte = pte->pte &~_PAGE_RW;
-+ pte_val(*pte) = pte_val(*pte) &~_PAGE_RW;
- }
-+#endif
-
- }
-
--#endif
--
- int symbol_hijack(struct kernsym *sym, const char *symbol_name, unsigned long *code) {
-
- int ret;

0 comments on commit d307305

Please sign in to comment.