From: George Dunlap <george.dunlap@citrix.com>
To: xen-devel@lists.xenproject.org
Cc: Ian Jackson <ian.jackson@citrix.com>,
Wei Liu <wei.liu2@citrix.com>, Jan Beulich <jbeulich@suse.com>,
Andrew Cooper <andrew.cooper3@citrix.com>
Subject: [PATCH v2 01/13] x86emul/fuzz: add rudimentary limit checking
Date: Mon, 25 Sep 2017 15:26:36 +0100 [thread overview]
Message-ID: <20170925142648.25959-1-george.dunlap@citrix.com> (raw)
From: Jan Beulich <jbeulich@suse.com>
fuzz_insn_fetch() is the only data access helper where it is possible
to see offsets larger than 4Gb in 16- or 32-bit modes, as we leave the
incoming rIP untouched in the emulator itself. The check is needed here
as otherwise, after successfully fetching insn bytes, we may end up
zero-extending EIP soon after complete_insn, which collides with the
X86EMUL_EXCEPTION-conditional respective ASSERT() in
x86_emulate_wrapper(). (NB: put_rep_prefix() is what allows
complete_insn to be reached with rc set to other than X86EMUL_OKAY or
X86EMUL_DONE. See also commit 53f87c03b4 ["x86emul: generalize
exception handling for rep_* hooks"].)
Add assert()-s for all other (data) access routines, as effective
address generation in the emulator ought to guarantee in-range values.
For them to not trigger, several adjustments to the emulator's address
calculations are needed: While for DstBitBase it is really mandatory,
the specification allows for either behavior for two-part accesses.
Observed behavior on real hardware, however, is for such accesses to
silently wrap at the 2^^32 boundary in other than 64-bit mode, just
like they do at the 2^^64 boundary in 64-bit mode. While adding
truncate_ea() invocations there, also convert open coded instances of
it.
Reported-by: George Dunlap <george.dunlap@citrix.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
CC: Ian Jackson <ian.jackson@citrix.com>
CC: Wei Liu <wei.liu2@citrix.com>
CC: Andrew Cooper <andrew.cooper3@citrix.com>
CC: Jan Beulich <jbeulich@suse.com>
---
tools/fuzz/x86_instruction_emulator/fuzz-emul.c | 32 ++++++++++++++++++++++---
xen/arch/x86/x86_emulate/x86_emulate.c | 22 +++++++++--------
2 files changed, 41 insertions(+), 13 deletions(-)
diff --git a/tools/fuzz/x86_instruction_emulator/fuzz-emul.c b/tools/fuzz/x86_instruction_emulator/fuzz-emul.c
index a2329f84a5..105145e9f9 100644
--- a/tools/fuzz/x86_instruction_emulator/fuzz-emul.c
+++ b/tools/fuzz/x86_instruction_emulator/fuzz-emul.c
@@ -139,7 +139,18 @@ static int fuzz_read(
struct x86_emulate_ctxt *ctxt)
{
/* Reads expected for all user and system segments. */
- assert(is_x86_user_segment(seg) || is_x86_system_segment(seg));
+ if ( is_x86_user_segment(seg) )
+ assert(ctxt->addr_size == 64 || !(offset >> 32));
+ else if ( seg == x86_seg_tr )
+ /*
+ * The TSS is special in that accesses below the segment base are
+ * possible, as the Interrupt Redirection Bitmap starts 32 bytes
+ * ahead of the I/O Bitmap, regardless of the value of the latter.
+ */
+ assert((long)offset < 0 ? (long)offset > -32 : !(offset >> 17));
+ else
+ assert(is_x86_system_segment(seg) &&
+ (ctxt->lma ? offset <= 0x10007 : !(offset >> 16)));
return data_read(ctxt, seg, "read", p_data, bytes);
}
@@ -162,6 +173,13 @@ static int fuzz_insn_fetch(
{
assert(seg == x86_seg_cs);
+ /* Minimal segment limit checking, until full one is being put in place. */
+ if ( ctxt->addr_size < 64 && (offset >> 32) )
+ {
+ x86_emul_hw_exception(13, 0, ctxt);
+ return X86EMUL_EXCEPTION;
+ }
+
/*
* Zero-length instruction fetches are made at the destination of jumps,
* to perform segmentation checks. No data needs returning.
@@ -232,6 +250,7 @@ static int fuzz_rep_ins(
struct x86_emulate_ctxt *ctxt)
{
assert(dst_seg == x86_seg_es);
+ assert(ctxt->addr_size == 64 || !(dst_offset >> 32));
return _fuzz_rep_read(ctxt, "rep_ins", reps);
}
@@ -247,6 +266,7 @@ static int fuzz_rep_movs(
{
assert(is_x86_user_segment(src_seg));
assert(dst_seg == x86_seg_es);
+ assert(ctxt->addr_size == 64 || !((src_offset | dst_offset) >> 32));
return _fuzz_rep_read(ctxt, "rep_movs", reps);
}
@@ -260,6 +280,7 @@ static int fuzz_rep_outs(
struct x86_emulate_ctxt *ctxt)
{
assert(is_x86_user_segment(src_seg));
+ assert(ctxt->addr_size == 64 || !(src_offset >> 32));
return _fuzz_rep_write(ctxt, "rep_outs", reps);
}
@@ -277,6 +298,7 @@ static int fuzz_rep_stos(
* for CLZERO.
*/
assert(is_x86_user_segment(seg));
+ assert(ctxt->addr_size == 64 || !(offset >> 32));
return _fuzz_rep_write(ctxt, "rep_stos", reps);
}
@@ -290,6 +312,7 @@ static int fuzz_write(
{
/* Writes not expected for any system segments. */
assert(is_x86_user_segment(seg));
+ assert(ctxt->addr_size == 64 || !(offset >> 32));
return maybe_fail(ctxt, "write", true);
}
@@ -306,8 +329,10 @@ static int fuzz_cmpxchg(
* Cmpxchg expected for user segments, and setting accessed/busy bits in
* GDT/LDT enties, but not expected for any IDT or TR accesses.
*/
- assert(is_x86_user_segment(seg) ||
- seg == x86_seg_gdtr || seg == x86_seg_ldtr);
+ if ( is_x86_user_segment(seg) )
+ assert(ctxt->addr_size == 64 || !(offset >> 32));
+ else
+ assert((seg == x86_seg_gdtr || seg == x86_seg_ldtr) && !(offset >> 16));
return maybe_fail(ctxt, "cmpxchg", true);
}
@@ -319,6 +344,7 @@ static int fuzz_invlpg(
{
/* invlpg(), unlike all other hooks, may be called with x86_seg_none. */
assert(is_x86_user_segment(seg) || seg == x86_seg_none);
+ assert(ctxt->addr_size == 64 || !(offset >> 32));
return maybe_fail(ctxt, "invlpg", false);
}
diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c
index c1e2300b39..31df5aeb97 100644
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -1249,10 +1249,10 @@ static void __put_rep_prefix(
/* Clip maximum repetitions so that the index register at most just wraps. */
#define truncate_ea_and_reps(ea, reps, bytes_per_rep) ({ \
- unsigned long todo__, ea__ = truncate_word(ea, ad_bytes); \
+ unsigned long todo__, ea__ = truncate_ea(ea); \
if ( !(_regs.eflags & X86_EFLAGS_DF) ) \
- todo__ = truncate_word(-(ea), ad_bytes) / (bytes_per_rep); \
- else if ( truncate_word((ea) + (bytes_per_rep) - 1, ad_bytes) < ea__ )\
+ todo__ = truncate_ea(-ea__) / (bytes_per_rep); \
+ else if ( truncate_ea(ea__ + (bytes_per_rep) - 1) < ea__ ) \
todo__ = 1; \
else \
todo__ = ea__ / (bytes_per_rep) + 1; \
@@ -3136,6 +3136,7 @@ x86_emulate(
op_bytes + (((-src.val - 1) >> 3) & ~(op_bytes - 1L));
else
ea.mem.off += (src.val >> 3) & ~(op_bytes - 1L);
+ ea.mem.off = truncate_ea(ea.mem.off);
}
/* Bit index always truncated to within range. */
@@ -3354,7 +3355,7 @@ x86_emulate(
unsigned long src_val2;
int lb, ub, idx;
generate_exception_if(src.type != OP_MEM, EXC_UD);
- if ( (rc = read_ulong(src.mem.seg, src.mem.off + op_bytes,
+ if ( (rc = read_ulong(src.mem.seg, truncate_ea(src.mem.off + op_bytes),
&src_val2, op_bytes, ctxt, ops)) )
goto done;
ub = (op_bytes == 2) ? (int16_t)src_val2 : (int32_t)src_val2;
@@ -3905,7 +3906,7 @@ x86_emulate(
seg = (b & 1) * 3; /* es = 0, ds = 3 */
les:
generate_exception_if(src.type != OP_MEM, EXC_UD);
- if ( (rc = read_ulong(src.mem.seg, src.mem.off + src.bytes,
+ if ( (rc = read_ulong(src.mem.seg, truncate_ea(src.mem.off + src.bytes),
&dst.val, 2, ctxt, ops)) != X86EMUL_OKAY )
goto done;
ASSERT(is_x86_user_segment(seg));
@@ -4939,7 +4940,8 @@ x86_emulate(
case 5: /* jmp (far, absolute indirect) */
generate_exception_if(src.type != OP_MEM, EXC_UD);
- if ( (rc = read_ulong(src.mem.seg, src.mem.off + op_bytes,
+ if ( (rc = read_ulong(src.mem.seg,
+ truncate_ea(src.mem.off + op_bytes),
&imm2, 2, ctxt, ops)) )
goto done;
imm1 = src.val;
@@ -5126,8 +5128,8 @@ x86_emulate(
}
if ( (rc = ops->write(ea.mem.seg, ea.mem.off, &sreg.limit,
2, ctxt)) != X86EMUL_OKAY ||
- (rc = ops->write(ea.mem.seg, ea.mem.off + 2, &sreg.base,
- op_bytes, ctxt)) != X86EMUL_OKAY )
+ (rc = ops->write(ea.mem.seg, truncate_ea(ea.mem.off + 2),
+ &sreg.base, op_bytes, ctxt)) != X86EMUL_OKAY )
goto done;
break;
@@ -5137,9 +5139,9 @@ x86_emulate(
generate_exception_if(!mode_ring0(), EXC_GP, 0);
fail_if(ops->write_segment == NULL);
memset(&sreg, 0, sizeof(sreg));
- if ( (rc = read_ulong(ea.mem.seg, ea.mem.off+0,
+ if ( (rc = read_ulong(ea.mem.seg, ea.mem.off,
&limit, 2, ctxt, ops)) ||
- (rc = read_ulong(ea.mem.seg, ea.mem.off+2,
+ (rc = read_ulong(ea.mem.seg, truncate_ea(ea.mem.off + 2),
&base, mode_64bit() ? 8 : 4, ctxt, ops)) )
goto done;
generate_exception_if(!is_canonical_address(base), EXC_GP, 0);
--
2.14.1
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel
next reply other threads:[~2017-09-25 14:27 UTC|newest]
Thread overview: 56+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-09-25 14:26 George Dunlap [this message]
2017-09-25 14:26 ` [PATCH v2 02/13] fuzz/x86_emulate: Actually use cpu_regs input George Dunlap
2017-10-04 8:21 ` Jan Beulich
2017-09-25 14:26 ` [PATCH v2 03/13] fuzz/x86_emulate: Clear errors after each iteration George Dunlap
2017-10-04 8:22 ` Jan Beulich
2017-09-25 14:26 ` [PATCH v2 04/13] fuzz/x86_emulate: Improve failure descriptions in x86_emulate harness George Dunlap
2017-10-04 8:22 ` Jan Beulich
2017-09-25 14:26 ` [PATCH v2 05/13] fuzz/x86_emulate: Implement input_read() and input_avail() George Dunlap
2017-10-04 8:22 ` Jan Beulich
2017-10-04 16:23 ` George Dunlap
2017-09-25 14:26 ` [PATCH v2 06/13] fuzz/x86_emulate: Rename the file containing the wrapper code George Dunlap
2017-10-04 8:23 ` Jan Beulich
2017-10-04 16:34 ` George Dunlap
2017-10-05 9:01 ` Jan Beulich
2017-10-05 13:50 ` George Dunlap
2017-09-25 14:26 ` [PATCH v2 07/13] fuzz/x86_emulate: Add 'afl-cov' target George Dunlap
2017-10-04 8:23 ` Jan Beulich
2017-10-04 16:48 ` George Dunlap
2017-10-05 9:06 ` Jan Beulich
2017-09-25 14:26 ` [PATCH v2 08/13] fuzz/x86_emulate: Take multiple test files for inputs George Dunlap
2017-10-04 8:24 ` Jan Beulich
2017-10-04 16:58 ` George Dunlap
2017-10-05 9:08 ` Jan Beulich
2017-09-25 14:26 ` [PATCH v2 09/13] fuzz/x86_emulate: Move all state into fuzz_state George Dunlap
2017-10-04 8:25 ` Jan Beulich
2017-10-04 16:51 ` George Dunlap
2017-09-25 14:26 ` [PATCH v2 10/13] fuzz/x86_emulate: Make input more compact George Dunlap
2017-10-04 8:26 ` Jan Beulich
2017-10-05 15:04 ` George Dunlap
2017-10-05 15:37 ` Jan Beulich
2017-09-25 14:26 ` [PATCH v2 11/13] fuzz/x86_emulate: Add --rerun option to try to track down instability George Dunlap
2017-10-04 8:27 ` Jan Beulich
2017-10-05 16:12 ` George Dunlap
2017-10-06 5:53 ` Jan Beulich
2017-09-25 14:26 ` [PATCH v2 12/13] fuzz/x86_emulate: Set and fuzz more CPU state George Dunlap
2017-10-04 8:28 ` Jan Beulich
2017-10-05 17:08 ` George Dunlap
2017-10-06 6:10 ` Jan Beulich
2017-10-06 10:53 ` George Dunlap
2017-10-06 9:57 ` Jan Beulich
2017-10-06 10:50 ` George Dunlap
2017-10-06 11:53 ` Jan Beulich
2017-10-06 11:56 ` Jan Beulich
2017-10-10 15:45 ` George Dunlap
2017-09-25 14:26 ` [PATCH v2 13/13] fuzz/x86_emulate: Add an option to limit the number of instructions executed George Dunlap
2017-10-04 8:28 ` Jan Beulich
2017-10-06 10:40 ` George Dunlap
2017-10-06 12:12 ` Jan Beulich
2017-10-06 13:02 ` George Dunlap
2017-10-06 15:21 ` [PATCH v2 01/13] x86emul/fuzz: add rudimentary limit checking George Dunlap
2017-10-06 15:54 ` Jan Beulich
2017-10-06 17:06 ` George Dunlap
2017-10-09 7:17 ` Jan Beulich
2017-10-09 12:54 ` Andrew Cooper
2017-10-09 13:26 ` Jan Beulich
2017-10-09 13:35 ` Andrew Cooper
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170925142648.25959-1-george.dunlap@citrix.com \
--to=george.dunlap@citrix.com \
--cc=andrew.cooper3@citrix.com \
--cc=ian.jackson@citrix.com \
--cc=jbeulich@suse.com \
--cc=wei.liu2@citrix.com \
--cc=xen-devel@lists.xenproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).