From: mark.rutland@arm.com (Mark Rutland)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 3/3] arm64: dump: Add checking for writable and exectuable pages
Date: Fri, 30 Sep 2016 03:08:14 +0100 [thread overview]
Message-ID: <20160930020813.GB4611@remoulade> (raw)
In-Reply-To: <20160929213257.30505-4-labbott@redhat.com>
Hi,
On Thu, Sep 29, 2016 at 02:32:57PM -0700, Laura Abbott wrote:
> Page mappings with full RWX permissions are a security risk. x86
> has an option to walk the page tables and dump any bad pages.
> (See e1a58320a38d ("x86/mm: Warn on W^X mappings")). Add a similar
> implementation for arm64.
>
> Signed-off-by: Laura Abbott <labbott@redhat.com>
> @@ -31,6 +32,8 @@ struct ptdump_info {
> const struct addr_marker *markers;
> unsigned long base_addr;
> unsigned long max_addr;
(unrelated aside: it looks like max_addr is never used or even assigned to;
care to delete it in a prep patch?)
> + /* Internal, do not touch */
> + struct list_head node;
> };
> +static LIST_HEAD(dump_info);
With the EFI runtime map tables it's unfortunately valid (and very likely with
64K pages) that there will be RWX mappings, at least with contemporary versions
of the UEFI spec. Luckily, those are only installed rarely and transiently.
Given that (and other potential ptdump users), I don't think we should have a
dynamic list of ptdump_infos for W^X checks, and should instead have
ptdump_check_wx() explicitly check the tables we care about. More comments
below on that.
I think we only care about the swapper and hyp tables, as nothing else is
permanent. Does that sound sane?
> struct prot_bits {
> @@ -219,6 +223,15 @@ static void note_page(struct pg_state *st, unsigned long addr, unsigned level,
> unsigned long delta;
>
> if (st->current_prot) {
> + if (st->check_wx &&
> + ((st->current_prot & PTE_RDONLY) != PTE_RDONLY) &&
> + ((st->current_prot & PTE_PXN) != PTE_PXN)) {
> + WARN_ONCE(1, "arm64/mm: Found insecure W+X mapping at address %p/%pS\n",
> + (void *)st->start_address,
> + (void *)st->start_address);
> + st->wx_pages += (addr - st->start_address) / PAGE_SIZE;
> + }
> +
Currently note_page() is painful to read due to the indentation and logic.
Rather than adding to that, could we factor this into a helper? e.g.
note_prot_wx(struct pg_state *st, unsigned long addr)
{
if (!st->check_wx)
return;
if ((st->current_prot & PTE_RDONLY) == PTE_RDONLY)
return;
if ((st->current_prot & PTE_PXN) == PTE_PXN)
return;
WARN_ONCE(1, "arm64/mm: Found insecure W+X mapping at address %p/%pS\n",
(void *)st->start_address, (void *)st->start_address);
st->wx_pages += (addr - st->start_address) / PAGE_SIZE;
}
> +void ptdump_check_wx(void)
> +{
> + struct ptdump_info *info;
> +
> + list_for_each_entry(info, &dump_info, node) {
> + struct pg_state st = {
> + .seq = NULL,
> + .marker = info->markers,
> + .check_wx = true,
> + };
> +
> + __walk_pgd(&st, info->mm, info->base_addr);
> + note_page(&st, 0, 0, 0);
> + if (st.wx_pages)
> + pr_info("Checked W+X mappings (%p): FAILED, %lu W+X pages found\n",
> + info->mm,
> + st.wx_pages);
> + else
> + pr_info("Checked W+X mappings (%p): passed, no W+X pages found\n", info->mm);
> + }
> +}
As above, I don't think we should use a list of arbitrary ptdump_infos.
Given we won't log addresses in the walking code, I think that we can make up a
trivial marker array, and then just use init_mm direct, e.g. (never even
compile-tested):
void ptdump_check_wx(void)
{
struct pg_state st = {
.seq = NULL,
.marker = (struct addr_markers[]) {
{ -1, NULL},
},
.check_wx = true,
};
__walk_pgd(&st, init_mm, 0);
note_page(&st, 0, 0, 0);
if (st.wx_pages)
pr_info("Checked W+X mappings (%p): FAILED, %lu W+X pages found\n",
info->mm,
st.wx_pages);
else
pr_info("Checked W+X mappings (%p): passed, no W+X pages found\n", info->mm);
}
Otherwise, this looks good to me. Thanks for putting this together!
Mark.
next prev parent reply other threads:[~2016-09-30 2:08 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-09-29 21:32 [PATCH 0/3] WX Checking for arm64 Laura Abbott
2016-09-29 21:32 ` [PATCH 1/3] arm64: dump: Make ptdump debugfs a separate option Laura Abbott
2016-09-30 0:13 ` Mark Rutland
2016-09-30 0:31 ` Laura Abbott
2016-09-30 0:48 ` Mark Rutland
2016-09-30 1:11 ` Laura Abbott
2016-09-30 1:27 ` Mark Rutland
2016-09-29 21:32 ` [PATCH 2/3] arm64: dump: Make the page table dumping seq_file optional Laura Abbott
2016-09-30 0:36 ` Mark Rutland
2016-09-29 21:32 ` [PATCH 3/3] arm64: dump: Add checking for writable and exectuable pages Laura Abbott
2016-09-30 2:08 ` Mark Rutland [this message]
2016-09-30 15:58 ` Mark Rutland
2016-09-30 16:25 ` Kees Cook
2016-09-30 16:41 ` Mark Rutland
2016-09-30 17:16 ` Kees Cook
2016-09-30 1:29 ` [kernel-hardening] [PATCH 0/3] WX Checking for arm64 Kees Cook
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=20160930020813.GB4611@remoulade \
--to=mark.rutland@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox