Re: [Patch v2 3/3] s390/kprobes: add support for pc-relative long displacement instructions

2013-08-25 Thread Masami Hiramatsu
(2013/08/23 20:04), Heiko Carstens wrote:
> With the general-instruction extension facility (z10) a couple of
> instructions with a pc-relative long displacement were introduced.
> The kprobes support for these instructions however was never implemented.
> 
> In result, if anybody ever put a probe on any of these instructions the
> result would have been random behaviour after the instruction got executed
> within the insn slot.
> 
> So lets add the missing handling for these instructions. Since all of the
> new instructions have 32 bit signed displacement the easiest solution is
> to allocate an insn slot that is within the same 2GB area like the original
> instruction and patch the displacement field.
> 

At least generic kprobes flow looks good for me.

Reviewed-by: Masami Hiramatsu 

> Signed-off-by: Heiko Carstens 
> ---
>  arch/s390/include/asm/kprobes.h |4 +-
>  arch/s390/kernel/kprobes.c  |  144 
> +--
>  2 files changed, 140 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/s390/include/asm/kprobes.h b/arch/s390/include/asm/kprobes.h
> index dcf6948..4176dfe 100644
> --- a/arch/s390/include/asm/kprobes.h
> +++ b/arch/s390/include/asm/kprobes.h
> @@ -31,6 +31,8 @@
>  #include 
>  #include 
>  
> +#define __ARCH_WANT_KPROBES_INSN_SLOT
> +
>  struct pt_regs;
>  struct kprobe;
>  
> @@ -57,7 +59,7 @@ typedef u16 kprobe_opcode_t;
>  /* Architecture specific copy of original instruction */
>  struct arch_specific_insn {
>   /* copy of original instruction */
> - kprobe_opcode_t insn[MAX_INSN_SIZE];
> + kprobe_opcode_t *insn;
>  };
>  
>  struct prev_kprobe {
> diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
> index 3388b2b..cb7ac9e 100644
> --- a/arch/s390/kernel/kprobes.c
> +++ b/arch/s390/kernel/kprobes.c
> @@ -37,6 +37,26 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
>  
>  struct kretprobe_blackpoint kretprobe_blacklist[] = { };
>  
> +DEFINE_INSN_CACHE_OPS(dmainsn);
> +
> +static void *alloc_dmainsn_page(void)
> +{
> + return (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
> +}
> +
> +static void free_dmainsn_page(void *page)
> +{
> + free_page((unsigned long)page);
> +}
> +
> +struct kprobe_insn_cache kprobe_dmainsn_slots = {
> + .mutex = __MUTEX_INITIALIZER(kprobe_dmainsn_slots.mutex),
> + .alloc = alloc_dmainsn_page,
> + .free = free_dmainsn_page,
> + .pages = LIST_HEAD_INIT(kprobe_dmainsn_slots.pages),
> + .insn_size = MAX_INSN_SIZE,
> +};
> +
>  static int __kprobes is_prohibited_opcode(kprobe_opcode_t *insn)
>  {
>   switch (insn[0] >> 8) {
> @@ -100,9 +120,8 @@ static int __kprobes get_fixup_type(kprobe_opcode_t *insn)
>   fixup |= FIXUP_RETURN_REGISTER;
>   break;
>   case 0xc0:
> - if ((insn[0] & 0x0f) == 0x00 || /* larl  */
> - (insn[0] & 0x0f) == 0x05)   /* brasl */
> - fixup |= FIXUP_RETURN_REGISTER;
> + if ((insn[0] & 0x0f) == 0x05)   /* brasl */
> + fixup |= FIXUP_RETURN_REGISTER;
>   break;
>   case 0xeb:
>   if ((insn[2] & 0xff) == 0x44 || /* bxhg  */
> @@ -117,18 +136,128 @@ static int __kprobes get_fixup_type(kprobe_opcode_t 
> *insn)
>   return fixup;
>  }
>  
> +static int __kprobes is_insn_relative_long(kprobe_opcode_t *insn)
> +{
> + /* Check if we have a RIL-b or RIL-c format instruction which
> +  * we need to modify in order to avoid instruction emulation. */
> + switch (insn[0] >> 8) {
> + case 0xc0:
> + if ((insn[0] & 0x0f) == 0x00) /* larl */
> + return true;
> + break;
> + case 0xc4:
> + switch (insn[0] & 0x0f) {
> + case 0x02: /* llhrl  */
> + case 0x04: /* lghrl  */
> + case 0x05: /* lhrl   */
> + case 0x06: /* llghrl */
> + case 0x07: /* sthrl  */
> + case 0x08: /* lgrl   */
> + case 0x0b: /* stgrl  */
> + case 0x0c: /* lgfrl  */
> + case 0x0d: /* lrl*/
> + case 0x0e: /* llgfrl */
> + case 0x0f: /* strl   */
> + return true;
> + }
> + break;
> + case 0xc6:
> + switch (insn[0] & 0x0f) {
> + case 0x00: /* exrl   */
> + case 0x02: /* pfdrl  */
> + case 0x04: /* cghrl  */
> + case 0x05: /* chrl   */
> + case 0x06: /* clghrl */
> + case 0x07: /* clhrl  */
> + case 0x08: /* cgrl   */
> + case 0x0a: /* clgrl  */
> + case 0x0c: /* cgfrl  */
> + case 0x0d: /* crl*/
> + case 0x0e: /* clgfrl */
> + case 0x0f: /* clrl   */
> + return true;
> + }
> + break;
> + }
> + return false;
> +}
> +
> +static void __kprobes copy_instruction(struct kprobe *p)
> +{
> +

Re: [Patch v2 3/3] s390/kprobes: add support for pc-relative long displacement instructions

2013-08-25 Thread Masami Hiramatsu
(2013/08/23 20:04), Heiko Carstens wrote:
 With the general-instruction extension facility (z10) a couple of
 instructions with a pc-relative long displacement were introduced.
 The kprobes support for these instructions however was never implemented.
 
 In result, if anybody ever put a probe on any of these instructions the
 result would have been random behaviour after the instruction got executed
 within the insn slot.
 
 So lets add the missing handling for these instructions. Since all of the
 new instructions have 32 bit signed displacement the easiest solution is
 to allocate an insn slot that is within the same 2GB area like the original
 instruction and patch the displacement field.
 

At least generic kprobes flow looks good for me.

Reviewed-by: Masami Hiramatsu masami.hiramatsu...@hitachi.com

 Signed-off-by: Heiko Carstens heiko.carst...@de.ibm.com
 ---
  arch/s390/include/asm/kprobes.h |4 +-
  arch/s390/kernel/kprobes.c  |  144 
 +--
  2 files changed, 140 insertions(+), 8 deletions(-)
 
 diff --git a/arch/s390/include/asm/kprobes.h b/arch/s390/include/asm/kprobes.h
 index dcf6948..4176dfe 100644
 --- a/arch/s390/include/asm/kprobes.h
 +++ b/arch/s390/include/asm/kprobes.h
 @@ -31,6 +31,8 @@
  #include linux/ptrace.h
  #include linux/percpu.h
  
 +#define __ARCH_WANT_KPROBES_INSN_SLOT
 +
  struct pt_regs;
  struct kprobe;
  
 @@ -57,7 +59,7 @@ typedef u16 kprobe_opcode_t;
  /* Architecture specific copy of original instruction */
  struct arch_specific_insn {
   /* copy of original instruction */
 - kprobe_opcode_t insn[MAX_INSN_SIZE];
 + kprobe_opcode_t *insn;
  };
  
  struct prev_kprobe {
 diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
 index 3388b2b..cb7ac9e 100644
 --- a/arch/s390/kernel/kprobes.c
 +++ b/arch/s390/kernel/kprobes.c
 @@ -37,6 +37,26 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
  
  struct kretprobe_blackpoint kretprobe_blacklist[] = { };
  
 +DEFINE_INSN_CACHE_OPS(dmainsn);
 +
 +static void *alloc_dmainsn_page(void)
 +{
 + return (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
 +}
 +
 +static void free_dmainsn_page(void *page)
 +{
 + free_page((unsigned long)page);
 +}
 +
 +struct kprobe_insn_cache kprobe_dmainsn_slots = {
 + .mutex = __MUTEX_INITIALIZER(kprobe_dmainsn_slots.mutex),
 + .alloc = alloc_dmainsn_page,
 + .free = free_dmainsn_page,
 + .pages = LIST_HEAD_INIT(kprobe_dmainsn_slots.pages),
 + .insn_size = MAX_INSN_SIZE,
 +};
 +
  static int __kprobes is_prohibited_opcode(kprobe_opcode_t *insn)
  {
   switch (insn[0]  8) {
 @@ -100,9 +120,8 @@ static int __kprobes get_fixup_type(kprobe_opcode_t *insn)
   fixup |= FIXUP_RETURN_REGISTER;
   break;
   case 0xc0:
 - if ((insn[0]  0x0f) == 0x00 || /* larl  */
 - (insn[0]  0x0f) == 0x05)   /* brasl */
 - fixup |= FIXUP_RETURN_REGISTER;
 + if ((insn[0]  0x0f) == 0x05)   /* brasl */
 + fixup |= FIXUP_RETURN_REGISTER;
   break;
   case 0xeb:
   if ((insn[2]  0xff) == 0x44 || /* bxhg  */
 @@ -117,18 +136,128 @@ static int __kprobes get_fixup_type(kprobe_opcode_t 
 *insn)
   return fixup;
  }
  
 +static int __kprobes is_insn_relative_long(kprobe_opcode_t *insn)
 +{
 + /* Check if we have a RIL-b or RIL-c format instruction which
 +  * we need to modify in order to avoid instruction emulation. */
 + switch (insn[0]  8) {
 + case 0xc0:
 + if ((insn[0]  0x0f) == 0x00) /* larl */
 + return true;
 + break;
 + case 0xc4:
 + switch (insn[0]  0x0f) {
 + case 0x02: /* llhrl  */
 + case 0x04: /* lghrl  */
 + case 0x05: /* lhrl   */
 + case 0x06: /* llghrl */
 + case 0x07: /* sthrl  */
 + case 0x08: /* lgrl   */
 + case 0x0b: /* stgrl  */
 + case 0x0c: /* lgfrl  */
 + case 0x0d: /* lrl*/
 + case 0x0e: /* llgfrl */
 + case 0x0f: /* strl   */
 + return true;
 + }
 + break;
 + case 0xc6:
 + switch (insn[0]  0x0f) {
 + case 0x00: /* exrl   */
 + case 0x02: /* pfdrl  */
 + case 0x04: /* cghrl  */
 + case 0x05: /* chrl   */
 + case 0x06: /* clghrl */
 + case 0x07: /* clhrl  */
 + case 0x08: /* cgrl   */
 + case 0x0a: /* clgrl  */
 + case 0x0c: /* cgfrl  */
 + case 0x0d: /* crl*/
 + case 0x0e: /* clgfrl */
 + case 0x0f: /* clrl   */
 + return true;
 + }
 + break;
 + }
 + return false;
 +}
 +
 +static void __kprobes copy_instruction(struct kprobe *p)
 +{
 + s64 disp, new_disp;
 + u64 addr, new_addr;
 +
 + 

[Patch v2 3/3] s390/kprobes: add support for pc-relative long displacement instructions

2013-08-23 Thread Heiko Carstens
With the general-instruction extension facility (z10) a couple of
instructions with a pc-relative long displacement were introduced.
The kprobes support for these instructions however was never implemented.

In result, if anybody ever put a probe on any of these instructions the
result would have been random behaviour after the instruction got executed
within the insn slot.

So lets add the missing handling for these instructions. Since all of the
new instructions have 32 bit signed displacement the easiest solution is
to allocate an insn slot that is within the same 2GB area like the original
instruction and patch the displacement field.

Signed-off-by: Heiko Carstens 
---
 arch/s390/include/asm/kprobes.h |4 +-
 arch/s390/kernel/kprobes.c  |  144 +--
 2 files changed, 140 insertions(+), 8 deletions(-)

diff --git a/arch/s390/include/asm/kprobes.h b/arch/s390/include/asm/kprobes.h
index dcf6948..4176dfe 100644
--- a/arch/s390/include/asm/kprobes.h
+++ b/arch/s390/include/asm/kprobes.h
@@ -31,6 +31,8 @@
 #include 
 #include 
 
+#define __ARCH_WANT_KPROBES_INSN_SLOT
+
 struct pt_regs;
 struct kprobe;
 
@@ -57,7 +59,7 @@ typedef u16 kprobe_opcode_t;
 /* Architecture specific copy of original instruction */
 struct arch_specific_insn {
/* copy of original instruction */
-   kprobe_opcode_t insn[MAX_INSN_SIZE];
+   kprobe_opcode_t *insn;
 };
 
 struct prev_kprobe {
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
index 3388b2b..cb7ac9e 100644
--- a/arch/s390/kernel/kprobes.c
+++ b/arch/s390/kernel/kprobes.c
@@ -37,6 +37,26 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
 
 struct kretprobe_blackpoint kretprobe_blacklist[] = { };
 
+DEFINE_INSN_CACHE_OPS(dmainsn);
+
+static void *alloc_dmainsn_page(void)
+{
+   return (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
+}
+
+static void free_dmainsn_page(void *page)
+{
+   free_page((unsigned long)page);
+}
+
+struct kprobe_insn_cache kprobe_dmainsn_slots = {
+   .mutex = __MUTEX_INITIALIZER(kprobe_dmainsn_slots.mutex),
+   .alloc = alloc_dmainsn_page,
+   .free = free_dmainsn_page,
+   .pages = LIST_HEAD_INIT(kprobe_dmainsn_slots.pages),
+   .insn_size = MAX_INSN_SIZE,
+};
+
 static int __kprobes is_prohibited_opcode(kprobe_opcode_t *insn)
 {
switch (insn[0] >> 8) {
@@ -100,9 +120,8 @@ static int __kprobes get_fixup_type(kprobe_opcode_t *insn)
fixup |= FIXUP_RETURN_REGISTER;
break;
case 0xc0:
-   if ((insn[0] & 0x0f) == 0x00 || /* larl  */
-   (insn[0] & 0x0f) == 0x05)   /* brasl */
-   fixup |= FIXUP_RETURN_REGISTER;
+   if ((insn[0] & 0x0f) == 0x05)   /* brasl */
+   fixup |= FIXUP_RETURN_REGISTER;
break;
case 0xeb:
if ((insn[2] & 0xff) == 0x44 || /* bxhg  */
@@ -117,18 +136,128 @@ static int __kprobes get_fixup_type(kprobe_opcode_t 
*insn)
return fixup;
 }
 
+static int __kprobes is_insn_relative_long(kprobe_opcode_t *insn)
+{
+   /* Check if we have a RIL-b or RIL-c format instruction which
+* we need to modify in order to avoid instruction emulation. */
+   switch (insn[0] >> 8) {
+   case 0xc0:
+   if ((insn[0] & 0x0f) == 0x00) /* larl */
+   return true;
+   break;
+   case 0xc4:
+   switch (insn[0] & 0x0f) {
+   case 0x02: /* llhrl  */
+   case 0x04: /* lghrl  */
+   case 0x05: /* lhrl   */
+   case 0x06: /* llghrl */
+   case 0x07: /* sthrl  */
+   case 0x08: /* lgrl   */
+   case 0x0b: /* stgrl  */
+   case 0x0c: /* lgfrl  */
+   case 0x0d: /* lrl*/
+   case 0x0e: /* llgfrl */
+   case 0x0f: /* strl   */
+   return true;
+   }
+   break;
+   case 0xc6:
+   switch (insn[0] & 0x0f) {
+   case 0x00: /* exrl   */
+   case 0x02: /* pfdrl  */
+   case 0x04: /* cghrl  */
+   case 0x05: /* chrl   */
+   case 0x06: /* clghrl */
+   case 0x07: /* clhrl  */
+   case 0x08: /* cgrl   */
+   case 0x0a: /* clgrl  */
+   case 0x0c: /* cgfrl  */
+   case 0x0d: /* crl*/
+   case 0x0e: /* clgfrl */
+   case 0x0f: /* clrl   */
+   return true;
+   }
+   break;
+   }
+   return false;
+}
+
+static void __kprobes copy_instruction(struct kprobe *p)
+{
+   s64 disp, new_disp;
+   u64 addr, new_addr;
+
+   memcpy(p->ainsn.insn, p->addr, ((p->opcode >> 14) + 3) & -2);
+   if (!is_insn_relative_long(p->ainsn.insn))
+   return;
+   /*
+* For pc-relative instructions in RIL-b or RIL-c format 

[Patch v2 3/3] s390/kprobes: add support for pc-relative long displacement instructions

2013-08-23 Thread Heiko Carstens
With the general-instruction extension facility (z10) a couple of
instructions with a pc-relative long displacement were introduced.
The kprobes support for these instructions however was never implemented.

In result, if anybody ever put a probe on any of these instructions the
result would have been random behaviour after the instruction got executed
within the insn slot.

So lets add the missing handling for these instructions. Since all of the
new instructions have 32 bit signed displacement the easiest solution is
to allocate an insn slot that is within the same 2GB area like the original
instruction and patch the displacement field.

Signed-off-by: Heiko Carstens heiko.carst...@de.ibm.com
---
 arch/s390/include/asm/kprobes.h |4 +-
 arch/s390/kernel/kprobes.c  |  144 +--
 2 files changed, 140 insertions(+), 8 deletions(-)

diff --git a/arch/s390/include/asm/kprobes.h b/arch/s390/include/asm/kprobes.h
index dcf6948..4176dfe 100644
--- a/arch/s390/include/asm/kprobes.h
+++ b/arch/s390/include/asm/kprobes.h
@@ -31,6 +31,8 @@
 #include linux/ptrace.h
 #include linux/percpu.h
 
+#define __ARCH_WANT_KPROBES_INSN_SLOT
+
 struct pt_regs;
 struct kprobe;
 
@@ -57,7 +59,7 @@ typedef u16 kprobe_opcode_t;
 /* Architecture specific copy of original instruction */
 struct arch_specific_insn {
/* copy of original instruction */
-   kprobe_opcode_t insn[MAX_INSN_SIZE];
+   kprobe_opcode_t *insn;
 };
 
 struct prev_kprobe {
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
index 3388b2b..cb7ac9e 100644
--- a/arch/s390/kernel/kprobes.c
+++ b/arch/s390/kernel/kprobes.c
@@ -37,6 +37,26 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
 
 struct kretprobe_blackpoint kretprobe_blacklist[] = { };
 
+DEFINE_INSN_CACHE_OPS(dmainsn);
+
+static void *alloc_dmainsn_page(void)
+{
+   return (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
+}
+
+static void free_dmainsn_page(void *page)
+{
+   free_page((unsigned long)page);
+}
+
+struct kprobe_insn_cache kprobe_dmainsn_slots = {
+   .mutex = __MUTEX_INITIALIZER(kprobe_dmainsn_slots.mutex),
+   .alloc = alloc_dmainsn_page,
+   .free = free_dmainsn_page,
+   .pages = LIST_HEAD_INIT(kprobe_dmainsn_slots.pages),
+   .insn_size = MAX_INSN_SIZE,
+};
+
 static int __kprobes is_prohibited_opcode(kprobe_opcode_t *insn)
 {
switch (insn[0]  8) {
@@ -100,9 +120,8 @@ static int __kprobes get_fixup_type(kprobe_opcode_t *insn)
fixup |= FIXUP_RETURN_REGISTER;
break;
case 0xc0:
-   if ((insn[0]  0x0f) == 0x00 || /* larl  */
-   (insn[0]  0x0f) == 0x05)   /* brasl */
-   fixup |= FIXUP_RETURN_REGISTER;
+   if ((insn[0]  0x0f) == 0x05)   /* brasl */
+   fixup |= FIXUP_RETURN_REGISTER;
break;
case 0xeb:
if ((insn[2]  0xff) == 0x44 || /* bxhg  */
@@ -117,18 +136,128 @@ static int __kprobes get_fixup_type(kprobe_opcode_t 
*insn)
return fixup;
 }
 
+static int __kprobes is_insn_relative_long(kprobe_opcode_t *insn)
+{
+   /* Check if we have a RIL-b or RIL-c format instruction which
+* we need to modify in order to avoid instruction emulation. */
+   switch (insn[0]  8) {
+   case 0xc0:
+   if ((insn[0]  0x0f) == 0x00) /* larl */
+   return true;
+   break;
+   case 0xc4:
+   switch (insn[0]  0x0f) {
+   case 0x02: /* llhrl  */
+   case 0x04: /* lghrl  */
+   case 0x05: /* lhrl   */
+   case 0x06: /* llghrl */
+   case 0x07: /* sthrl  */
+   case 0x08: /* lgrl   */
+   case 0x0b: /* stgrl  */
+   case 0x0c: /* lgfrl  */
+   case 0x0d: /* lrl*/
+   case 0x0e: /* llgfrl */
+   case 0x0f: /* strl   */
+   return true;
+   }
+   break;
+   case 0xc6:
+   switch (insn[0]  0x0f) {
+   case 0x00: /* exrl   */
+   case 0x02: /* pfdrl  */
+   case 0x04: /* cghrl  */
+   case 0x05: /* chrl   */
+   case 0x06: /* clghrl */
+   case 0x07: /* clhrl  */
+   case 0x08: /* cgrl   */
+   case 0x0a: /* clgrl  */
+   case 0x0c: /* cgfrl  */
+   case 0x0d: /* crl*/
+   case 0x0e: /* clgfrl */
+   case 0x0f: /* clrl   */
+   return true;
+   }
+   break;
+   }
+   return false;
+}
+
+static void __kprobes copy_instruction(struct kprobe *p)
+{
+   s64 disp, new_disp;
+   u64 addr, new_addr;
+
+   memcpy(p-ainsn.insn, p-addr, ((p-opcode  14) + 3)  -2);
+   if (!is_insn_relative_long(p-ainsn.insn))
+   return;
+   /*
+* For pc-relative