diff options
author | 2024-04-05 08:59:40 +0200 | |
---|---|---|
committer | 2024-04-05 08:59:40 +0200 | |
commit | d0ce95087288b30e5e211bac8e9a0817f2effcf5 (patch) | |
tree | ce2e128cfdf8d491a494d6583979bc5330db21e2 /0023-x86-account-for-shadow-stack-in-exception-from-stub-.patch | |
parent | Xen 4.17.4-pre-patchset-0 (diff) | |
download | xen-upstream-patches-d0ce95087288b30e5e211bac8e9a0817f2effcf5.tar.gz xen-upstream-patches-d0ce95087288b30e5e211bac8e9a0817f2effcf5.tar.bz2 xen-upstream-patches-d0ce95087288b30e5e211bac8e9a0817f2effcf5.zip |
Xen 4.17.4-pre-patchset-14.17.4-pre-patchset-14.17
Signed-off-by: Tomáš Mózes <hydrapolic@gmail.com>
Diffstat (limited to '0023-x86-account-for-shadow-stack-in-exception-from-stub-.patch')
-rw-r--r-- | 0023-x86-account-for-shadow-stack-in-exception-from-stub-.patch | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/0023-x86-account-for-shadow-stack-in-exception-from-stub-.patch b/0023-x86-account-for-shadow-stack-in-exception-from-stub-.patch new file mode 100644 index 0000000..e23a764 --- /dev/null +++ b/0023-x86-account-for-shadow-stack-in-exception-from-stub-.patch @@ -0,0 +1,212 @@ +From 49f77602373b58b7bbdb40cea2b49d2f88d4003d Mon Sep 17 00:00:00 2001 +From: Jan Beulich <jbeulich@suse.com> +Date: Tue, 27 Feb 2024 14:12:11 +0100 +Subject: [PATCH 23/67] x86: account for shadow stack in exception-from-stub + recovery + +Dealing with exceptions raised from within emulation stubs involves +discarding return address (replaced by exception related information). +Such discarding of course also requires removing the corresponding entry +from the shadow stack. + +Also amend the comment in fixup_exception_return(), to further clarify +why use of ptr[1] can't be an out-of-bounds access. + +This is CVE-2023-46841 / XSA-451. + +Fixes: 209fb9919b50 ("x86/extable: Adjust extable handling to be shadow stack compatible") +Signed-off-by: Jan Beulich <jbeulich@suse.com> +Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com> +master commit: 91f5f7a9154919a765c3933521760acffeddbf28 +master date: 2024-02-27 13:49:22 +0100 +--- + xen/arch/x86/extable.c | 20 ++++++---- + xen/arch/x86/include/asm/uaccess.h | 3 +- + xen/arch/x86/traps.c | 63 +++++++++++++++++++++++++++--- + 3 files changed, 71 insertions(+), 15 deletions(-) + +diff --git a/xen/arch/x86/extable.c b/xen/arch/x86/extable.c +index 6758ba1dca..dd9583f2a5 100644 +--- a/xen/arch/x86/extable.c ++++ b/xen/arch/x86/extable.c +@@ -86,26 +86,29 @@ search_one_extable(const struct exception_table_entry *first, + } + + unsigned long +-search_exception_table(const struct cpu_user_regs *regs) ++search_exception_table(const struct cpu_user_regs *regs, unsigned long *stub_ra) + { + const struct virtual_region *region = find_text_region(regs->rip); + unsigned long stub = this_cpu(stubs.addr); + + if ( region && region->ex ) ++ { ++ *stub_ra = 0; + return search_one_extable(region->ex, region->ex_end, regs->rip); ++ } + + if ( regs->rip >= stub + STUB_BUF_SIZE / 2 && + regs->rip < stub + STUB_BUF_SIZE && + regs->rsp > (unsigned long)regs && + regs->rsp < (unsigned long)get_cpu_info() ) + { +- unsigned long retptr = *(unsigned long *)regs->rsp; ++ unsigned long retaddr = *(unsigned long *)regs->rsp, fixup; + +- region = find_text_region(retptr); +- retptr = region && region->ex +- ? search_one_extable(region->ex, region->ex_end, retptr) +- : 0; +- if ( retptr ) ++ region = find_text_region(retaddr); ++ fixup = region && region->ex ++ ? search_one_extable(region->ex, region->ex_end, retaddr) ++ : 0; ++ if ( fixup ) + { + /* + * Put trap number and error code on the stack (in place of the +@@ -117,7 +120,8 @@ search_exception_table(const struct cpu_user_regs *regs) + }; + + *(unsigned long *)regs->rsp = token.raw; +- return retptr; ++ *stub_ra = retaddr; ++ return fixup; + } + } + +diff --git a/xen/arch/x86/include/asm/uaccess.h b/xen/arch/x86/include/asm/uaccess.h +index 684fccd95c..74bb222c03 100644 +--- a/xen/arch/x86/include/asm/uaccess.h ++++ b/xen/arch/x86/include/asm/uaccess.h +@@ -421,7 +421,8 @@ union stub_exception_token { + unsigned long raw; + }; + +-extern unsigned long search_exception_table(const struct cpu_user_regs *regs); ++extern unsigned long search_exception_table(const struct cpu_user_regs *regs, ++ unsigned long *stub_ra); + extern void sort_exception_tables(void); + extern void sort_exception_table(struct exception_table_entry *start, + const struct exception_table_entry *stop); +diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c +index 06c4f3868b..7599bee361 100644 +--- a/xen/arch/x86/traps.c ++++ b/xen/arch/x86/traps.c +@@ -856,7 +856,7 @@ void do_unhandled_trap(struct cpu_user_regs *regs) + } + + static void fixup_exception_return(struct cpu_user_regs *regs, +- unsigned long fixup) ++ unsigned long fixup, unsigned long stub_ra) + { + if ( IS_ENABLED(CONFIG_XEN_SHSTK) ) + { +@@ -873,7 +873,8 @@ static void fixup_exception_return(struct cpu_user_regs *regs, + /* + * Search for %rip. The shstk currently looks like this: + * +- * ... [Likely pointed to by SSP] ++ * tok [Supervisor token, == &tok | BUSY, only with FRED inactive] ++ * ... [Pointed to by SSP for most exceptions, empty in IST cases] + * %cs [== regs->cs] + * %rip [== regs->rip] + * SSP [Likely points to 3 slots higher, above %cs] +@@ -891,7 +892,56 @@ static void fixup_exception_return(struct cpu_user_regs *regs, + */ + if ( ptr[0] == regs->rip && ptr[1] == regs->cs ) + { ++ unsigned long primary_shstk = ++ (ssp & ~(STACK_SIZE - 1)) + ++ (PRIMARY_SHSTK_SLOT + 1) * PAGE_SIZE - 8; ++ + wrss(fixup, ptr); ++ ++ if ( !stub_ra ) ++ goto shstk_done; ++ ++ /* ++ * Stub recovery ought to happen only when the outer context ++ * was on the main shadow stack. We need to also "pop" the ++ * stub's return address from the interrupted context's shadow ++ * stack. That is, ++ * - if we're still on the main stack, we need to move the ++ * entire stack (up to and including the exception frame) ++ * up by one slot, incrementing the original SSP in the ++ * exception frame, ++ * - if we're on an IST stack, we need to increment the ++ * original SSP. ++ */ ++ BUG_ON((ptr[-1] ^ primary_shstk) >> PAGE_SHIFT); ++ ++ if ( (ssp ^ primary_shstk) >> PAGE_SHIFT ) ++ { ++ /* ++ * We're on an IST stack. First make sure the two return ++ * addresses actually match. Then increment the interrupted ++ * context's SSP. ++ */ ++ BUG_ON(stub_ra != *(unsigned long*)ptr[-1]); ++ wrss(ptr[-1] + 8, &ptr[-1]); ++ goto shstk_done; ++ } ++ ++ /* Make sure the two return addresses actually match. */ ++ BUG_ON(stub_ra != ptr[2]); ++ ++ /* Move exception frame, updating SSP there. */ ++ wrss(ptr[1], &ptr[2]); /* %cs */ ++ wrss(ptr[0], &ptr[1]); /* %rip */ ++ wrss(ptr[-1] + 8, &ptr[0]); /* SSP */ ++ ++ /* Move all newer entries. */ ++ while ( --ptr != _p(ssp) ) ++ wrss(ptr[-1], &ptr[0]); ++ ++ /* Finally account for our own stack having shifted up. */ ++ asm volatile ( "incsspd %0" :: "r" (2) ); ++ + goto shstk_done; + } + } +@@ -912,7 +962,8 @@ static void fixup_exception_return(struct cpu_user_regs *regs, + + static bool extable_fixup(struct cpu_user_regs *regs, bool print) + { +- unsigned long fixup = search_exception_table(regs); ++ unsigned long stub_ra = 0; ++ unsigned long fixup = search_exception_table(regs, &stub_ra); + + if ( unlikely(fixup == 0) ) + return false; +@@ -926,7 +977,7 @@ static bool extable_fixup(struct cpu_user_regs *regs, bool print) + vector_name(regs->entry_vector), regs->error_code, + _p(regs->rip), _p(regs->rip), _p(fixup)); + +- fixup_exception_return(regs, fixup); ++ fixup_exception_return(regs, fixup, stub_ra); + this_cpu(last_extable_addr) = regs->rip; + + return true; +@@ -1214,7 +1265,7 @@ void do_invalid_op(struct cpu_user_regs *regs) + void (*fn)(struct cpu_user_regs *) = bug_ptr(bug); + + fn(regs); +- fixup_exception_return(regs, (unsigned long)eip); ++ fixup_exception_return(regs, (unsigned long)eip, 0); + return; + } + +@@ -1235,7 +1286,7 @@ void do_invalid_op(struct cpu_user_regs *regs) + case BUGFRAME_warn: + printk("Xen WARN at %s%s:%d\n", prefix, filename, lineno); + show_execution_state(regs); +- fixup_exception_return(regs, (unsigned long)eip); ++ fixup_exception_return(regs, (unsigned long)eip, 0); + return; + + case BUGFRAME_bug: +-- +2.44.0 + |