Date: Thu, 23 Sep 2021 21:49:47 +0200 From: Mateusz Guzik <mjguzik@gmail.com> To: Konstantin Belousov <kib@freebsd.org> Cc: src-committers@freebsd.org, dev-commits-src-all@freebsd.org, dev-commits-src-main@freebsd.org Subject: Re: git: df8dd6025af8 - main - amd64: stop using top of the thread' kernel stack for FPU user save area Message-ID: <CAGudoHGE9YHLTMtm9XuV7yqZVXbjb%2BDJNOUAkMHmeaDjYmQG6g@mail.gmail.com> In-Reply-To: <202109211721.18LHLFWM028927@gitrepo.freebsd.org> References: <202109211721.18LHLFWM028927@gitrepo.freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On 9/21/21, Konstantin Belousov <kib@freebsd.org> wrote: > The branch main has been updated by kib: > > URL: > https://cgit.FreeBSD.org/src/commit/?id=df8dd6025af88a99d34f549fa9591a9b8f9b75b1 > > commit df8dd6025af88a99d34f549fa9591a9b8f9b75b1 > Author: Konstantin Belousov <kib@FreeBSD.org> > AuthorDate: 2021-09-13 21:05:47 +0000 > Commit: Konstantin Belousov <kib@FreeBSD.org> > CommitDate: 2021-09-21 17:20:15 +0000 > > amd64: stop using top of the thread' kernel stack for FPU user save > area > This causes KASAN to crash on boot: panic: ASan: Invalid access, 192-byte read at 0xffffffff84105f40, UseAfterScope(f8) cpuid = 0 time = 1 KDB: stack backtrace: db_trace_self_wrapper() at db_trace_self_wrapper+0xa5/frame 0xffffffff841056f0 kdb_backtrace() at kdb_backtrace+0xc9/frame 0xffffffff84105850 vpanic() at vpanic+0x248/frame 0xffffffff84105930 panic() at panic+0xb5/frame 0xffffffff841059f0 kasan_memmove() at kasan_memmove+0x313/frame 0xffffffff84105ac0 cpu_fork() at cpu_fork+0x19b/frame 0xffffffff84105b30 vm_forkproc() at vm_forkproc+0x18f/frame 0xffffffff84105b90 fork1() at fork1+0x1ff4/frame 0xffffffff84105d10 kproc_create() at kproc_create+0x166/frame 0xffffffff84105eb0 audit_worker_init() at audit_worker_init+0x41/frame 0xffffffff84105ed0 mi_startup() at mi_startup+0x340/frame 0xffffffff84105ff0 btext() at btext+0x22 > Instead do one more allocation at the thread creation time. This frees > a lot of space on the stack. > > Also do not use alloca() for temporal storage in signal delivery > sendsig() > function and signal return syscall sys_sigreturn(). This saves equal > amount of space, again by the cost of one more allocation at the thread > creation time. > > A useful experiment now would be to reduce KSTACK_PAGES. > > Reviewed by: jhb, markj > Tested by: pho > Sponsored by: The FreeBSD Foundation > MFC after: 1 week > Differential revision: https://reviews.freebsd.org/D31954 > --- > sys/amd64/amd64/exec_machdep.c | 4 ++-- > sys/amd64/amd64/fpu.c | 2 ++ > sys/amd64/amd64/machdep.c | 14 -------------- > sys/amd64/amd64/vm_machdep.c | 22 +++++++++++++--------- > sys/amd64/ia32/ia32_signal.c | 6 +++--- > sys/amd64/include/proc.h | 2 ++ > sys/kern/kern_thread.c | 2 +- > 7 files changed, 23 insertions(+), 29 deletions(-) > > diff --git a/sys/amd64/amd64/exec_machdep.c > b/sys/amd64/amd64/exec_machdep.c > index 1297117638d6..48bda05f9685 100644 > --- a/sys/amd64/amd64/exec_machdep.c > +++ b/sys/amd64/amd64/exec_machdep.c > @@ -135,7 +135,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) > > if (cpu_max_ext_state_size > sizeof(struct savefpu) && use_xsave) { > xfpusave_len = cpu_max_ext_state_size - sizeof(struct savefpu); > - xfpusave = __builtin_alloca(xfpusave_len); > + xfpusave = (char *)td->td_md.md_fpu_scratch; > } else { > xfpusave_len = 0; > xfpusave = NULL; > @@ -674,7 +674,7 @@ set_mcontext(struct thread *td, mcontext_t *mcp) > if (mcp->mc_xfpustate_len > cpu_max_ext_state_size - > sizeof(struct savefpu)) > return (EINVAL); > - xfpustate = __builtin_alloca(mcp->mc_xfpustate_len); > + xfpustate = (char *)td->td_md.md_fpu_scratch; > ret = copyin((void *)mcp->mc_xfpustate, xfpustate, > mcp->mc_xfpustate_len); > if (ret != 0) > diff --git a/sys/amd64/amd64/fpu.c b/sys/amd64/amd64/fpu.c > index d7936b3b1922..24986958d4ca 100644 > --- a/sys/amd64/amd64/fpu.c > +++ b/sys/amd64/amd64/fpu.c > @@ -448,6 +448,8 @@ fpuinitstate(void *arg __unused) > xsave_area_elm_descr), M_DEVBUF, M_WAITOK | M_ZERO); > } > > + cpu_thread_alloc(&thread0); > + > saveintr = intr_disable(); > stop_emulating(); > > diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c > index d4e2356a9ae1..5c9b64526609 100644 > --- a/sys/amd64/amd64/machdep.c > +++ b/sys/amd64/amd64/machdep.c > @@ -1258,7 +1258,6 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) > caddr_t kmdp; > int gsel_tss, x; > struct pcpu *pc; > - struct xstate_hdr *xhdr; > uint64_t cr3, rsp0; > pml4_entry_t *pml4e; > pdp_entry_t *pdpe; > @@ -1564,19 +1563,6 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) > msgbufinit(msgbufp, msgbufsize); > fpuinit(); > > - /* > - * Reinitialize thread0's stack base now that the xsave area size is > - * known. Set up thread0's pcb save area after fpuinit calculated fpu > - * save area size. Zero out the extended state header in fpu save area. > - */ > - set_top_of_stack_td(&thread0); > - thread0.td_pcb->pcb_save = get_pcb_user_save_td(&thread0); > - bzero(thread0.td_pcb->pcb_save, cpu_max_ext_state_size); > - if (use_xsave) { > - xhdr = (struct xstate_hdr *)(get_pcb_user_save_td(&thread0) + > - 1); > - xhdr->xstate_bv = xsave_mask; > - } > /* make an initial tss so cpu can get interrupt stack on syscall! */ > rsp0 = thread0.td_md.md_stack_base; > /* Ensure the stack is aligned to 16 bytes */ > diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c > index 4567e6e0eb5d..e42d16d61b3a 100644 > --- a/sys/amd64/amd64/vm_machdep.c > +++ b/sys/amd64/amd64/vm_machdep.c > @@ -90,19 +90,17 @@ void > set_top_of_stack_td(struct thread *td) > { > td->td_md.md_stack_base = td->td_kstack + > - td->td_kstack_pages * PAGE_SIZE - > - roundup2(cpu_max_ext_state_size, XSAVE_AREA_ALIGN); > + td->td_kstack_pages * PAGE_SIZE; > } > > struct savefpu * > get_pcb_user_save_td(struct thread *td) > { > - vm_offset_t p; > - > - p = td->td_md.md_stack_base; > - KASSERT((p % XSAVE_AREA_ALIGN) == 0, > - ("Unaligned pcb_user_save area ptr %#lx td %p", p, td)); > - return ((struct savefpu *)p); > + KASSERT(((vm_offset_t)td->td_md.md_usr_fpu_save % > + XSAVE_AREA_ALIGN) == 0, > + ("Unaligned pcb_user_save area ptr %p td %p", > + td->td_md.md_usr_fpu_save, td)); > + return (td->td_md.md_usr_fpu_save); > } > > struct pcb * > @@ -393,6 +391,8 @@ cpu_thread_alloc(struct thread *td) > set_top_of_stack_td(td); > td->td_pcb = pcb = get_pcb_td(td); > td->td_frame = (struct trapframe *)td->td_md.md_stack_base - 1; > + td->td_md.md_usr_fpu_save = fpu_save_area_alloc(); > + td->td_md.md_fpu_scratch = fpu_save_area_alloc(); > pcb->pcb_save = get_pcb_user_save_pcb(pcb); > if (use_xsave) { > xhdr = (struct xstate_hdr *)(pcb->pcb_save + 1); > @@ -404,8 +404,12 @@ cpu_thread_alloc(struct thread *td) > void > cpu_thread_free(struct thread *td) > { > - > cpu_thread_clean(td); > + > + fpu_save_area_free(td->td_md.md_usr_fpu_save); > + td->td_md.md_usr_fpu_save = NULL; > + fpu_save_area_free(td->td_md.md_fpu_scratch); > + td->td_md.md_fpu_scratch = NULL; > } > > bool > diff --git a/sys/amd64/ia32/ia32_signal.c b/sys/amd64/ia32/ia32_signal.c > index 49b5797d68fd..9b67c7001a87 100644 > --- a/sys/amd64/ia32/ia32_signal.c > +++ b/sys/amd64/ia32/ia32_signal.c > @@ -210,7 +210,7 @@ ia32_set_mcontext(struct thread *td, struct > ia32_mcontext *mcp) > if (mcp->mc_xfpustate_len > cpu_max_ext_state_size - > sizeof(struct savefpu)) > return (EINVAL); > - xfpustate = __builtin_alloca(mcp->mc_xfpustate_len); > + xfpustate = (char *)td->td_md.md_fpu_scratch; > ret = copyin(PTRIN(mcp->mc_xfpustate), xfpustate, > mcp->mc_xfpustate_len); > if (ret != 0) > @@ -579,7 +579,7 @@ ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t > *mask) > > if (cpu_max_ext_state_size > sizeof(struct savefpu) && use_xsave) { > xfpusave_len = cpu_max_ext_state_size - sizeof(struct savefpu); > - xfpusave = __builtin_alloca(xfpusave_len); > + xfpusave = (char *)td->td_md.md_fpu_scratch; > } else { > xfpusave_len = 0; > xfpusave = NULL; > @@ -882,7 +882,7 @@ freebsd32_sigreturn(td, uap) > td->td_proc->p_pid, td->td_name, xfpustate_len); > return (EINVAL); > } > - xfpustate = __builtin_alloca(xfpustate_len); > + xfpustate = (char *)td->td_md.md_fpu_scratch; > error = copyin(PTRIN(ucp->uc_mcontext.mc_xfpustate), > xfpustate, xfpustate_len); > if (error != 0) { > diff --git a/sys/amd64/include/proc.h b/sys/amd64/include/proc.h > index 0f8cf50e326d..bd07f70f8d44 100644 > --- a/sys/amd64/include/proc.h > +++ b/sys/amd64/include/proc.h > @@ -75,6 +75,8 @@ struct mdthread { > int md_efirt_dis_pf; /* (k) */ > struct pcb md_pcb; > vm_offset_t md_stack_base; > + struct savefpu *md_usr_fpu_save; > + struct savefpu *md_fpu_scratch; > }; > > struct mdproc { > diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c > index 65c5cc65c87e..62f939406374 100644 > --- a/sys/kern/kern_thread.c > +++ b/sys/kern/kern_thread.c > @@ -91,7 +91,7 @@ _Static_assert(offsetof(struct thread, td_pflags) == > 0x110, > "struct thread KBI td_pflags"); > _Static_assert(offsetof(struct thread, td_frame) == 0x4a8, > "struct thread KBI td_frame"); > -_Static_assert(offsetof(struct thread, td_emuldata) == 0x6b0, > +_Static_assert(offsetof(struct thread, td_emuldata) == 0x6c0, > "struct thread KBI td_emuldata"); > _Static_assert(offsetof(struct proc, p_flag) == 0xb8, > "struct proc KBI p_flag"); > -- Mateusz Guzik <mjguzik gmail.com>
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAGudoHGE9YHLTMtm9XuV7yqZVXbjb%2BDJNOUAkMHmeaDjYmQG6g>