All of lore.kernel.org
 help / color / mirror / Atom feed
From: james.morse@arm.com (James Morse)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v2] arm64: print a fault message when attempting to write RO memory
Date: Fri, 17 Feb 2017 11:00:39 +0000	[thread overview]
Message-ID: <58A6D7D7.1030704@arm.com> (raw)
In-Reply-To: <20170217011959.26754-1-stephen.boyd@linaro.org>

Hi Stephen,

On 17/02/17 01:19, Stephen Boyd wrote:
> If a page is marked read only we should print out that fact,
> instead of printing out that there was a page fault. Right now we
> get a cryptic error message that something went wrong with an
> unhandled fault, but we don't evaluate the esr to figure out that
> it was a read/write permission fault.
> 
> Instead of seeing:
> 
>   Unable to handle kernel paging request at virtual address ffff000008e460d8
>   pgd = ffff800003504000
>   [ffff000008e460d8] *pgd=0000000083473003, *pud=0000000083503003, *pmd=0000000000000000
>   Internal error: Oops: 9600004f [#1] PREEMPT SMP
> 
> we'll see:
> 
>   Unable to handle kernel write to read-only memory at virtual address ffff000008e760d8
>   pgd = ffff80003d3de000
>   [ffff000008e760d8] *pgd=0000000083472003, *pud=0000000083435003, *pmd=0000000000000000
>   Internal error: Oops: 9600004f [#1] PREEMPT SMP

This looks like a good idea..



> diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
> index 156169c6981b..8bd4e7f11c70 100644
> --- a/arch/arm64/mm/fault.c
> +++ b/arch/arm64/mm/fault.c

>  /*
>   * The kernel tried to access some page that wasn't present.
>   */
>  static void __do_kernel_fault(struct mm_struct *mm, unsigned long addr,
>  			      unsigned int esr, struct pt_regs *regs)
>  {
> +	const char *msg;
>  	/*
>  	 * Are we prepared to handle this kernel fault?
>  	 * We are almost certainly not prepared to handle instruction faults.
> @@ -177,9 +193,19 @@ static void __do_kernel_fault(struct mm_struct *mm, unsigned long addr,
>  	 * No handler, we'll have to terminate things with extreme prejudice.
>  	 */
>  	bust_spinlocks(1);
> -	pr_alert("Unable to handle kernel %s at virtual address %08lx\n",
> -		 (addr < PAGE_SIZE) ? "NULL pointer dereference" :
> -		 "paging request", addr);
> +
> +	if (is_permission_fault(esr, regs)) {

is_permission_fault() was previously guarded with a 'addr<USER_DS' check, this
is because it assumes software-PAN is relevant.

The corner case is when the kernel accesses TTBR1-mapped memory while
software-PAN happens to have swivelled TTBR0. Translation faults will be matched
by is_permission_fault(), but permission faults won't.

Juggling is_permission_fault() to look something like:
---%<---
	if (fsc_type == ESR_ELx_FSC_PERM)
		return true;

	if (addr < USER_DS && system_uses_ttbr0_pan())
		return fsc_type == ESR_ELx_FSC_FAULT &&
			(regs->pstate & PSR_PAN_BIT);

	return false;
---%<---
... should fix this.



> +		if (esr & ESR_ELx_WNR)
> +			msg = "write to read-only memory";
> +		else
> +			msg = "read from unreadable memory";
> +	} else if (addr < PAGE_SIZE)
> +		msg = "NULL pointer dereference";
> +	else
> +		msg = "paging request";

Nit: {} all the way down!


> +
> +	pr_alert("Unable to handle kernel %s at virtual address %08lx\n", msg,
> +		 addr);
>  
>  	show_pte(mm, addr);
>  	die("Oops", regs, esr);
> @@ -269,21 +295,6 @@ static int __do_page_fault(struct mm_struct *mm, unsigned long addr,
>  	return fault;
>  }

> -static inline bool is_permission_fault(unsigned int esr, struct pt_regs *regs)
> -{
> -	unsigned int ec       = ESR_ELx_EC(esr);
> -	unsigned int fsc_type = esr & ESR_ELx_FSC_TYPE;
> -
> -	if (ec != ESR_ELx_EC_DABT_CUR && ec != ESR_ELx_EC_IABT_CUR)
> -		return false;
> -
> -	if (system_uses_ttbr0_pan())
> -		return fsc_type == ESR_ELx_FSC_FAULT &&
> -			(regs->pstate & PSR_PAN_BIT);
> -	else
> -		return fsc_type == ESR_ELx_FSC_PERM;
> -}


Thanks!

James

WARNING: multiple messages have this Message-ID (diff)
From: James Morse <james.morse@arm.com>
To: Stephen Boyd <stephen.boyd@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>,
	Will Deacon <will.deacon@arm.com>,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, Laura Abbott <labbott@redhat.com>,
	Mark Rutland <mark.rutland@arm.com>
Subject: Re: [PATCH v2] arm64: print a fault message when attempting to write RO memory
Date: Fri, 17 Feb 2017 11:00:39 +0000	[thread overview]
Message-ID: <58A6D7D7.1030704@arm.com> (raw)
In-Reply-To: <20170217011959.26754-1-stephen.boyd@linaro.org>

Hi Stephen,

On 17/02/17 01:19, Stephen Boyd wrote:
> If a page is marked read only we should print out that fact,
> instead of printing out that there was a page fault. Right now we
> get a cryptic error message that something went wrong with an
> unhandled fault, but we don't evaluate the esr to figure out that
> it was a read/write permission fault.
> 
> Instead of seeing:
> 
>   Unable to handle kernel paging request at virtual address ffff000008e460d8
>   pgd = ffff800003504000
>   [ffff000008e460d8] *pgd=0000000083473003, *pud=0000000083503003, *pmd=0000000000000000
>   Internal error: Oops: 9600004f [#1] PREEMPT SMP
> 
> we'll see:
> 
>   Unable to handle kernel write to read-only memory at virtual address ffff000008e760d8
>   pgd = ffff80003d3de000
>   [ffff000008e760d8] *pgd=0000000083472003, *pud=0000000083435003, *pmd=0000000000000000
>   Internal error: Oops: 9600004f [#1] PREEMPT SMP

This looks like a good idea..



> diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
> index 156169c6981b..8bd4e7f11c70 100644
> --- a/arch/arm64/mm/fault.c
> +++ b/arch/arm64/mm/fault.c

>  /*
>   * The kernel tried to access some page that wasn't present.
>   */
>  static void __do_kernel_fault(struct mm_struct *mm, unsigned long addr,
>  			      unsigned int esr, struct pt_regs *regs)
>  {
> +	const char *msg;
>  	/*
>  	 * Are we prepared to handle this kernel fault?
>  	 * We are almost certainly not prepared to handle instruction faults.
> @@ -177,9 +193,19 @@ static void __do_kernel_fault(struct mm_struct *mm, unsigned long addr,
>  	 * No handler, we'll have to terminate things with extreme prejudice.
>  	 */
>  	bust_spinlocks(1);
> -	pr_alert("Unable to handle kernel %s at virtual address %08lx\n",
> -		 (addr < PAGE_SIZE) ? "NULL pointer dereference" :
> -		 "paging request", addr);
> +
> +	if (is_permission_fault(esr, regs)) {

is_permission_fault() was previously guarded with a 'addr<USER_DS' check, this
is because it assumes software-PAN is relevant.

The corner case is when the kernel accesses TTBR1-mapped memory while
software-PAN happens to have swivelled TTBR0. Translation faults will be matched
by is_permission_fault(), but permission faults won't.

Juggling is_permission_fault() to look something like:
---%<---
	if (fsc_type == ESR_ELx_FSC_PERM)
		return true;

	if (addr < USER_DS && system_uses_ttbr0_pan())
		return fsc_type == ESR_ELx_FSC_FAULT &&
			(regs->pstate & PSR_PAN_BIT);

	return false;
---%<---
... should fix this.



> +		if (esr & ESR_ELx_WNR)
> +			msg = "write to read-only memory";
> +		else
> +			msg = "read from unreadable memory";
> +	} else if (addr < PAGE_SIZE)
> +		msg = "NULL pointer dereference";
> +	else
> +		msg = "paging request";

Nit: {} all the way down!


> +
> +	pr_alert("Unable to handle kernel %s at virtual address %08lx\n", msg,
> +		 addr);
>  
>  	show_pte(mm, addr);
>  	die("Oops", regs, esr);
> @@ -269,21 +295,6 @@ static int __do_page_fault(struct mm_struct *mm, unsigned long addr,
>  	return fault;
>  }

> -static inline bool is_permission_fault(unsigned int esr, struct pt_regs *regs)
> -{
> -	unsigned int ec       = ESR_ELx_EC(esr);
> -	unsigned int fsc_type = esr & ESR_ELx_FSC_TYPE;
> -
> -	if (ec != ESR_ELx_EC_DABT_CUR && ec != ESR_ELx_EC_IABT_CUR)
> -		return false;
> -
> -	if (system_uses_ttbr0_pan())
> -		return fsc_type == ESR_ELx_FSC_FAULT &&
> -			(regs->pstate & PSR_PAN_BIT);
> -	else
> -		return fsc_type == ESR_ELx_FSC_PERM;
> -}


Thanks!

James

  reply	other threads:[~2017-02-17 11:00 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-02-17  1:19 [PATCH v2] arm64: print a fault message when attempting to write RO memory Stephen Boyd
2017-02-17  1:19 ` Stephen Boyd
2017-02-17 11:00 ` James Morse [this message]
2017-02-17 11:00   ` James Morse
2017-02-17 15:53   ` Stephen Boyd
2017-02-20 11:10     ` James Morse
2017-02-20 11:10       ` James Morse
2017-02-25  1:39       ` Stephen Boyd
2017-02-25  1:39         ` Stephen Boyd
2017-03-23 14:22         ` Will Deacon
2017-03-23 14:22           ` Will Deacon
2017-04-04  6:28           ` Stephen Boyd
2017-04-04  6:28             ` Stephen Boyd

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=58A6D7D7.1030704@arm.com \
    --to=james.morse@arm.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.