Skip to content

Commit 20621d2

Browse files
committed
Merge tag 'x86_urgent_for_v5.15_rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fixes from Borislav Petkov: - Prevent a infinite loop in the MCE recovery on return to user space, which was caused by a second MCE queueing work for the same page and thereby creating a circular work list. - Make kern_addr_valid() handle existing PMD entries, which are marked not present in the higher level page table, correctly instead of blindly dereferencing them. - Pass a valid address to sanitize_phys(). This was caused by the mixture of inclusive and exclusive ranges. memtype_reserve() expect 'end' being exclusive, but sanitize_phys() wants it inclusive. This worked so far, but with end being the end of the physical address space the fail is exposed. - Increase the maximum supported GPIO numbers for 64bit. Newer SoCs exceed the previous maximum. * tag 'x86_urgent_for_v5.15_rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/mce: Avoid infinite loop for copy from user recovery x86/mm: Fix kern_addr_valid() to cope with existing but not present entries x86/platform: Increase maximum GPIO number for X86_64 x86/pat: Pass valid address to sanitize_phys()
2 parents fec3036 + 81065b3 commit 20621d2

File tree

5 files changed

+47
-15
lines changed

5 files changed

+47
-15
lines changed

arch/x86/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,11 @@ config NEED_PER_CPU_PAGE_FIRST_CHUNK
339339
config ARCH_HIBERNATION_POSSIBLE
340340
def_bool y
341341

342+
config ARCH_NR_GPIO
343+
int
344+
default 1024 if X86_64
345+
default 512
346+
342347
config ARCH_SUSPEND_POSSIBLE
343348
def_bool y
344349

arch/x86/kernel/cpu/mce/core.c

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,6 +1253,9 @@ static void __mc_scan_banks(struct mce *m, struct pt_regs *regs, struct mce *fin
12531253

12541254
static void kill_me_now(struct callback_head *ch)
12551255
{
1256+
struct task_struct *p = container_of(ch, struct task_struct, mce_kill_me);
1257+
1258+
p->mce_count = 0;
12561259
force_sig(SIGBUS);
12571260
}
12581261

@@ -1262,6 +1265,7 @@ static void kill_me_maybe(struct callback_head *cb)
12621265
int flags = MF_ACTION_REQUIRED;
12631266
int ret;
12641267

1268+
p->mce_count = 0;
12651269
pr_err("Uncorrected hardware memory error in user-access at %llx", p->mce_addr);
12661270

12671271
if (!p->mce_ripv)
@@ -1290,17 +1294,34 @@ static void kill_me_maybe(struct callback_head *cb)
12901294
}
12911295
}
12921296

1293-
static void queue_task_work(struct mce *m, int kill_current_task)
1297+
static void queue_task_work(struct mce *m, char *msg, int kill_current_task)
12941298
{
1295-
current->mce_addr = m->addr;
1296-
current->mce_kflags = m->kflags;
1297-
current->mce_ripv = !!(m->mcgstatus & MCG_STATUS_RIPV);
1298-
current->mce_whole_page = whole_page(m);
1299+
int count = ++current->mce_count;
12991300

1300-
if (kill_current_task)
1301-
current->mce_kill_me.func = kill_me_now;
1302-
else
1303-
current->mce_kill_me.func = kill_me_maybe;
1301+
/* First call, save all the details */
1302+
if (count == 1) {
1303+
current->mce_addr = m->addr;
1304+
current->mce_kflags = m->kflags;
1305+
current->mce_ripv = !!(m->mcgstatus & MCG_STATUS_RIPV);
1306+
current->mce_whole_page = whole_page(m);
1307+
1308+
if (kill_current_task)
1309+
current->mce_kill_me.func = kill_me_now;
1310+
else
1311+
current->mce_kill_me.func = kill_me_maybe;
1312+
}
1313+
1314+
/* Ten is likely overkill. Don't expect more than two faults before task_work() */
1315+
if (count > 10)
1316+
mce_panic("Too many consecutive machine checks while accessing user data", m, msg);
1317+
1318+
/* Second or later call, make sure page address matches the one from first call */
1319+
if (count > 1 && (current->mce_addr >> PAGE_SHIFT) != (m->addr >> PAGE_SHIFT))
1320+
mce_panic("Consecutive machine checks to different user pages", m, msg);
1321+
1322+
/* Do not call task_work_add() more than once */
1323+
if (count > 1)
1324+
return;
13041325

13051326
task_work_add(current, &current->mce_kill_me, TWA_RESUME);
13061327
}
@@ -1438,7 +1459,7 @@ noinstr void do_machine_check(struct pt_regs *regs)
14381459
/* If this triggers there is no way to recover. Die hard. */
14391460
BUG_ON(!on_thread_stack() || !user_mode(regs));
14401461

1441-
queue_task_work(&m, kill_current_task);
1462+
queue_task_work(&m, msg, kill_current_task);
14421463

14431464
} else {
14441465
/*
@@ -1456,7 +1477,7 @@ noinstr void do_machine_check(struct pt_regs *regs)
14561477
}
14571478

14581479
if (m.kflags & MCE_IN_KERNEL_COPYIN)
1459-
queue_task_work(&m, kill_current_task);
1480+
queue_task_work(&m, msg, kill_current_task);
14601481
}
14611482
out:
14621483
mce_wrmsrl(MSR_IA32_MCG_STATUS, 0);

arch/x86/mm/init_64.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,18 +1432,18 @@ int kern_addr_valid(unsigned long addr)
14321432
return 0;
14331433

14341434
p4d = p4d_offset(pgd, addr);
1435-
if (p4d_none(*p4d))
1435+
if (!p4d_present(*p4d))
14361436
return 0;
14371437

14381438
pud = pud_offset(p4d, addr);
1439-
if (pud_none(*pud))
1439+
if (!pud_present(*pud))
14401440
return 0;
14411441

14421442
if (pud_large(*pud))
14431443
return pfn_valid(pud_pfn(*pud));
14441444

14451445
pmd = pmd_offset(pud, addr);
1446-
if (pmd_none(*pmd))
1446+
if (!pmd_present(*pmd))
14471447
return 0;
14481448

14491449
if (pmd_large(*pmd))

arch/x86/mm/pat/memtype.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,12 @@ int memtype_reserve(u64 start, u64 end, enum page_cache_mode req_type,
583583
int err = 0;
584584

585585
start = sanitize_phys(start);
586-
end = sanitize_phys(end);
586+
587+
/*
588+
* The end address passed into this function is exclusive, but
589+
* sanitize_phys() expects an inclusive address.
590+
*/
591+
end = sanitize_phys(end - 1) + 1;
587592
if (start >= end) {
588593
WARN(1, "%s failed: [mem %#010Lx-%#010Lx], req %s\n", __func__,
589594
start, end - 1, cattr_name(req_type));

include/linux/sched.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,6 +1471,7 @@ struct task_struct {
14711471
mce_whole_page : 1,
14721472
__mce_reserved : 62;
14731473
struct callback_head mce_kill_me;
1474+
int mce_count;
14741475
#endif
14751476

14761477
#ifdef CONFIG_KRETPROBES

0 commit comments

Comments
 (0)