Re: [PATCH 3.2 091/102] KVM: x86: Emulator fixes for eip canonical checks on near branches
On Sun, 2014-11-02 at 10:44 +0200, Nadav Amit wrote: > Sorry, but this patch is incomplete due to a bug. > The following patch - http://www.spinics.net/lists/kvm/msg109664.html - is > needed as well (on top of the previous one). Thanks, I've added that (commit 7e466f6c). Ben. > Nadav > > > On Nov 2, 2014, at 00:28, Ben Hutchings wrote: > > > > 3.2.64-rc1 review patch. If anyone has any objections, please let me know. > > > > -- > > > > From: Nadav Amit > > > > commit 234f3ce485d54017f15cf5e0699cff4100121601 upstream. > > > > Before changing rip (during jmp, call, ret, etc.) the target should be > > asserted > > to be canonical one, as real CPUs do. During sysret, both target rsp and > > rip > > should be canonical. If any of these values is noncanonical, a #GP exception > > should occur. The exception to this rule are syscall and sysenter > > instructions > > in which the assigned rip is checked during the assignment to the relevant > > MSRs. > > > > This patch fixes the emulator to behave as real CPUs do for near branches. > > Far branches are handled by the next patch. > > > > This fixes CVE-2014-3647. > > > > Signed-off-by: Nadav Amit > > Signed-off-by: Paolo Bonzini > > [bwh: Backported to 3.2: > > - Adjust context > > - Use ctxt->regs[] instead of reg_read(), reg_write(), reg_rmw()] > > Signed-off-by: Ben Hutchings > > --- > > arch/x86/kvm/emulate.c | 78 > > ++ > > 1 file changed, 54 insertions(+), 24 deletions(-) > > > > --- a/arch/x86/kvm/emulate.c > > +++ b/arch/x86/kvm/emulate.c > > @@ -529,7 +529,8 @@ static int emulate_nm(struct x86_emulate > > return emulate_exception(ctxt, NM_VECTOR, 0, false); > > } > > > > -static inline void assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong > > dst) > > +static inline int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst, > > + int cs_l) > > { > > switch (ctxt->op_bytes) { > > case 2: > > @@ -539,16 +540,25 @@ static inline void assign_eip_near(struc > > ctxt->_eip = (u32)dst; > > break; > > case 8: > > + if ((cs_l && is_noncanonical_address(dst)) || > > + (!cs_l && (dst & ~(u32)-1))) > > + return emulate_gp(ctxt, 0); > > ctxt->_eip = dst; > > break; > > default: > > WARN(1, "unsupported eip assignment size\n"); > > } > > + return X86EMUL_CONTINUE; > > +} > > + > > +static inline int assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong dst) > > +{ > > + return assign_eip_far(ctxt, dst, ctxt->mode == X86EMUL_MODE_PROT64); > > } > > > > -static inline void jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) > > +static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) > > { > > - assign_eip_near(ctxt, ctxt->_eip + rel); > > + return assign_eip_near(ctxt, ctxt->_eip + rel); > > } > > > > static u16 get_segment_selector(struct x86_emulate_ctxt *ctxt, unsigned seg) > > @@ -1787,13 +1797,15 @@ static int em_grp45(struct x86_emulate_c > > case 2: /* call near abs */ { > > long int old_eip; > > old_eip = ctxt->_eip; > > - ctxt->_eip = ctxt->src.val; > > + rc = assign_eip_near(ctxt, ctxt->src.val); > > + if (rc != X86EMUL_CONTINUE) > > + break; > > ctxt->src.val = old_eip; > > rc = em_push(ctxt); > > break; > > } > > case 4: /* jmp abs */ > > - ctxt->_eip = ctxt->src.val; > > + rc = assign_eip_near(ctxt, ctxt->src.val); > > break; > > case 5: /* jmp far */ > > rc = em_jmp_far(ctxt); > > @@ -1825,10 +1837,14 @@ static int em_grp9(struct x86_emulate_ct > > > > static int em_ret(struct x86_emulate_ctxt *ctxt) > > { > > - ctxt->dst.type = OP_REG; > > - ctxt->dst.addr.reg = >_eip; > > - ctxt->dst.bytes = ctxt->op_bytes; > > - return em_pop(ctxt); > > + int rc; > > + unsigned long eip; > > + > > + rc = emulate_pop(ctxt, , ctxt->op_bytes); > > + if (rc != X86EMUL_CONTINUE) > > + return rc; > > + > > + return assign_eip_near(ctxt, eip); > > } > > > > static int em_ret_far(struct x86_emulate_ctxt *ctxt) > > @@ -2060,7 +2076,7 @@ static int em_sysexit(struct x86_emulate > > { > > struct x86_emulate_ops *ops = ctxt->ops; > > struct desc_struct cs, ss; > > - u64 msr_data; > > + u64 msr_data, rcx, rdx; > > int usermode; > > u16 cs_sel = 0, ss_sel = 0; > > > > @@ -2076,6 +2092,9 @@ static int em_sysexit(struct x86_emulate > > else > > usermode = X86EMUL_MODE_PROT32; > > > > + rcx = ctxt->regs[VCPU_REGS_RCX]; > > + rdx = ctxt->regs[VCPU_REGS_RDX]; > > + > > cs.dpl = 3; > > ss.dpl = 3; > > ops->get_msr(ctxt, MSR_IA32_SYSENTER_CS, _data); > > @@ -2093,6 +2112,9 @@ static int em_sysexit(struct x86_emulate > > ss_sel = cs_sel + 8; > > cs.d = 0; >
Re: [PATCH 3.2 091/102] KVM: x86: Emulator fixes for eip canonical checks on near branches
On Sun, 2014-11-02 at 10:44 +0200, Nadav Amit wrote: Sorry, but this patch is incomplete due to a bug. The following patch - http://www.spinics.net/lists/kvm/msg109664.html - is needed as well (on top of the previous one). Thanks, I've added that (commit 7e466f6c). Ben. Nadav On Nov 2, 2014, at 00:28, Ben Hutchings b...@decadent.org.uk wrote: 3.2.64-rc1 review patch. If anyone has any objections, please let me know. -- From: Nadav Amit na...@cs.technion.ac.il commit 234f3ce485d54017f15cf5e0699cff4100121601 upstream. Before changing rip (during jmp, call, ret, etc.) the target should be asserted to be canonical one, as real CPUs do. During sysret, both target rsp and rip should be canonical. If any of these values is noncanonical, a #GP exception should occur. The exception to this rule are syscall and sysenter instructions in which the assigned rip is checked during the assignment to the relevant MSRs. This patch fixes the emulator to behave as real CPUs do for near branches. Far branches are handled by the next patch. This fixes CVE-2014-3647. Signed-off-by: Nadav Amit na...@cs.technion.ac.il Signed-off-by: Paolo Bonzini pbonz...@redhat.com [bwh: Backported to 3.2: - Adjust context - Use ctxt-regs[] instead of reg_read(), reg_write(), reg_rmw()] Signed-off-by: Ben Hutchings b...@decadent.org.uk --- arch/x86/kvm/emulate.c | 78 ++ 1 file changed, 54 insertions(+), 24 deletions(-) --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -529,7 +529,8 @@ static int emulate_nm(struct x86_emulate return emulate_exception(ctxt, NM_VECTOR, 0, false); } -static inline void assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong dst) +static inline int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst, + int cs_l) { switch (ctxt-op_bytes) { case 2: @@ -539,16 +540,25 @@ static inline void assign_eip_near(struc ctxt-_eip = (u32)dst; break; case 8: + if ((cs_l is_noncanonical_address(dst)) || + (!cs_l (dst ~(u32)-1))) + return emulate_gp(ctxt, 0); ctxt-_eip = dst; break; default: WARN(1, unsupported eip assignment size\n); } + return X86EMUL_CONTINUE; +} + +static inline int assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong dst) +{ + return assign_eip_far(ctxt, dst, ctxt-mode == X86EMUL_MODE_PROT64); } -static inline void jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) +static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) { - assign_eip_near(ctxt, ctxt-_eip + rel); + return assign_eip_near(ctxt, ctxt-_eip + rel); } static u16 get_segment_selector(struct x86_emulate_ctxt *ctxt, unsigned seg) @@ -1787,13 +1797,15 @@ static int em_grp45(struct x86_emulate_c case 2: /* call near abs */ { long int old_eip; old_eip = ctxt-_eip; - ctxt-_eip = ctxt-src.val; + rc = assign_eip_near(ctxt, ctxt-src.val); + if (rc != X86EMUL_CONTINUE) + break; ctxt-src.val = old_eip; rc = em_push(ctxt); break; } case 4: /* jmp abs */ - ctxt-_eip = ctxt-src.val; + rc = assign_eip_near(ctxt, ctxt-src.val); break; case 5: /* jmp far */ rc = em_jmp_far(ctxt); @@ -1825,10 +1837,14 @@ static int em_grp9(struct x86_emulate_ct static int em_ret(struct x86_emulate_ctxt *ctxt) { - ctxt-dst.type = OP_REG; - ctxt-dst.addr.reg = ctxt-_eip; - ctxt-dst.bytes = ctxt-op_bytes; - return em_pop(ctxt); + int rc; + unsigned long eip; + + rc = emulate_pop(ctxt, eip, ctxt-op_bytes); + if (rc != X86EMUL_CONTINUE) + return rc; + + return assign_eip_near(ctxt, eip); } static int em_ret_far(struct x86_emulate_ctxt *ctxt) @@ -2060,7 +2076,7 @@ static int em_sysexit(struct x86_emulate { struct x86_emulate_ops *ops = ctxt-ops; struct desc_struct cs, ss; - u64 msr_data; + u64 msr_data, rcx, rdx; int usermode; u16 cs_sel = 0, ss_sel = 0; @@ -2076,6 +2092,9 @@ static int em_sysexit(struct x86_emulate else usermode = X86EMUL_MODE_PROT32; + rcx = ctxt-regs[VCPU_REGS_RCX]; + rdx = ctxt-regs[VCPU_REGS_RDX]; + cs.dpl = 3; ss.dpl = 3; ops-get_msr(ctxt, MSR_IA32_SYSENTER_CS, msr_data); @@ -2093,6 +2112,9 @@ static int em_sysexit(struct x86_emulate ss_sel = cs_sel + 8; cs.d = 0; cs.l = 1; + if (is_noncanonical_address(rcx) || + is_noncanonical_address(rdx)) + return emulate_gp(ctxt, 0); break;
Re: [PATCH 3.2 091/102] KVM: x86: Emulator fixes for eip canonical checks on near branches
Sorry, but this patch is incomplete due to a bug. The following patch - http://www.spinics.net/lists/kvm/msg109664.html - is needed as well (on top of the previous one). Nadav > On Nov 2, 2014, at 00:28, Ben Hutchings wrote: > > 3.2.64-rc1 review patch. If anyone has any objections, please let me know. > > -- > > From: Nadav Amit > > commit 234f3ce485d54017f15cf5e0699cff4100121601 upstream. > > Before changing rip (during jmp, call, ret, etc.) the target should be > asserted > to be canonical one, as real CPUs do. During sysret, both target rsp and rip > should be canonical. If any of these values is noncanonical, a #GP exception > should occur. The exception to this rule are syscall and sysenter > instructions > in which the assigned rip is checked during the assignment to the relevant > MSRs. > > This patch fixes the emulator to behave as real CPUs do for near branches. > Far branches are handled by the next patch. > > This fixes CVE-2014-3647. > > Signed-off-by: Nadav Amit > Signed-off-by: Paolo Bonzini > [bwh: Backported to 3.2: > - Adjust context > - Use ctxt->regs[] instead of reg_read(), reg_write(), reg_rmw()] > Signed-off-by: Ben Hutchings > --- > arch/x86/kvm/emulate.c | 78 ++ > 1 file changed, 54 insertions(+), 24 deletions(-) > > --- a/arch/x86/kvm/emulate.c > +++ b/arch/x86/kvm/emulate.c > @@ -529,7 +529,8 @@ static int emulate_nm(struct x86_emulate > return emulate_exception(ctxt, NM_VECTOR, 0, false); > } > > -static inline void assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong dst) > +static inline int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst, > +int cs_l) > { > switch (ctxt->op_bytes) { > case 2: > @@ -539,16 +540,25 @@ static inline void assign_eip_near(struc > ctxt->_eip = (u32)dst; > break; > case 8: > + if ((cs_l && is_noncanonical_address(dst)) || > + (!cs_l && (dst & ~(u32)-1))) > + return emulate_gp(ctxt, 0); > ctxt->_eip = dst; > break; > default: > WARN(1, "unsupported eip assignment size\n"); > } > + return X86EMUL_CONTINUE; > +} > + > +static inline int assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong dst) > +{ > + return assign_eip_far(ctxt, dst, ctxt->mode == X86EMUL_MODE_PROT64); > } > > -static inline void jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) > +static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) > { > - assign_eip_near(ctxt, ctxt->_eip + rel); > + return assign_eip_near(ctxt, ctxt->_eip + rel); > } > > static u16 get_segment_selector(struct x86_emulate_ctxt *ctxt, unsigned seg) > @@ -1787,13 +1797,15 @@ static int em_grp45(struct x86_emulate_c > case 2: /* call near abs */ { > long int old_eip; > old_eip = ctxt->_eip; > - ctxt->_eip = ctxt->src.val; > + rc = assign_eip_near(ctxt, ctxt->src.val); > + if (rc != X86EMUL_CONTINUE) > + break; > ctxt->src.val = old_eip; > rc = em_push(ctxt); > break; > } > case 4: /* jmp abs */ > - ctxt->_eip = ctxt->src.val; > + rc = assign_eip_near(ctxt, ctxt->src.val); > break; > case 5: /* jmp far */ > rc = em_jmp_far(ctxt); > @@ -1825,10 +1837,14 @@ static int em_grp9(struct x86_emulate_ct > > static int em_ret(struct x86_emulate_ctxt *ctxt) > { > - ctxt->dst.type = OP_REG; > - ctxt->dst.addr.reg = >_eip; > - ctxt->dst.bytes = ctxt->op_bytes; > - return em_pop(ctxt); > + int rc; > + unsigned long eip; > + > + rc = emulate_pop(ctxt, , ctxt->op_bytes); > + if (rc != X86EMUL_CONTINUE) > + return rc; > + > + return assign_eip_near(ctxt, eip); > } > > static int em_ret_far(struct x86_emulate_ctxt *ctxt) > @@ -2060,7 +2076,7 @@ static int em_sysexit(struct x86_emulate > { > struct x86_emulate_ops *ops = ctxt->ops; > struct desc_struct cs, ss; > - u64 msr_data; > + u64 msr_data, rcx, rdx; > int usermode; > u16 cs_sel = 0, ss_sel = 0; > > @@ -2076,6 +2092,9 @@ static int em_sysexit(struct x86_emulate > else > usermode = X86EMUL_MODE_PROT32; > > + rcx = ctxt->regs[VCPU_REGS_RCX]; > + rdx = ctxt->regs[VCPU_REGS_RDX]; > + > cs.dpl = 3; > ss.dpl = 3; > ops->get_msr(ctxt, MSR_IA32_SYSENTER_CS, _data); > @@ -2093,6 +2112,9 @@ static int em_sysexit(struct x86_emulate > ss_sel = cs_sel + 8; > cs.d = 0; > cs.l = 1; > + if (is_noncanonical_address(rcx) || > + is_noncanonical_address(rdx)) > + return emulate_gp(ctxt, 0); > break; > } > cs_sel |= SELECTOR_RPL_MASK; > @@ -2101,8 +2123,8 @@
Re: [PATCH 3.2 091/102] KVM: x86: Emulator fixes for eip canonical checks on near branches
Sorry, but this patch is incomplete due to a bug. The following patch - http://www.spinics.net/lists/kvm/msg109664.html - is needed as well (on top of the previous one). Nadav On Nov 2, 2014, at 00:28, Ben Hutchings b...@decadent.org.uk wrote: 3.2.64-rc1 review patch. If anyone has any objections, please let me know. -- From: Nadav Amit na...@cs.technion.ac.il commit 234f3ce485d54017f15cf5e0699cff4100121601 upstream. Before changing rip (during jmp, call, ret, etc.) the target should be asserted to be canonical one, as real CPUs do. During sysret, both target rsp and rip should be canonical. If any of these values is noncanonical, a #GP exception should occur. The exception to this rule are syscall and sysenter instructions in which the assigned rip is checked during the assignment to the relevant MSRs. This patch fixes the emulator to behave as real CPUs do for near branches. Far branches are handled by the next patch. This fixes CVE-2014-3647. Signed-off-by: Nadav Amit na...@cs.technion.ac.il Signed-off-by: Paolo Bonzini pbonz...@redhat.com [bwh: Backported to 3.2: - Adjust context - Use ctxt-regs[] instead of reg_read(), reg_write(), reg_rmw()] Signed-off-by: Ben Hutchings b...@decadent.org.uk --- arch/x86/kvm/emulate.c | 78 ++ 1 file changed, 54 insertions(+), 24 deletions(-) --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -529,7 +529,8 @@ static int emulate_nm(struct x86_emulate return emulate_exception(ctxt, NM_VECTOR, 0, false); } -static inline void assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong dst) +static inline int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst, +int cs_l) { switch (ctxt-op_bytes) { case 2: @@ -539,16 +540,25 @@ static inline void assign_eip_near(struc ctxt-_eip = (u32)dst; break; case 8: + if ((cs_l is_noncanonical_address(dst)) || + (!cs_l (dst ~(u32)-1))) + return emulate_gp(ctxt, 0); ctxt-_eip = dst; break; default: WARN(1, unsupported eip assignment size\n); } + return X86EMUL_CONTINUE; +} + +static inline int assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong dst) +{ + return assign_eip_far(ctxt, dst, ctxt-mode == X86EMUL_MODE_PROT64); } -static inline void jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) +static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) { - assign_eip_near(ctxt, ctxt-_eip + rel); + return assign_eip_near(ctxt, ctxt-_eip + rel); } static u16 get_segment_selector(struct x86_emulate_ctxt *ctxt, unsigned seg) @@ -1787,13 +1797,15 @@ static int em_grp45(struct x86_emulate_c case 2: /* call near abs */ { long int old_eip; old_eip = ctxt-_eip; - ctxt-_eip = ctxt-src.val; + rc = assign_eip_near(ctxt, ctxt-src.val); + if (rc != X86EMUL_CONTINUE) + break; ctxt-src.val = old_eip; rc = em_push(ctxt); break; } case 4: /* jmp abs */ - ctxt-_eip = ctxt-src.val; + rc = assign_eip_near(ctxt, ctxt-src.val); break; case 5: /* jmp far */ rc = em_jmp_far(ctxt); @@ -1825,10 +1837,14 @@ static int em_grp9(struct x86_emulate_ct static int em_ret(struct x86_emulate_ctxt *ctxt) { - ctxt-dst.type = OP_REG; - ctxt-dst.addr.reg = ctxt-_eip; - ctxt-dst.bytes = ctxt-op_bytes; - return em_pop(ctxt); + int rc; + unsigned long eip; + + rc = emulate_pop(ctxt, eip, ctxt-op_bytes); + if (rc != X86EMUL_CONTINUE) + return rc; + + return assign_eip_near(ctxt, eip); } static int em_ret_far(struct x86_emulate_ctxt *ctxt) @@ -2060,7 +2076,7 @@ static int em_sysexit(struct x86_emulate { struct x86_emulate_ops *ops = ctxt-ops; struct desc_struct cs, ss; - u64 msr_data; + u64 msr_data, rcx, rdx; int usermode; u16 cs_sel = 0, ss_sel = 0; @@ -2076,6 +2092,9 @@ static int em_sysexit(struct x86_emulate else usermode = X86EMUL_MODE_PROT32; + rcx = ctxt-regs[VCPU_REGS_RCX]; + rdx = ctxt-regs[VCPU_REGS_RDX]; + cs.dpl = 3; ss.dpl = 3; ops-get_msr(ctxt, MSR_IA32_SYSENTER_CS, msr_data); @@ -2093,6 +2112,9 @@ static int em_sysexit(struct x86_emulate ss_sel = cs_sel + 8; cs.d = 0; cs.l = 1; + if (is_noncanonical_address(rcx) || + is_noncanonical_address(rdx)) + return emulate_gp(ctxt, 0); break; } cs_sel |= SELECTOR_RPL_MASK; @@ -2101,8 +2123,8 @@ static int em_sysexit(struct x86_emulate
[PATCH 3.2 091/102] KVM: x86: Emulator fixes for eip canonical checks on near branches
3.2.64-rc1 review patch. If anyone has any objections, please let me know. -- From: Nadav Amit commit 234f3ce485d54017f15cf5e0699cff4100121601 upstream. Before changing rip (during jmp, call, ret, etc.) the target should be asserted to be canonical one, as real CPUs do. During sysret, both target rsp and rip should be canonical. If any of these values is noncanonical, a #GP exception should occur. The exception to this rule are syscall and sysenter instructions in which the assigned rip is checked during the assignment to the relevant MSRs. This patch fixes the emulator to behave as real CPUs do for near branches. Far branches are handled by the next patch. This fixes CVE-2014-3647. Signed-off-by: Nadav Amit Signed-off-by: Paolo Bonzini [bwh: Backported to 3.2: - Adjust context - Use ctxt->regs[] instead of reg_read(), reg_write(), reg_rmw()] Signed-off-by: Ben Hutchings --- arch/x86/kvm/emulate.c | 78 ++ 1 file changed, 54 insertions(+), 24 deletions(-) --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -529,7 +529,8 @@ static int emulate_nm(struct x86_emulate return emulate_exception(ctxt, NM_VECTOR, 0, false); } -static inline void assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong dst) +static inline int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst, + int cs_l) { switch (ctxt->op_bytes) { case 2: @@ -539,16 +540,25 @@ static inline void assign_eip_near(struc ctxt->_eip = (u32)dst; break; case 8: + if ((cs_l && is_noncanonical_address(dst)) || + (!cs_l && (dst & ~(u32)-1))) + return emulate_gp(ctxt, 0); ctxt->_eip = dst; break; default: WARN(1, "unsupported eip assignment size\n"); } + return X86EMUL_CONTINUE; +} + +static inline int assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong dst) +{ + return assign_eip_far(ctxt, dst, ctxt->mode == X86EMUL_MODE_PROT64); } -static inline void jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) +static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) { - assign_eip_near(ctxt, ctxt->_eip + rel); + return assign_eip_near(ctxt, ctxt->_eip + rel); } static u16 get_segment_selector(struct x86_emulate_ctxt *ctxt, unsigned seg) @@ -1787,13 +1797,15 @@ static int em_grp45(struct x86_emulate_c case 2: /* call near abs */ { long int old_eip; old_eip = ctxt->_eip; - ctxt->_eip = ctxt->src.val; + rc = assign_eip_near(ctxt, ctxt->src.val); + if (rc != X86EMUL_CONTINUE) + break; ctxt->src.val = old_eip; rc = em_push(ctxt); break; } case 4: /* jmp abs */ - ctxt->_eip = ctxt->src.val; + rc = assign_eip_near(ctxt, ctxt->src.val); break; case 5: /* jmp far */ rc = em_jmp_far(ctxt); @@ -1825,10 +1837,14 @@ static int em_grp9(struct x86_emulate_ct static int em_ret(struct x86_emulate_ctxt *ctxt) { - ctxt->dst.type = OP_REG; - ctxt->dst.addr.reg = >_eip; - ctxt->dst.bytes = ctxt->op_bytes; - return em_pop(ctxt); + int rc; + unsigned long eip; + + rc = emulate_pop(ctxt, , ctxt->op_bytes); + if (rc != X86EMUL_CONTINUE) + return rc; + + return assign_eip_near(ctxt, eip); } static int em_ret_far(struct x86_emulate_ctxt *ctxt) @@ -2060,7 +2076,7 @@ static int em_sysexit(struct x86_emulate { struct x86_emulate_ops *ops = ctxt->ops; struct desc_struct cs, ss; - u64 msr_data; + u64 msr_data, rcx, rdx; int usermode; u16 cs_sel = 0, ss_sel = 0; @@ -2076,6 +2092,9 @@ static int em_sysexit(struct x86_emulate else usermode = X86EMUL_MODE_PROT32; + rcx = ctxt->regs[VCPU_REGS_RCX]; + rdx = ctxt->regs[VCPU_REGS_RDX]; + cs.dpl = 3; ss.dpl = 3; ops->get_msr(ctxt, MSR_IA32_SYSENTER_CS, _data); @@ -2093,6 +2112,9 @@ static int em_sysexit(struct x86_emulate ss_sel = cs_sel + 8; cs.d = 0; cs.l = 1; + if (is_noncanonical_address(rcx) || + is_noncanonical_address(rdx)) + return emulate_gp(ctxt, 0); break; } cs_sel |= SELECTOR_RPL_MASK; @@ -2101,8 +2123,8 @@ static int em_sysexit(struct x86_emulate ops->set_segment(ctxt, cs_sel, , 0, VCPU_SREG_CS); ops->set_segment(ctxt, ss_sel, , 0, VCPU_SREG_SS); - ctxt->_eip = ctxt->regs[VCPU_REGS_RDX]; - ctxt->regs[VCPU_REGS_RSP] = ctxt->regs[VCPU_REGS_RCX]; + ctxt->_eip = rdx; + ctxt->regs[VCPU_REGS_RSP] = rcx; return
[PATCH 3.2 091/102] KVM: x86: Emulator fixes for eip canonical checks on near branches
3.2.64-rc1 review patch. If anyone has any objections, please let me know. -- From: Nadav Amit na...@cs.technion.ac.il commit 234f3ce485d54017f15cf5e0699cff4100121601 upstream. Before changing rip (during jmp, call, ret, etc.) the target should be asserted to be canonical one, as real CPUs do. During sysret, both target rsp and rip should be canonical. If any of these values is noncanonical, a #GP exception should occur. The exception to this rule are syscall and sysenter instructions in which the assigned rip is checked during the assignment to the relevant MSRs. This patch fixes the emulator to behave as real CPUs do for near branches. Far branches are handled by the next patch. This fixes CVE-2014-3647. Signed-off-by: Nadav Amit na...@cs.technion.ac.il Signed-off-by: Paolo Bonzini pbonz...@redhat.com [bwh: Backported to 3.2: - Adjust context - Use ctxt-regs[] instead of reg_read(), reg_write(), reg_rmw()] Signed-off-by: Ben Hutchings b...@decadent.org.uk --- arch/x86/kvm/emulate.c | 78 ++ 1 file changed, 54 insertions(+), 24 deletions(-) --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -529,7 +529,8 @@ static int emulate_nm(struct x86_emulate return emulate_exception(ctxt, NM_VECTOR, 0, false); } -static inline void assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong dst) +static inline int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst, + int cs_l) { switch (ctxt-op_bytes) { case 2: @@ -539,16 +540,25 @@ static inline void assign_eip_near(struc ctxt-_eip = (u32)dst; break; case 8: + if ((cs_l is_noncanonical_address(dst)) || + (!cs_l (dst ~(u32)-1))) + return emulate_gp(ctxt, 0); ctxt-_eip = dst; break; default: WARN(1, unsupported eip assignment size\n); } + return X86EMUL_CONTINUE; +} + +static inline int assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong dst) +{ + return assign_eip_far(ctxt, dst, ctxt-mode == X86EMUL_MODE_PROT64); } -static inline void jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) +static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) { - assign_eip_near(ctxt, ctxt-_eip + rel); + return assign_eip_near(ctxt, ctxt-_eip + rel); } static u16 get_segment_selector(struct x86_emulate_ctxt *ctxt, unsigned seg) @@ -1787,13 +1797,15 @@ static int em_grp45(struct x86_emulate_c case 2: /* call near abs */ { long int old_eip; old_eip = ctxt-_eip; - ctxt-_eip = ctxt-src.val; + rc = assign_eip_near(ctxt, ctxt-src.val); + if (rc != X86EMUL_CONTINUE) + break; ctxt-src.val = old_eip; rc = em_push(ctxt); break; } case 4: /* jmp abs */ - ctxt-_eip = ctxt-src.val; + rc = assign_eip_near(ctxt, ctxt-src.val); break; case 5: /* jmp far */ rc = em_jmp_far(ctxt); @@ -1825,10 +1837,14 @@ static int em_grp9(struct x86_emulate_ct static int em_ret(struct x86_emulate_ctxt *ctxt) { - ctxt-dst.type = OP_REG; - ctxt-dst.addr.reg = ctxt-_eip; - ctxt-dst.bytes = ctxt-op_bytes; - return em_pop(ctxt); + int rc; + unsigned long eip; + + rc = emulate_pop(ctxt, eip, ctxt-op_bytes); + if (rc != X86EMUL_CONTINUE) + return rc; + + return assign_eip_near(ctxt, eip); } static int em_ret_far(struct x86_emulate_ctxt *ctxt) @@ -2060,7 +2076,7 @@ static int em_sysexit(struct x86_emulate { struct x86_emulate_ops *ops = ctxt-ops; struct desc_struct cs, ss; - u64 msr_data; + u64 msr_data, rcx, rdx; int usermode; u16 cs_sel = 0, ss_sel = 0; @@ -2076,6 +2092,9 @@ static int em_sysexit(struct x86_emulate else usermode = X86EMUL_MODE_PROT32; + rcx = ctxt-regs[VCPU_REGS_RCX]; + rdx = ctxt-regs[VCPU_REGS_RDX]; + cs.dpl = 3; ss.dpl = 3; ops-get_msr(ctxt, MSR_IA32_SYSENTER_CS, msr_data); @@ -2093,6 +2112,9 @@ static int em_sysexit(struct x86_emulate ss_sel = cs_sel + 8; cs.d = 0; cs.l = 1; + if (is_noncanonical_address(rcx) || + is_noncanonical_address(rdx)) + return emulate_gp(ctxt, 0); break; } cs_sel |= SELECTOR_RPL_MASK; @@ -2101,8 +2123,8 @@ static int em_sysexit(struct x86_emulate ops-set_segment(ctxt, cs_sel, cs, 0, VCPU_SREG_CS); ops-set_segment(ctxt, ss_sel, ss, 0, VCPU_SREG_SS); - ctxt-_eip = ctxt-regs[VCPU_REGS_RDX]; - ctxt-regs[VCPU_REGS_RSP] = ctxt-regs[VCPU_REGS_RCX]; + ctxt-_eip = rdx;