amd64: check that %cs and %ss values from ucontext fit into registers
This change only checks that the values from the user-supplied context are not truncated by C implicit type convertions. The validity of the segment selectors is still checked by hardware. Reviewed by: jhb, markj Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D55861
This commit is contained in:
@@ -94,6 +94,15 @@ _Static_assert(sizeof(mcontext_t) == 800, "mcontext_t size incorrect");
|
||||
_Static_assert(sizeof(ucontext_t) == 880, "ucontext_t size incorrect");
|
||||
_Static_assert(sizeof(siginfo_t) == 80, "siginfo_t size incorrect");
|
||||
|
||||
/*
|
||||
* Check that the value r is 16bit, i.e. fits into a segment register.
|
||||
*/
|
||||
static bool
|
||||
is_seg_val(register_t r)
|
||||
{
|
||||
return ((uint64_t)r <= 0xffff);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send an interrupt to process.
|
||||
*
|
||||
@@ -262,6 +271,14 @@ sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
if (!is_seg_val(ucp->uc_mcontext.mc_ss) ||
|
||||
!is_seg_val(ucp->uc_mcontext.mc_cs)) {
|
||||
uprintf("pid %d (%s): sigreturn cs = %#lx ss = %#lx\n",
|
||||
p->p_pid, td->td_name, ucp->uc_mcontext.mc_cs,
|
||||
ucp->uc_mcontext.mc_ss);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't allow users to load a valid privileged %cs. Let the
|
||||
* hardware check for invalid selectors, excess privilege in
|
||||
@@ -659,6 +676,8 @@ set_mcontext(struct thread *td, mcontext_t *mcp)
|
||||
if (mcp->mc_len != sizeof(*mcp) ||
|
||||
(mcp->mc_flags & ~_MC_FLAG_MASK) != 0)
|
||||
return (EINVAL);
|
||||
if (!is_seg_val(mcp->mc_ss) || !is_seg_val(mcp->mc_cs))
|
||||
return (EINVAL);
|
||||
rflags = (mcp->mc_rflags & PSL_USERCHANGE) |
|
||||
(tp->tf_rflags & ~PSL_USERCHANGE);
|
||||
if (mcp->mc_flags & _MC_HASFPXSTATE) {
|
||||
|
||||
@@ -88,6 +88,15 @@ extern char _binary_elf_vdso32_so_1_size;
|
||||
static void freebsd4_ia32_sendsig(sig_t, ksiginfo_t *, sigset_t *);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check that the value r is 16bit, i.e. fits into a segment register.
|
||||
*/
|
||||
static bool
|
||||
is_seg_val(uint32_t r)
|
||||
{
|
||||
return (r <= 0xffff);
|
||||
}
|
||||
|
||||
static void
|
||||
ia32_get_fpcontext(struct thread *td, struct ia32_mcontext *mcp,
|
||||
char **xfpusave, size_t *xfpusave_len)
|
||||
@@ -205,6 +214,8 @@ ia32_set_mcontext(struct thread *td, struct ia32_mcontext *mcp)
|
||||
tp = td->td_frame;
|
||||
if (mcp->mc_len != sizeof(*mcp))
|
||||
return (EINVAL);
|
||||
if (!is_seg_val(mcp->mc_ss) || !is_seg_val(mcp->mc_cs))
|
||||
return (EINVAL);
|
||||
rflags = (mcp->mc_eflags & PSL_USERCHANGE) |
|
||||
(tp->tf_rflags & ~PSL_USERCHANGE);
|
||||
if (mcp->mc_flags & _MC_IA32_HASFPXSTATE) {
|
||||
@@ -707,6 +718,8 @@ ofreebsd32_sigreturn(struct thread *td, struct ofreebsd32_sigreturn_args *uap)
|
||||
if (!EFL_SECURE(eflags, regs->tf_rflags)) {
|
||||
return (EINVAL);
|
||||
}
|
||||
if (!is_seg_val(scp->sc_ss) || !is_seg_val(scp->sc_cs))
|
||||
return (EINVAL);
|
||||
if (!CS_SECURE(scp->sc_cs)) {
|
||||
ksiginfo_init_trap(&ksi);
|
||||
ksi.ksi_signo = SIGBUS;
|
||||
@@ -772,6 +785,13 @@ freebsd4_freebsd32_sigreturn(struct thread *td,
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
if (!is_seg_val(ucp->uc_mcontext.mc_ss) ||
|
||||
!is_seg_val(ucp->uc_mcontext.mc_cs)) {
|
||||
uprintf("pid %d (%s): sigreturn cs = %#x ss = %#x\n",
|
||||
td->td_proc->p_pid, td->td_name, ucp->uc_mcontext.mc_cs,
|
||||
ucp->uc_mcontext.mc_ss);
|
||||
return (EINVAL);
|
||||
}
|
||||
/*
|
||||
* Don't allow users to load a valid privileged %cs. Let the
|
||||
* hardware check for invalid selectors, excess privilege in
|
||||
@@ -841,6 +861,14 @@ freebsd32_sigreturn(struct thread *td, struct freebsd32_sigreturn_args *uap)
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
if (!is_seg_val(ucp->uc_mcontext.mc_ss) ||
|
||||
!is_seg_val(ucp->uc_mcontext.mc_cs)) {
|
||||
uprintf("pid %d (%s): sigreturn cs = %#x ss = %#x\n",
|
||||
td->td_proc->p_pid, td->td_name, ucp->uc_mcontext.mc_cs,
|
||||
ucp->uc_mcontext.mc_ss);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't allow users to load a valid privileged %cs. Let the
|
||||
* hardware check for invalid selectors, excess privilege in
|
||||
|
||||
Reference in New Issue
Block a user