mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
bitkeeper revision 1.1159.21.1 (41193c65K9NbWw4E7FhhvSPwFS3svQ)
More binary-rewrite patches.
This commit is contained in:
1 parent
6dff829b83
commit
81e8a9dce6
5 files changed
+212
-165
No files matched your search
@@ -248,7 +248,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code,
|
||||
* (error_code & 4) == 0, and that the fault was not a
|
||||
* protection error (error_code & 1) == 0.
|
||||
*/
|
||||
if (unlikely(address >= TASK_SIZE)) {
|
||||
if (unlikely(address >= TASK_SIZE) ||
|
||||
unlikely(address < (FIRST_USER_PGD_NR<<PGDIR_SHIFT))) {
|
||||
if (!(error_code & 5))
|
||||
goto vmalloc_fault;
|
||||
/*
|
||||
|
||||
@@ -250,16 +250,21 @@ void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused)
|
||||
if (PTRS_PER_PMD == 1)
|
||||
spin_lock_irqsave(&pgd_lock, flags);
|
||||
|
||||
memcpy((pgd_t *)pgd + USER_PTRS_PER_PGD,
|
||||
swapper_pg_dir + USER_PTRS_PER_PGD,
|
||||
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
|
||||
memcpy((pgd_t *)pgd,
|
||||
swapper_pg_dir,
|
||||
FIRST_USER_PGD_NR * sizeof(pgd_t));
|
||||
memcpy((pgd_t *)pgd + FIRST_USER_PGD_NR + USER_PTRS_PER_PGD,
|
||||
swapper_pg_dir + FIRST_USER_PGD_NR + USER_PTRS_PER_PGD,
|
||||
(PTRS_PER_PGD - USER_PTRS_PER_PGD -
|
||||
FIRST_USER_PGD_NR) * sizeof(pgd_t));
|
||||
|
||||
if (PTRS_PER_PMD > 1)
|
||||
goto out;
|
||||
|
||||
pgd_list_add(pgd);
|
||||
spin_unlock_irqrestore(&pgd_lock, flags);
|
||||
memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
|
||||
memset((pgd_t *)pgd + FIRST_USER_PGD_NR,
|
||||
0, USER_PTRS_PER_PGD*sizeof(pgd_t));
|
||||
out:
|
||||
__make_page_readonly(pgd);
|
||||
queue_pgd_pin(__pa(pgd));
|
||||
|
||||
@@ -27,11 +27,12 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#if 0
|
||||
#if 1
|
||||
#define ASSERT(_p) \
|
||||
if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \
|
||||
__LINE__, __FILE__); *(int*)0=0; }
|
||||
@@ -43,35 +44,57 @@
|
||||
#define DPRINTK(_f, _a...) ((void)0)
|
||||
#endif
|
||||
|
||||
static char *fixup_buf;
|
||||
#define FIXUP_BUF_USER PAGE_SIZE
|
||||
#define FIXUP_BUF_ORDER 1
|
||||
#define FIXUP_BUF_SIZE (PAGE_SIZE<<FIXUP_BUF_ORDER)
|
||||
#define PATCH_LEN 5
|
||||
|
||||
struct fixup_entry {
|
||||
unsigned long patch_addr;
|
||||
unsigned long patch_addr; /* XXX */
|
||||
unsigned char patched_code[20];
|
||||
unsigned short patched_code_len;
|
||||
unsigned short fixup_idx;
|
||||
unsigned short return_idx;
|
||||
struct fixup_entry *next;
|
||||
};
|
||||
|
||||
#define FIXUP_HASHSZ 128
|
||||
static struct fixup_entry *fixup_hash[FIXUP_HASHSZ];
|
||||
#define FIXUP_HASH(_a) ((unsigned int)(_a) & (FIXUP_HASHSZ-1))
|
||||
static inline int FIXUP_HASH(char *b)
|
||||
{
|
||||
int i, j = 0;
|
||||
for ( i = 0; i < PATCH_LEN; i++ )
|
||||
j ^= b[i];
|
||||
return j & (FIXUP_HASHSZ-1);
|
||||
}
|
||||
|
||||
/* General instruction properties. */
|
||||
#define INSN_SUFFIX_BYTES (7)
|
||||
#define PREFIX_BYTE (1<<3)
|
||||
#define OPCODE_BYTE (1<<4)
|
||||
#define HAS_MODRM (1<<5)
|
||||
|
||||
#define X 0 /* invalid */
|
||||
/* Helpful codes for the main decode routine. */
|
||||
#define CODE_MASK (3<<6)
|
||||
#define PUSH (0<<6) /* PUSH onto stack */
|
||||
#define POP (1<<6) /* POP from stack */
|
||||
#define JMP (2<<6) /* 8-bit relative JMP */
|
||||
|
||||
/* Short forms for the table. */
|
||||
#define X 0 /* invalid for some random reason */
|
||||
#define S 0 /* invalid because it munges the stack */
|
||||
#define P PREFIX_BYTE
|
||||
#define O OPCODE_BYTE
|
||||
#define M HAS_MODRM
|
||||
|
||||
static unsigned char insn_decode[256] = {
|
||||
/* 0x00 - 0x0F */
|
||||
O|M, O|M, O|M, O|M, O|1, O|4, O, O,
|
||||
O|M, O|M, O|M, O|M, O|1, O|4, O, X,
|
||||
O|M, O|M, O|M, O|M, O|1, O|4, S, S,
|
||||
O|M, O|M, O|M, O|M, O|1, O|4, S, X,
|
||||
/* 0x10 - 0x1F */
|
||||
O|M, O|M, O|M, O|M, O|1, O|4, O, O,
|
||||
O|M, O|M, O|M, O|M, O|1, O|4, O, O,
|
||||
O|M, O|M, O|M, O|M, O|1, O|4, S, S,
|
||||
O|M, O|M, O|M, O|M, O|1, O|4, S, S,
|
||||
/* 0x20 - 0x2F */
|
||||
O|M, O|M, O|M, O|M, O|1, O|4, P, O,
|
||||
O|M, O|M, O|M, O|M, O|1, O|4, P, O,
|
||||
@@ -79,20 +102,20 @@ static unsigned char insn_decode[256] = {
|
||||
O|M, O|M, O|M, O|M, O|1, O|4, P, O,
|
||||
O|M, O|M, O|M, O|M, O|1, O|4, P, O,
|
||||
/* 0x40 - 0x4F */
|
||||
O, O, O, O, O, O, O, O,
|
||||
O, O, O, O, O, O, O, O,
|
||||
O, O, O, O, S, O, O, O,
|
||||
O, O, O, O, S, O, O, O,
|
||||
/* 0x50 - 0x5F */
|
||||
O, O, O, O, O, O, O, O,
|
||||
O, O, O, O, O, O, O, O,
|
||||
O|PUSH, O|PUSH, O|PUSH, O|PUSH, S, O|PUSH, O|PUSH, O|PUSH,
|
||||
O|POP, O|POP, O|POP, O|POP, S, O|POP, O|POP, O|POP,
|
||||
/* 0x60 - 0x6F */
|
||||
O, O, O|M, O|M, P, P, X, X,
|
||||
O|4, O|M|4, O|1, O|M|1, O, O, O, O,
|
||||
S, S, O|M, O|M, P, P, X, X,
|
||||
O|4|PUSH, O|M|4, O|1|PUSH, O|M|1, O, O, O, O,
|
||||
/* 0x70 - 0x7F */
|
||||
O|1, O|1, O|1, O|1, O|1, O|1, O|1, O|1,
|
||||
O|1, O|1, O|1, O|1, O|1, O|1, O|1, O|1,
|
||||
O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP,
|
||||
O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP,
|
||||
/* 0x80 - 0x8F */
|
||||
O|M|1, O|M|4, O|M|1, O|M|1, O|M, O|M, O|M, O|M,
|
||||
O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M,
|
||||
O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M|POP,
|
||||
/* 0x90 - 0x9F */
|
||||
O, O, O, O, O, O, O, O,
|
||||
O, O, X, O, O, O, O, O,
|
||||
@@ -110,13 +133,15 @@ static unsigned char insn_decode[256] = {
|
||||
X, X, X, X, X, X, X, X,
|
||||
/* 0xE0 - 0xEF */
|
||||
X, X, X, X, X, X, X, X,
|
||||
X, O|4, X, O|1, X, X, X, X,
|
||||
X, O|4, X, O|1|JMP, X, X, X, X,
|
||||
/* 0xF0 - 0xFF */
|
||||
P, X, P, P, O, O, O|M|1, O|M|4,
|
||||
O, O, O, O, O, O, O|M, O|M
|
||||
O, O, O, O, O, O, O|M, X
|
||||
};
|
||||
|
||||
static unsigned int get_insn_len(unsigned char *insn, unsigned char *p_opcode)
|
||||
static unsigned int get_insn_len(unsigned char *insn,
|
||||
unsigned char *p_opcode,
|
||||
unsigned char *p_decode)
|
||||
{
|
||||
unsigned char b, d, *pb, mod, rm;
|
||||
|
||||
@@ -130,10 +155,14 @@ static unsigned int get_insn_len(unsigned char *insn, unsigned char *p_opcode)
|
||||
}
|
||||
|
||||
*p_opcode = b;
|
||||
*p_decode = d;
|
||||
|
||||
/* 2. Ensure we have a valid opcode byte. */
|
||||
if ( !(d & OPCODE_BYTE) )
|
||||
{
|
||||
printk(KERN_ALERT " *** %02x %02x %02x\n", pb[0], pb[1], pb[2]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 3. Process Mod/RM if there is one. */
|
||||
if ( d & HAS_MODRM )
|
||||
@@ -175,13 +204,10 @@ static unsigned char handleable_code[32] = {
|
||||
asmlinkage void do_fixup_4gb_segment(struct pt_regs *regs, long error_code)
|
||||
{
|
||||
static unsigned int fixup_idx = 0;
|
||||
int relbyte_idx = -1, relword_idx = -1, save_indirect_reg;
|
||||
unsigned int fi;
|
||||
int save_indirect_reg, hash, rel_idx;
|
||||
unsigned int insn_len = (unsigned int)error_code, new_insn_len;
|
||||
unsigned char b[20], modrm, mod, reg, rm, patch[5], opcode;
|
||||
unsigned char *fixup_buf =
|
||||
(unsigned char *)fix_to_virt(FIX_4GB_SEGMENT_FIXUP_RW);
|
||||
unsigned long fixup_buf_user =
|
||||
fix_to_virt(FIX_4GB_SEGMENT_FIXUP_RO);
|
||||
unsigned char b[20], modrm, mod, reg, rm, patch[PATCH_LEN], opcode, decode;
|
||||
unsigned long eip = regs->eip - insn_len;
|
||||
struct fixup_entry *fe;
|
||||
pte_t *pte;
|
||||
@@ -198,28 +224,50 @@ asmlinkage void do_fixup_4gb_segment(struct pt_regs *regs, long error_code)
|
||||
|
||||
if ( unlikely(eip >= (PAGE_OFFSET-32)) )
|
||||
{
|
||||
if ( (eip < fixup_buf_user) || (eip >= (fixup_buf_user+PAGE_SIZE-32)) )
|
||||
{
|
||||
DPRINTK("User executing out of kernel space?!");
|
||||
return;
|
||||
}
|
||||
/* We know it's safe to directly copy teh bytes into our buffer. */
|
||||
memcpy(b, (void *)eip, sizeof(b));
|
||||
}
|
||||
else if ( unlikely(copy_from_user(b, (void *)eip, sizeof(b)) != 0) )
|
||||
{
|
||||
DPRINTK("Could not read instruction bytes from user space.");
|
||||
DPRINTK("User executing out of kernel space?!");
|
||||
return;
|
||||
}
|
||||
|
||||
if ( unlikely(((eip ^ (eip+5)) & PAGE_MASK) != 0) )
|
||||
|
||||
if ( unlikely(((eip ^ (eip+PATCH_LEN)) & PAGE_MASK) != 0) )
|
||||
{
|
||||
DPRINTK("Patch instruction would straddle a page boundary.");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the page to be patched is part of a read-only VMA. This
|
||||
* means that our patch will never erroneously get flushed to disc.
|
||||
*/
|
||||
if ( eip > (FIXUP_BUF_USER + FIXUP_BUF_SIZE) ) /* don't check fixup area */
|
||||
{
|
||||
/* [SMP] Need to the mmap_sem semaphore. */
|
||||
struct vm_area_struct *vma = find_vma(current->mm, eip);
|
||||
if ( (vma == NULL) || (vma->vm_flags & VM_MAYSHARE) )
|
||||
{
|
||||
DPRINTK("Cannot patch a shareable VMA.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( unlikely(copy_from_user(b, (void *)eip, sizeof(b)) != 0) )
|
||||
{
|
||||
DPRINTK("Could not read instruction bytes from user space.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Already created a fixup for this address and code sequence? */
|
||||
hash = FIXUP_HASH(b);
|
||||
for ( fe = fixup_hash[hash];
|
||||
fe != NULL; fe = fe->next )
|
||||
{
|
||||
if ( eip != fe->patch_addr )
|
||||
continue; /* XXX */
|
||||
if ( memcmp(fe->patched_code, b, fe->patched_code_len) == 0 )
|
||||
goto do_the_patch;
|
||||
}
|
||||
|
||||
/* Guaranteed enough room to patch? */
|
||||
if ( unlikely(fixup_idx > (PAGE_SIZE-32)) )
|
||||
if ( unlikely((fi = fixup_idx) > (FIXUP_BUF_SIZE-32)) )
|
||||
{
|
||||
static int printed = 0;
|
||||
if ( !printed )
|
||||
@@ -268,40 +316,77 @@ asmlinkage void do_fixup_4gb_segment(struct pt_regs *regs, long error_code)
|
||||
return;
|
||||
}
|
||||
|
||||
while ( insn_len < 5 )
|
||||
/* Indirect jump pointer. */
|
||||
*(u32 *)&fixup_buf[fi] = FIXUP_BUF_USER + fi + 4;
|
||||
fi += 4;
|
||||
|
||||
/* push <r32> */
|
||||
if ( save_indirect_reg )
|
||||
fixup_buf[fi++] = 0x50 + rm;
|
||||
|
||||
/* add %gs:0,<r32> */
|
||||
fixup_buf[fi++] = 0x65;
|
||||
fixup_buf[fi++] = 0x03;
|
||||
fixup_buf[fi++] = 0x05 | (rm << 3);
|
||||
*(unsigned long *)&fixup_buf[fi] = 0;
|
||||
fi += 4;
|
||||
|
||||
/* Relocate the faulting instruction, minus the GS override. */
|
||||
memcpy(&fixup_buf[fi], &b[1], error_code - 1);
|
||||
fi += error_code - 1;
|
||||
|
||||
/* pop <r32> */
|
||||
if ( save_indirect_reg )
|
||||
fixup_buf[fi++] = 0x58 + rm;
|
||||
|
||||
while ( insn_len < PATCH_LEN )
|
||||
{
|
||||
/* Bail if can't decode the following instruction. */
|
||||
if ( unlikely((new_insn_len =
|
||||
get_insn_len(&b[insn_len], &opcode)) == 0) )
|
||||
get_insn_len(&b[insn_len], &opcode, &decode)) == 0) )
|
||||
{
|
||||
DPRINTK("Could not decode following instruction.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* We track one 8-bit relative offset for patching later. */
|
||||
if ( ((opcode >= 0x70) && (opcode <= 0x7f)) || (opcode == 0xeb) )
|
||||
if ( (decode & CODE_MASK) == JMP )
|
||||
{
|
||||
if ( relbyte_idx != -1 )
|
||||
{
|
||||
DPRINTK("Multiple relative offsets in patch seq!");
|
||||
return;
|
||||
}
|
||||
relbyte_idx = insn_len;
|
||||
while ( b[relbyte_idx] != opcode )
|
||||
relbyte_idx++;
|
||||
relbyte_idx++;
|
||||
rel_idx = insn_len;
|
||||
while ( (fixup_buf[fi++] = b[rel_idx++]) != opcode )
|
||||
continue;
|
||||
|
||||
/* Patch the 8-bit relative offset. */
|
||||
int idx = fe->fixup_idx + relbyte_idx + 6 + 4/**/;
|
||||
if ( save_indirect_reg )
|
||||
idx += 2;
|
||||
fixup_buf[idx] = fi - (idx + 1);
|
||||
|
||||
/* jmp <rel32> */
|
||||
fixup_buf[fi++] = 0xe9;
|
||||
fi += 4;
|
||||
*(unsigned long *)&fixup_buf[fi-4] =
|
||||
(eip + relbyte_idx + 1 + (long)(char)b[relbyte_idx]) -
|
||||
(FIXUP_BUF_USER + fi);
|
||||
}
|
||||
else if ( opcode == 0xe9 )
|
||||
{
|
||||
if ( relword_idx != -1 )
|
||||
{
|
||||
DPRINTK("Multiple relative offsets in patch seq!");
|
||||
return;
|
||||
}
|
||||
relword_idx = insn_len;
|
||||
while ( b[relword_idx] != opcode )
|
||||
relword_idx++;
|
||||
relword_idx++;
|
||||
rel_idx = insn_len;
|
||||
while ( (fixup_buf[fi++] = b[rel_idx++]) != opcode )
|
||||
continue;
|
||||
|
||||
/* Patch the 32-bit relative offset. */
|
||||
int idx = fe->fixup_idx + relword_idx + 6 + 4/**/;
|
||||
if ( save_indirect_reg )
|
||||
idx += 2;
|
||||
*(unsigned long *)&fixup_buf[idx] +=
|
||||
(eip + relword_idx) - (FIXUP_BUF_USER + idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Relocate the instruction verbatim. */
|
||||
memcpy(&fixup_buf[fi], &b[insn_len], new_insn_len);
|
||||
fi += new_insn_len;
|
||||
}
|
||||
|
||||
if ( (insn_len += new_insn_len) > 20 )
|
||||
@@ -311,7 +396,7 @@ asmlinkage void do_fixup_4gb_segment(struct pt_regs *regs, long error_code)
|
||||
}
|
||||
|
||||
/* The instructions together must be no smaller than 'jmp <disp32>'. */
|
||||
if ( insn_len >= 5 )
|
||||
if ( insn_len >= PATCH_LEN )
|
||||
break;
|
||||
|
||||
/* Can't have a RET in the middle of a patch sequence. */
|
||||
@@ -322,120 +407,70 @@ asmlinkage void do_fixup_4gb_segment(struct pt_regs *regs, long error_code)
|
||||
}
|
||||
}
|
||||
|
||||
/* Already created a fixup for this address and code sequence? */
|
||||
for ( fe = fixup_hash[FIXUP_HASH(eip)];
|
||||
fe != NULL; fe = fe->next )
|
||||
{
|
||||
if ( (fe->patch_addr == eip) &&
|
||||
(fe->patched_code_len == insn_len) &&
|
||||
(memcmp(fe->patched_code, b, insn_len) == 0) )
|
||||
goto do_the_patch;
|
||||
}
|
||||
|
||||
/* No existing patch -- create an entry for one. */
|
||||
/* Create an entry for a new fixup patch. */
|
||||
fe = kmalloc(sizeof(struct fixup_entry), GFP_KERNEL);
|
||||
if ( unlikely(fe == NULL) )
|
||||
{
|
||||
DPRINTK("Not enough memory to allocate a fixup_entry.");
|
||||
return;
|
||||
}
|
||||
fe->patch_addr = eip;
|
||||
fe->patch_addr = eip; /* XXX */
|
||||
fe->patched_code_len = insn_len;
|
||||
memcpy(fe->patched_code, b, insn_len);
|
||||
fe->fixup_idx = fixup_idx;
|
||||
fe->next = fixup_hash[FIXUP_HASH(eip)];
|
||||
fixup_hash[FIXUP_HASH(eip)] = fe;
|
||||
|
||||
/* push <r32> */
|
||||
if ( save_indirect_reg )
|
||||
fixup_buf[fixup_idx++] = 0x50 + rm;
|
||||
fe->return_idx =
|
||||
fixup_idx + error_code + 6 + 4/**/ + (save_indirect_reg ? 2 : 0);
|
||||
fe->next = fixup_hash[hash];
|
||||
fixup_hash[hash] = fe;
|
||||
|
||||
/* add %gs:0,<r32> */
|
||||
fixup_buf[fixup_idx++] = 0x65;
|
||||
fixup_buf[fixup_idx++] = 0x03;
|
||||
fixup_buf[fixup_idx++] = 0x05 | (rm << 3);
|
||||
*(unsigned long *)&fixup_buf[fixup_idx] = 0;
|
||||
fixup_idx += 4;
|
||||
|
||||
/* First relocated instruction, minus the GS override. */
|
||||
memcpy(&fixup_buf[fixup_idx], &b[1], error_code - 1);
|
||||
fixup_idx += error_code - 1;
|
||||
|
||||
/* pop <r32> */
|
||||
if ( save_indirect_reg )
|
||||
fixup_buf[fixup_idx++] = 0x58 + rm;
|
||||
|
||||
if ( insn_len != error_code )
|
||||
{
|
||||
/* Relocated instructions. */
|
||||
memcpy(&fixup_buf[fixup_idx], &b[error_code], insn_len - error_code);
|
||||
fixup_idx += insn_len - error_code;
|
||||
}
|
||||
|
||||
/* jmp <rel32> */
|
||||
fixup_buf[fixup_idx++] = 0xe9;
|
||||
fixup_idx += 4;
|
||||
*(unsigned long *)&fixup_buf[fixup_idx-4] =
|
||||
(eip + insn_len) - (fixup_buf_user + fixup_idx);
|
||||
fixup_buf[fi++] = 0xe9;
|
||||
fi += 4;
|
||||
*(unsigned long *)&fixup_buf[fi-4] =
|
||||
(eip + insn_len) - (FIXUP_BUF_USER + fi);
|
||||
|
||||
if ( relbyte_idx != -1 )
|
||||
/* Commit the patch. */
|
||||
fixup_idx = fi;
|
||||
|
||||
#if 0
|
||||
if ( fe->fixup_idx == 4122 )
|
||||
{
|
||||
/* Patch the 8-bit relative offset. */
|
||||
int idx = fe->fixup_idx + relbyte_idx + 6;
|
||||
if ( save_indirect_reg )
|
||||
idx += 2;
|
||||
fixup_buf[idx] = fixup_idx - (idx + 1);
|
||||
|
||||
/* jmp <rel32> */
|
||||
fixup_buf[fixup_idx++] = 0xe9;
|
||||
fixup_idx += 4;
|
||||
*(unsigned long *)&fixup_buf[fixup_idx-4] =
|
||||
(eip + relbyte_idx + 1 + (long)(char)b[relbyte_idx]) -
|
||||
(fixup_buf_user + fixup_idx);
|
||||
}
|
||||
else if ( relword_idx != -1 )
|
||||
{
|
||||
/* Patch the 32-bit relative offset by subtracting the code disp. */
|
||||
int idx = fe->fixup_idx + relword_idx + 6;
|
||||
if ( save_indirect_reg )
|
||||
idx += 2;
|
||||
*(unsigned long *)&fixup_buf[idx] +=
|
||||
(eip + relword_idx) - (fixup_buf_user + idx);
|
||||
int iii;
|
||||
printk(KERN_ALERT "EIP == %08lx; USER_EIP == %08lx\n",
|
||||
eip, FIXUP_BUF_USER + fe->fixup_idx);
|
||||
printk(KERN_ALERT " .byte ");
|
||||
for ( iii = 0; iii < insn_len; iii++ )
|
||||
printk("0x%02x,", b[iii]);
|
||||
printk("\n");
|
||||
printk(KERN_ALERT " .byte ");
|
||||
for ( iii = fe->fixup_idx; iii < fi; iii++ )
|
||||
printk("0x%02x,", fixup_buf[iii]);
|
||||
printk("\n");
|
||||
printk(KERN_ALERT " .byte ");
|
||||
for ( iii = fe->fixup_idx; iii < fi; iii++ )
|
||||
printk("0x%02x,", ((char *)FIXUP_BUF_USER)[iii]);
|
||||
printk("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
do_the_patch:
|
||||
/* Create the patching instruction in a temporary buffer. */
|
||||
patch[0] = 0xe9;
|
||||
*(unsigned long *)&patch[1] =
|
||||
(fixup_buf_user + fe->fixup_idx) - (eip + 5);
|
||||
|
||||
/*
|
||||
* Check that the page to be patched is part of a read-only VMA. This
|
||||
* means that our patch will never erroneously get flushed to disc.
|
||||
*/
|
||||
if ( eip < PAGE_OFFSET ) /* don't need to check the fixmap area */
|
||||
{
|
||||
/* [SMP] Need to the mmap_sem semaphore. */
|
||||
struct vm_area_struct *vma = find_vma(current->mm, eip);
|
||||
if ( (vma == NULL) || (vma->vm_flags & VM_MAYSHARE) )
|
||||
{
|
||||
DPRINTK("Cannot patch a shareable VMA.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
patch[0] = 0x67;
|
||||
patch[1] = 0xff;
|
||||
patch[2] = 0x26; /* call <r/m16> */
|
||||
*(u16 *)&patch[3] = FIXUP_BUF_USER + fe->fixup_idx;
|
||||
|
||||
/* [SMP] Need to pause other threads while patching. */
|
||||
pgd = pgd_offset(current->mm, eip);
|
||||
pmd = pmd_offset(pgd, eip);
|
||||
pte = pte_offset_kernel(pmd, eip);
|
||||
veip = kmap(pte_page(*pte));
|
||||
memcpy((char *)veip + (eip & ~PAGE_MASK), patch, 5);
|
||||
memcpy((char *)veip + (eip & ~PAGE_MASK), patch, PATCH_LEN);
|
||||
kunmap(pte_page(*pte));
|
||||
|
||||
/* Success! Return to user land to execute 2nd insn of the pair. */
|
||||
regs->eip = fixup_buf_user + fe->fixup_idx + error_code + 6;
|
||||
if ( save_indirect_reg )
|
||||
regs->eip += 2;
|
||||
regs->eip = FIXUP_BUF_USER + fe->return_idx;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -443,7 +478,9 @@ static int nosegfixup = 0;
|
||||
|
||||
static int __init fixup_init(void)
|
||||
{
|
||||
unsigned long page;
|
||||
struct vm_struct vma;
|
||||
struct page *_pages[1<<FIXUP_BUF_ORDER], **pages=_pages;
|
||||
int i;
|
||||
|
||||
if ( nosegfixup )
|
||||
return 0;
|
||||
@@ -451,9 +488,14 @@ static int __init fixup_init(void)
|
||||
HYPERVISOR_vm_assist(VMASST_CMD_enable,
|
||||
VMASST_TYPE_4gb_segments_notify);
|
||||
|
||||
page = get_zeroed_page(GFP_ATOMIC);
|
||||
__set_fixmap(FIX_4GB_SEGMENT_FIXUP_RO, __pa(page), PAGE_READONLY);
|
||||
__set_fixmap(FIX_4GB_SEGMENT_FIXUP_RW, __pa(page), PAGE_KERNEL);
|
||||
fixup_buf = (char *)__get_free_pages(GFP_ATOMIC, FIXUP_BUF_ORDER);
|
||||
for ( i = 0; i < (1<<FIXUP_BUF_ORDER); i++ )
|
||||
_pages[i] = virt_to_page(fixup_buf) + i;
|
||||
|
||||
vma.addr = (void *)FIXUP_BUF_USER;
|
||||
vma.size = FIXUP_BUF_SIZE + PAGE_SIZE; /* fucking stupid interface */
|
||||
if ( map_vm_area(&vma, PAGE_READONLY, &pages) != 0 )
|
||||
BUG();
|
||||
|
||||
memset(fixup_hash, 0, sizeof(fixup_hash));
|
||||
|
||||
|
||||
@@ -44,8 +44,6 @@
|
||||
enum fixed_addresses {
|
||||
FIX_HOLE,
|
||||
FIX_VSYSCALL,
|
||||
FIX_4GB_SEGMENT_FIXUP_RO,
|
||||
FIX_4GB_SEGMENT_FIXUP_RW,
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */
|
||||
#endif
|
||||
@@ -128,8 +126,8 @@ extern void __set_fixmap_ma (enum fixed_addresses idx,
|
||||
* This is the range that is readable by user mode, and things
|
||||
* acting like user mode such as get_user_pages.
|
||||
*/
|
||||
#define FIXADDR_USER_START (__fix_to_virt(FIX_4GB_SEGMENT_FIXUP_RO))
|
||||
#define FIXADDR_USER_END (FIXADDR_USER_START + (2*PAGE_SIZE))
|
||||
#define FIXADDR_USER_START (__fix_to_virt(FIX_VSYSCALL))
|
||||
#define FIXADDR_USER_END (FIXADDR_USER_START + PAGE_SIZE)
|
||||
|
||||
|
||||
extern void __this_fixmap_does_not_exist(void);
|
||||
|
||||
@@ -64,16 +64,17 @@ void paging_init(void);
|
||||
#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
|
||||
#define PGDIR_MASK (~(PGDIR_SIZE-1))
|
||||
|
||||
#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
|
||||
#define FIRST_USER_PGD_NR 0
|
||||
#define FIRST_USER_PGD_NR 1
|
||||
#define USER_PTRS_PER_PGD ((TASK_SIZE/PGDIR_SIZE) - FIRST_USER_PGD_NR)
|
||||
|
||||
#if 0 /* XEN */
|
||||
#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
|
||||
#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
|
||||
|
||||
#define TWOLEVEL_PGDIR_SHIFT 22
|
||||
#define BOOT_USER_PGD_PTRS (__PAGE_OFFSET >> TWOLEVEL_PGDIR_SHIFT)
|
||||
#define BOOT_KERNEL_PGD_PTRS (1024-BOOT_USER_PGD_PTRS)
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
/* Just any arbitrary offset to the start of the vmalloc VM area: the
|
||||
|
||||