Commit 7d53be55 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'x86_urgent_for_v5.10-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 fixes from Borislav Petkov:

 - An IOMMU VT-d build fix when CONFIG_PCI_ATS=n along with a revert of
   same because the proper one is going through the IOMMU tree (Thomas
   Gleixner)

 - An Intel microcode loader fix to save the correct microcode patch to
   apply during resume (Chen Yu)

 - A fix to not access user memory of other processes when dumping
   opcode bytes (Thomas Gleixner)

* tag 'x86_urgent_for_v5.10-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  Revert "iommu/vt-d: Take CONFIG_PCI_ATS into account"
  x86/dumpstack: Do not try to access user space code of other tasks
  x86/microcode/intel: Check patch signature before saving microcode for early loading
  iommu/vt-d: Take CONFIG_PCI_ATS into account
parents 4a51c60a 01cf158e
......@@ -100,53 +100,6 @@ static int has_newer_microcode(void *mc, unsigned int csig, int cpf, int new_rev
return find_matching_signature(mc, csig, cpf);
}
/*
* Given CPU signature and a microcode patch, this function finds if the
* microcode patch has matching family and model with the CPU.
*
* %true - if there's a match
* %false - otherwise
*/
static bool microcode_matches(struct microcode_header_intel *mc_header,
unsigned long sig)
{
unsigned long total_size = get_totalsize(mc_header);
unsigned long data_size = get_datasize(mc_header);
struct extended_sigtable *ext_header;
unsigned int fam_ucode, model_ucode;
struct extended_signature *ext_sig;
unsigned int fam, model;
int ext_sigcount, i;
fam = x86_family(sig);
model = x86_model(sig);
fam_ucode = x86_family(mc_header->sig);
model_ucode = x86_model(mc_header->sig);
if (fam == fam_ucode && model == model_ucode)
return true;
/* Look for ext. headers: */
if (total_size <= data_size + MC_HEADER_SIZE)
return false;
ext_header = (void *) mc_header + data_size + MC_HEADER_SIZE;
ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
ext_sigcount = ext_header->count;
for (i = 0; i < ext_sigcount; i++) {
fam_ucode = x86_family(ext_sig->sig);
model_ucode = x86_model(ext_sig->sig);
if (fam == fam_ucode && model == model_ucode)
return true;
ext_sig++;
}
return false;
}
static struct ucode_patch *memdup_patch(void *data, unsigned int size)
{
struct ucode_patch *p;
......@@ -164,7 +117,7 @@ static struct ucode_patch *memdup_patch(void *data, unsigned int size)
return p;
}
static void save_microcode_patch(void *data, unsigned int size)
static void save_microcode_patch(struct ucode_cpu_info *uci, void *data, unsigned int size)
{
struct microcode_header_intel *mc_hdr, *mc_saved_hdr;
struct ucode_patch *iter, *tmp, *p = NULL;
......@@ -210,6 +163,9 @@ static void save_microcode_patch(void *data, unsigned int size)
if (!p)
return;
if (!find_matching_signature(p->data, uci->cpu_sig.sig, uci->cpu_sig.pf))
return;
/*
* Save for early loading. On 32-bit, that needs to be a physical
* address as the APs are running from physical addresses, before
......@@ -344,13 +300,14 @@ scan_microcode(void *data, size_t size, struct ucode_cpu_info *uci, bool save)
size -= mc_size;
if (!microcode_matches(mc_header, uci->cpu_sig.sig)) {
if (!find_matching_signature(data, uci->cpu_sig.sig,
uci->cpu_sig.pf)) {
data += mc_size;
continue;
}
if (save) {
save_microcode_patch(data, mc_size);
save_microcode_patch(uci, data, mc_size);
goto next;
}
......@@ -483,14 +440,14 @@ static void show_saved_mc(void)
* Save this microcode patch. It will be loaded early when a CPU is
* hot-added or resumes.
*/
static void save_mc_for_early(u8 *mc, unsigned int size)
static void save_mc_for_early(struct ucode_cpu_info *uci, u8 *mc, unsigned int size)
{
/* Synchronization during CPU hotplug. */
static DEFINE_MUTEX(x86_cpu_microcode_mutex);
mutex_lock(&x86_cpu_microcode_mutex);
save_microcode_patch(mc, size);
save_microcode_patch(uci, mc, size);
show_saved_mc();
mutex_unlock(&x86_cpu_microcode_mutex);
......@@ -935,7 +892,7 @@ static enum ucode_state generic_load_microcode(int cpu, struct iov_iter *iter)
* permanent memory. So it will be loaded early when a CPU is hot added
* or resumes.
*/
save_mc_for_early(new_mc, new_mc_size);
save_mc_for_early(uci, new_mc, new_mc_size);
pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n",
cpu, new_rev, uci->cpu_sig.rev);
......
......@@ -78,6 +78,9 @@ static int copy_code(struct pt_regs *regs, u8 *buf, unsigned long src,
if (!user_mode(regs))
return copy_from_kernel_nofault(buf, (u8 *)src, nbytes);
/* The user space code from other tasks cannot be accessed. */
if (regs != task_pt_regs(current))
return -EPERM;
/*
* Make sure userspace isn't trying to trick us into dumping kernel
* memory by pointing the userspace instruction pointer at it.
......@@ -85,6 +88,12 @@ static int copy_code(struct pt_regs *regs, u8 *buf, unsigned long src,
if (__chk_range_not_ok(src, nbytes, TASK_SIZE_MAX))
return -EINVAL;
/*
* Even if named copy_from_user_nmi() this can be invoked from
* other contexts and will not try to resolve a pagefault, which is
* the correct thing to do here as this code can be called from any
* context.
*/
return copy_from_user_nmi(buf, (void __user *)src, nbytes);
}
......@@ -115,13 +124,19 @@ void show_opcodes(struct pt_regs *regs, const char *loglvl)
u8 opcodes[OPCODE_BUFSIZE];
unsigned long prologue = regs->ip - PROLOGUE_SIZE;
if (copy_code(regs, opcodes, prologue, sizeof(opcodes))) {
printk("%sCode: Unable to access opcode bytes at RIP 0x%lx.\n",
loglvl, prologue);
} else {
switch (copy_code(regs, opcodes, prologue, sizeof(opcodes))) {
case 0:
printk("%sCode: %" __stringify(PROLOGUE_SIZE) "ph <%02x> %"
__stringify(EPILOGUE_SIZE) "ph\n", loglvl, opcodes,
opcodes[PROLOGUE_SIZE], opcodes + PROLOGUE_SIZE + 1);
break;
case -EPERM:
/* No access to the user space stack of other tasks. Ignore. */
break;
default:
printk("%sCode: Unable to access opcode bytes at RIP 0x%lx.\n",
loglvl, prologue);
break;
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment