Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetr Tesarik <ptesarik@suse.cz>2019-06-21 22:04:54 +0200
committerPetr Tesarik <ptesarik@suse.cz>2019-06-21 22:04:54 +0200
commit492238ee6483e6535c42d04a3c3ec8ba6caf61de (patch)
tree492ea91e1e3e4dacce8bb5f3ee70075d922f1e7d
parentc71dd256f59d889b05d06bf732b56861f363e923 (diff)
parentcfaef5e8ce0c9165cdfcdad5ffcee04037364fb3 (diff)
Merge branch 'users/msuchanek/SLE15-SP1_EMBARGO/for-next' into SLE15-SP1_EMBARGO
Pull POWER mm fix from Michal Suchanek suse-commit: af9d258df45988246b72a8c377f4c6ad0e706311
-rw-r--r--arch/powerpc/mm/mmu_context_book3s64.c46
1 files changed, 42 insertions, 4 deletions
diff --git a/arch/powerpc/mm/mmu_context_book3s64.c b/arch/powerpc/mm/mmu_context_book3s64.c
index a792d5f288bb..f7090b277027 100644
--- a/arch/powerpc/mm/mmu_context_book3s64.c
+++ b/arch/powerpc/mm/mmu_context_book3s64.c
@@ -85,14 +85,48 @@ int hash__alloc_context_id(void)
}
EXPORT_SYMBOL_GPL(hash__alloc_context_id);
+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;
-
/*
* The old code would re-promote on fork, we don't do that when using
* slices as it could cause problem promoting slices that have been
@@ -110,6 +144,10 @@ static int hash__init_new_context(struct mm_struct *mm)
if (mm->context.id == 0)
slice_init_new_context_exec(mm);
+ index = realloc_context_ids(&mm->context);
+ if (index < 0)
+ return index;
+
subpage_prot_init_new_context(mm);
pkey_mm_init(mm);