aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm/book3s64/mmu_context.c
diff options
context:
space:
mode:
authorMichael Ellerman <mpe@ellerman.id.au>2019-07-01 13:59:40 +1000
committerMichael Ellerman <mpe@ellerman.id.au>2019-07-01 13:59:40 +1000
commitb7cbb5240130520ba572ab1146431ad01d1f5099 (patch)
tree3465d7b80e01b845750dd3180162242bfb713281 /arch/powerpc/mm/book3s64/mmu_context.c
parentpowerpc/64s/exception: Fix machine check early corrupting AMR (diff)
parentMerge branch 'context-id-fix' into fixes (diff)
downloadlinux-dev-b7cbb5240130520ba572ab1146431ad01d1f5099.tar.xz
linux-dev-b7cbb5240130520ba572ab1146431ad01d1f5099.zip
Merge tag 'powerpc-5.2-6' into fixes
This merges the commits that were the fix for CVE-2019-12817, which was developed under embargo. They have already been merged by Linus Merge them into fixes now so that this branch contains all the fixes for this release.
Diffstat (limited to 'arch/powerpc/mm/book3s64/mmu_context.c')
-rw-r--r--arch/powerpc/mm/book3s64/mmu_context.c55
1 files changed, 47 insertions, 8 deletions
diff --git a/arch/powerpc/mm/book3s64/mmu_context.c b/arch/powerpc/mm/book3s64/mmu_context.c
index cb2b08635508..6d8f06b04022 100644
--- a/arch/powerpc/mm/book3s64/mmu_context.c
+++ b/arch/powerpc/mm/book3s64/mmu_context.c
@@ -55,20 +55,52 @@ EXPORT_SYMBOL_GPL(hash__alloc_context_id);
void slb_setup_new_exec(void);
+static int realloc_context_ids(mm_context_t *ctx)
+{
+ int i, id;
+
+ /*
+ * id 0 (aka. ctx->id) is special, we always allocate a new one, even if
+ * there wasn't one allocated previously (which happens in the exec
+ * case where ctx is newly allocated).
+ *
+ * We have to be a bit careful here. We must keep the existing ids in
+ * the array, so that we can test if they're non-zero to decide if we
+ * need to allocate a new one. However in case of error we must free the
+ * ids we've allocated but *not* any of the existing ones (or risk a
+ * UAF). That's why we decrement i at the start of the error handling
+ * loop, to skip the id that we just tested but couldn't reallocate.
+ */
+ for (i = 0; i < ARRAY_SIZE(ctx->extended_id); i++) {
+ if (i == 0 || ctx->extended_id[i]) {
+ id = hash__alloc_context_id();
+ if (id < 0)
+ goto error;
+
+ ctx->extended_id[i] = id;
+ }
+ }
+
+ /* The caller expects us to return id */
+ return ctx->id;
+
+error:
+ for (i--; i >= 0; i--) {
+ if (ctx->extended_id[i])
+ ida_free(&mmu_context_ida, ctx->extended_id[i]);
+ }
+
+ return id;
+}
+
static int hash__init_new_context(struct mm_struct *mm)
{
int index;
- index = hash__alloc_context_id();
- if (index < 0)
- return index;
-
mm->context.hash_context = kmalloc(sizeof(struct hash_mm_context),
GFP_KERNEL);
- if (!mm->context.hash_context) {
- ida_free(&mmu_context_ida, index);
+ if (!mm->context.hash_context)
return -ENOMEM;
- }
/*
* The old code would re-promote on fork, we don't do that when using
@@ -96,13 +128,20 @@ static int hash__init_new_context(struct mm_struct *mm)
mm->context.hash_context->spt = kmalloc(sizeof(struct subpage_prot_table),
GFP_KERNEL);
if (!mm->context.hash_context->spt) {
- ida_free(&mmu_context_ida, index);
kfree(mm->context.hash_context);
return -ENOMEM;
}
}
#endif
+ }
+ index = realloc_context_ids(&mm->context);
+ if (index < 0) {
+#ifdef CONFIG_PPC_SUBPAGE_PROT
+ kfree(mm->context.hash_context->spt);
+#endif
+ kfree(mm->context.hash_context);
+ return index;
}
pkey_mm_init(mm);