linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] kasan: also display registers for reports from HW exceptions
@ 2022-09-27  1:20 Peter Collingbourne
  2022-09-27 18:20 ` Andrey Konovalov
  0 siblings, 1 reply; 2+ messages in thread
From: Peter Collingbourne @ 2022-09-27  1:20 UTC (permalink / raw)
  To: Catalin Marinas, Vincenzo Frascino, Andrew Morton, Andrey Konovalov
  Cc: Peter Collingbourne, linux-arm-kernel, kasan-dev, linux-mm

It is sometimes useful to know the values of the registers when a KASAN
report is generated. We can do this easily for reports that resulted from
a hardware exception by passing the struct pt_regs from the exception into
the report function; do so, but only in HW tags mode because registers
may have been corrupted during the check in other modes.

Signed-off-by: Peter Collingbourne <pcc@google.com>
---
Applies to -next.

v2:
- only do this in HW tags mode
- move pr_err to caller

 arch/arm64/mm/fault.c |  2 +-
 include/linux/kasan.h | 10 ++++++++++
 mm/kasan/kasan.h      |  1 +
 mm/kasan/report.c     | 30 +++++++++++++++++++++++-------
 4 files changed, 35 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 5b391490e045..c4b91f5d8cc8 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -316,7 +316,7 @@ static void report_tag_fault(unsigned long addr, unsigned long esr,
 	 * find out access size.
 	 */
 	bool is_write = !!(esr & ESR_ELx_WNR);
-	kasan_report(addr, 0, is_write, regs->pc);
+	kasan_report_regs(addr, 0, is_write, regs);
 }
 #else
 /* Tag faults aren't enabled without CONFIG_KASAN_HW_TAGS. */
diff --git a/include/linux/kasan.h b/include/linux/kasan.h
index d811b3d7d2a1..381aea149353 100644
--- a/include/linux/kasan.h
+++ b/include/linux/kasan.h
@@ -353,6 +353,16 @@ static inline void *kasan_reset_tag(const void *addr)
 bool kasan_report(unsigned long addr, size_t size,
 		bool is_write, unsigned long ip);
 
+/**
+ * kasan_report_regs - print a report about a bad memory access detected by KASAN
+ * @addr: address of the bad access
+ * @size: size of the bad access
+ * @is_write: whether the bad access is a write or a read
+ * @regs: register values at the point of the bad memory access
+ */
+bool kasan_report_regs(unsigned long addr, size_t size, bool is_write,
+		       struct pt_regs *regs);
+
 #else /* CONFIG_KASAN_SW_TAGS || CONFIG_KASAN_HW_TAGS */
 
 static inline void *kasan_reset_tag(const void *addr)
diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h
index abbcc1b0eec5..39772c21a8ae 100644
--- a/mm/kasan/kasan.h
+++ b/mm/kasan/kasan.h
@@ -175,6 +175,7 @@ struct kasan_report_info {
 	size_t access_size;
 	bool is_write;
 	unsigned long ip;
+	struct pt_regs *regs;
 
 	/* Filled in by the common reporting code. */
 	void *first_bad_addr;
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index df3602062bfd..be8dd97940c7 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -24,6 +24,7 @@
 #include <linux/types.h>
 #include <linux/kasan.h>
 #include <linux/module.h>
+#include <linux/sched/debug.h>
 #include <linux/sched/task_stack.h>
 #include <linux/uaccess.h>
 #include <trace/events/error_report.h>
@@ -281,9 +282,6 @@ static void print_address_description(void *addr, u8 tag,
 {
 	struct page *page = addr_to_page(addr);
 
-	dump_stack_lvl(KERN_ERR);
-	pr_err("\n");
-
 	if (info->cache && info->object) {
 		describe_object(addr, info);
 		pr_err("\n");
@@ -391,11 +389,15 @@ static void print_report(struct kasan_report_info *info)
 		kasan_print_tags(tag, info->first_bad_addr);
 	pr_err("\n");
 
+	if (info->regs)
+		show_regs(info->regs);
+	else
+		dump_stack_lvl(KERN_ERR);
+
 	if (addr_has_metadata(addr)) {
+		pr_err("\n");
 		print_address_description(addr, tag, info);
 		print_memory_metadata(info->first_bad_addr);
-	} else {
-		dump_stack_lvl(KERN_ERR);
 	}
 }
 
@@ -467,8 +469,8 @@ void kasan_report_invalid_free(void *ptr, unsigned long ip, enum kasan_report_ty
  * user_access_save/restore(): kasan_report_invalid_free() cannot be called
  * from a UACCESS region, and kasan_report_async() is not used on x86.
  */
-bool kasan_report(unsigned long addr, size_t size, bool is_write,
-			unsigned long ip)
+static bool __kasan_report(unsigned long addr, size_t size, bool is_write,
+			unsigned long ip, struct pt_regs *regs)
 {
 	bool ret = true;
 	void *ptr = (void *)addr;
@@ -489,6 +491,7 @@ bool kasan_report(unsigned long addr, size_t size, bool is_write,
 	info.access_size = size;
 	info.is_write = is_write;
 	info.ip = ip;
+	info.regs = regs;
 
 	complete_report_info(&info);
 
@@ -502,6 +505,19 @@ bool kasan_report(unsigned long addr, size_t size, bool is_write,
 	return ret;
 }
 
+bool kasan_report(unsigned long addr, size_t size, bool is_write,
+			unsigned long ip)
+{
+	return __kasan_report(addr, size, is_write, ip, NULL);
+}
+
+bool kasan_report_regs(unsigned long addr, size_t size, bool is_write,
+		       struct pt_regs *regs)
+{
+	return __kasan_report(addr, size, is_write, instruction_pointer(regs),
+			      regs);
+}
+
 #ifdef CONFIG_KASAN_HW_TAGS
 void kasan_report_async(void)
 {
-- 
2.37.3.998.g577e59143f-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH v2] kasan: also display registers for reports from HW exceptions
  2022-09-27  1:20 [PATCH v2] kasan: also display registers for reports from HW exceptions Peter Collingbourne
@ 2022-09-27 18:20 ` Andrey Konovalov
  0 siblings, 0 replies; 2+ messages in thread
From: Andrey Konovalov @ 2022-09-27 18:20 UTC (permalink / raw)
  To: Peter Collingbourne
  Cc: Catalin Marinas, Vincenzo Frascino, Andrew Morton, Linux ARM,
	kasan-dev, Linux Memory Management List

On Tue, Sep 27, 2022 at 3:20 AM Peter Collingbourne <pcc@google.com> wrote:
>
> It is sometimes useful to know the values of the registers when a KASAN
> report is generated. We can do this easily for reports that resulted from
> a hardware exception by passing the struct pt_regs from the exception into
> the report function; do so, but only in HW tags mode because registers
> may have been corrupted during the check in other modes.
>
> Signed-off-by: Peter Collingbourne <pcc@google.com>
> ---
> Applies to -next.
>
> v2:
> - only do this in HW tags mode
> - move pr_err to caller
>
>  arch/arm64/mm/fault.c |  2 +-
>  include/linux/kasan.h | 10 ++++++++++
>  mm/kasan/kasan.h      |  1 +
>  mm/kasan/report.c     | 30 +++++++++++++++++++++++-------
>  4 files changed, 35 insertions(+), 8 deletions(-)
>
> diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
> index 5b391490e045..c4b91f5d8cc8 100644
> --- a/arch/arm64/mm/fault.c
> +++ b/arch/arm64/mm/fault.c
> @@ -316,7 +316,7 @@ static void report_tag_fault(unsigned long addr, unsigned long esr,
>          * find out access size.
>          */
>         bool is_write = !!(esr & ESR_ELx_WNR);
> -       kasan_report(addr, 0, is_write, regs->pc);
> +       kasan_report_regs(addr, 0, is_write, regs);
>  }
>  #else
>  /* Tag faults aren't enabled without CONFIG_KASAN_HW_TAGS. */
> diff --git a/include/linux/kasan.h b/include/linux/kasan.h
> index d811b3d7d2a1..381aea149353 100644
> --- a/include/linux/kasan.h
> +++ b/include/linux/kasan.h
> @@ -353,6 +353,16 @@ static inline void *kasan_reset_tag(const void *addr)
>  bool kasan_report(unsigned long addr, size_t size,
>                 bool is_write, unsigned long ip);
>
> +/**
> + * kasan_report_regs - print a report about a bad memory access detected by KASAN
> + * @addr: address of the bad access
> + * @size: size of the bad access
> + * @is_write: whether the bad access is a write or a read
> + * @regs: register values at the point of the bad memory access
> + */
> +bool kasan_report_regs(unsigned long addr, size_t size, bool is_write,
> +                      struct pt_regs *regs);
> +
>  #else /* CONFIG_KASAN_SW_TAGS || CONFIG_KASAN_HW_TAGS */
>
>  static inline void *kasan_reset_tag(const void *addr)
> diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h
> index abbcc1b0eec5..39772c21a8ae 100644
> --- a/mm/kasan/kasan.h
> +++ b/mm/kasan/kasan.h
> @@ -175,6 +175,7 @@ struct kasan_report_info {
>         size_t access_size;
>         bool is_write;
>         unsigned long ip;
> +       struct pt_regs *regs;
>
>         /* Filled in by the common reporting code. */
>         void *first_bad_addr;
> diff --git a/mm/kasan/report.c b/mm/kasan/report.c
> index df3602062bfd..be8dd97940c7 100644
> --- a/mm/kasan/report.c
> +++ b/mm/kasan/report.c
> @@ -24,6 +24,7 @@
>  #include <linux/types.h>
>  #include <linux/kasan.h>
>  #include <linux/module.h>
> +#include <linux/sched/debug.h>
>  #include <linux/sched/task_stack.h>
>  #include <linux/uaccess.h>
>  #include <trace/events/error_report.h>
> @@ -281,9 +282,6 @@ static void print_address_description(void *addr, u8 tag,
>  {
>         struct page *page = addr_to_page(addr);
>
> -       dump_stack_lvl(KERN_ERR);
> -       pr_err("\n");
> -
>         if (info->cache && info->object) {
>                 describe_object(addr, info);
>                 pr_err("\n");
> @@ -391,11 +389,15 @@ static void print_report(struct kasan_report_info *info)
>                 kasan_print_tags(tag, info->first_bad_addr);
>         pr_err("\n");
>
> +       if (info->regs)
> +               show_regs(info->regs);
> +       else
> +               dump_stack_lvl(KERN_ERR);
> +
>         if (addr_has_metadata(addr)) {
> +               pr_err("\n");
>                 print_address_description(addr, tag, info);
>                 print_memory_metadata(info->first_bad_addr);
> -       } else {
> -               dump_stack_lvl(KERN_ERR);
>         }
>  }
>
> @@ -467,8 +469,8 @@ void kasan_report_invalid_free(void *ptr, unsigned long ip, enum kasan_report_ty
>   * user_access_save/restore(): kasan_report_invalid_free() cannot be called
>   * from a UACCESS region, and kasan_report_async() is not used on x86.
>   */
> -bool kasan_report(unsigned long addr, size_t size, bool is_write,
> -                       unsigned long ip)
> +static bool __kasan_report(unsigned long addr, size_t size, bool is_write,
> +                       unsigned long ip, struct pt_regs *regs)
>  {
>         bool ret = true;
>         void *ptr = (void *)addr;
> @@ -489,6 +491,7 @@ bool kasan_report(unsigned long addr, size_t size, bool is_write,
>         info.access_size = size;
>         info.is_write = is_write;
>         info.ip = ip;
> +       info.regs = regs;
>
>         complete_report_info(&info);
>
> @@ -502,6 +505,19 @@ bool kasan_report(unsigned long addr, size_t size, bool is_write,
>         return ret;
>  }
>
> +bool kasan_report(unsigned long addr, size_t size, bool is_write,
> +                       unsigned long ip)
> +{
> +       return __kasan_report(addr, size, is_write, ip, NULL);
> +}
> +
> +bool kasan_report_regs(unsigned long addr, size_t size, bool is_write,
> +                      struct pt_regs *regs)
> +{
> +       return __kasan_report(addr, size, is_write, instruction_pointer(regs),
> +                             regs);
> +}
> +
>  #ifdef CONFIG_KASAN_HW_TAGS
>  void kasan_report_async(void)
>  {
> --
> 2.37.3.998.g577e59143f-goog
>

Reviewed-by: Andrey Konovalov <andreyknvl@gmail.com>

Thanks!

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2022-09-27 18:21 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-27  1:20 [PATCH v2] kasan: also display registers for reports from HW exceptions Peter Collingbourne
2022-09-27 18:20 ` Andrey Konovalov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).