x86/events, x86/insn-eval: Remove incorrect current->active_mm references

When decoding an instruction or handling a perf event that references an
LDT segment, if we don't have a valid user context, trying to access the
LDT by any means other than SLDT is racy.  Certainly, using
current->active_mm is wrong, as active_mm can point to a real user mm when
CR3 and LDTR no longer reference that mm.

Clean up the code.  If nmi_uaccess_okay() says we don't have a valid
context, just fail.  Otherwise use current->mm.

Signed-off-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Rik van Riel <riel@surriel.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Link: https://lore.kernel.org/r/20250402094540.3586683-3-mingo@kernel.org
This commit is contained in:
Andy Lutomirski 2025-04-02 11:45:35 +02:00 committed by Ingo Molnar
parent 0812e096cf
commit 81e3cbdef2
2 changed files with 18 additions and 4 deletions

View File

@ -2803,8 +2803,15 @@ static unsigned long get_segment_base(unsigned int segment)
#ifdef CONFIG_MODIFY_LDT_SYSCALL
struct ldt_struct *ldt;
/*
* If we're not in a valid context with a real (not just lazy)
* user mm, then don't even try.
*/
if (!nmi_uaccess_okay())
return 0;
/* IRQs are off, so this synchronizes with smp_store_release */
ldt = READ_ONCE(current->active_mm->context.ldt);
ldt = smp_load_acquire(&current->mm->context.ldt);
if (!ldt || idx >= ldt->nr_entries)
return 0;

View File

@ -631,14 +631,21 @@ static bool get_desc(struct desc_struct *out, unsigned short sel)
/* Bits [15:3] contain the index of the desired entry. */
sel >>= 3;
mutex_lock(&current->active_mm->context.lock);
ldt = current->active_mm->context.ldt;
/*
* If we're not in a valid context with a real (not just lazy)
* user mm, then don't even try.
*/
if (!nmi_uaccess_okay())
return false;
mutex_lock(&current->mm->context.lock);
ldt = current->mm->context.ldt;
if (ldt && sel < ldt->nr_entries) {
*out = ldt->entries[sel];
success = true;
}
mutex_unlock(&current->active_mm->context.lock);
mutex_unlock(&current->mm->context.lock);
return success;
}