diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 5ba5b46c4f..1b0cce128c 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -1321,7 +1321,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, return -1; } - assert(length < 256); + assert(length + 2 <= SCSI_MAX_MODE_LEN); (*p_outbuf)[0] = page; (*p_outbuf)[1] = length; *p_outbuf += length + 2; @@ -1524,7 +1524,7 @@ static void scsi_disk_emulate_read_data(SCSIRequest *req) static int scsi_disk_check_mode_select(SCSIDiskState *s, int page, uint8_t *inbuf, int inlen) { - uint8_t mode_current[SCSI_MAX_MODE_LEN]; + uint8_t mode_current[SCSI_MAX_MODE_LEN] = { 0 }; uint8_t mode_changeable[SCSI_MAX_MODE_LEN]; uint8_t *p; int len, expected_len, changeable_len, i; @@ -1543,21 +1543,21 @@ static int scsi_disk_check_mode_select(SCSIDiskState *s, int page, } p = mode_current; - memset(mode_current, 0, inlen + 2); len = mode_sense_page(s, page, &p, 0); - if (len < 0 || len != expected_len) { + /* The guest may send a truncated page, but not a longer one. */ + if (len < 0 || expected_len > len) { return -1; } p = mode_changeable; - memset(mode_changeable, 0, inlen + 2); + memset(mode_changeable, 0, len); changeable_len = mode_sense_page(s, page, &p, 1); assert(changeable_len == len); /* Check that unchangeable bits are the same as what MODE SENSE * would return. */ - for (i = 2; i < len; i++) { + for (i = 2; i < expected_len; i++) { if (((mode_current[i] ^ inbuf[i - 2]) & ~mode_changeable[i]) != 0) { return -1; } @@ -1565,11 +1565,15 @@ static int scsi_disk_check_mode_select(SCSIDiskState *s, int page, return 0; } -static void scsi_disk_apply_mode_select(SCSIDiskState *s, int page, uint8_t *p) +/* Note p may be truncated, so check any bytes you access against len. */ +static void scsi_disk_apply_mode_select(SCSIDiskState *s, int page, + uint8_t *p, int len) { switch (page) { case MODE_PAGE_CACHING: - blk_set_enable_write_cache(s->qdev.conf.blk, (p[0] & 4) != 0); + if (len > 0) { + blk_set_enable_write_cache(s->qdev.conf.blk, (p[0] & 4) != 0); + } break; default: @@ -1612,6 +1616,7 @@ static int mode_select_pages(SCSIDiskReq *r, uint8_t *p, int len, bool change) goto invalid_param_len; } trace_scsi_disk_mode_select_page_truncated(page, page_len, len); + page_len = len; } if (!change) { @@ -1619,7 +1624,7 @@ static int mode_select_pages(SCSIDiskReq *r, uint8_t *p, int len, bool change) goto invalid_param; } } else { - scsi_disk_apply_mode_select(s, page, p); + scsi_disk_apply_mode_select(s, page, p, page_len); } p += page_len; diff --git a/meson.build b/meson.build index 06c43b4358..49a5baf5b5 100644 --- a/meson.build +++ b/meson.build @@ -767,6 +767,9 @@ endif add_project_arguments(cc.get_supported_arguments(qemu_common_flags + qemu_cflags + warn_flags), native: false, language: 'c') add_global_link_arguments(qemu_ldflags, native: false, language: all_languages) +if have_rust + add_global_link_arguments(qemu_ldflags, native: false, language: 'rust') +endif if 'cpp' in all_languages add_project_arguments(cxx.get_supported_arguments(qemu_common_flags + qemu_cxxflags), diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc index 83c889cc3b..e4ef5a8758 100644 --- a/target/i386/tcg/emit.c.inc +++ b/target/i386/tcg/emit.c.inc @@ -3424,7 +3424,9 @@ static void gen_rot_overflow(X86DecodedInsn *decode, TCGv result, TCGv old, /* * RCx operations are invariant modulo 8*operand_size+1. For 8 and 16-bit operands, * this is less than 0x1f (the mask applied by gen_shift_count) so reduce further. - * FIXME: are flags updated if the count is nonzero, but a multiple of (8 << op) + 1? + * A count that is a nonzero multiple of (8 << op) + 1 reduces to 0 and leaves + * CF and OF unmodified (confirmed against hardware that rcl $9,%al behaves + * exactly like rcl $0,%al). */ static MemOp gen_rotc_count(DisasContext *s, X86DecodedInsn *decode, bool *can_be_zero, TCGv *count, int unit) diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index 58aac72011..d5c174b7fd 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -1096,17 +1096,22 @@ void helper_sysret(CPUX86State *env, int dflag) selector = (env->star >> 48) & 0xffff; #ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { - cpu_load_eflags(env, (uint32_t)(env->regs[11]), TF_MASK | AC_MASK - | ID_MASK | IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | - NT_MASK); if (dflag == 2) { + uint64_t new_rip = env->regs[R_ECX]; + if (IS_INTEL_CPU(env)) { + int shift = (get_pg_mode(env) & PG_MODE_LA57) ? 56 : 47; + int64_t sext = (int64_t)new_rip >> shift; + if (sext != 0 && sext != -1) { + raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); + } + } cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, 0, 0xffffffff, DESC_G_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); - env->eip = env->regs[R_ECX]; + env->eip = new_rip; } else { cpu_x86_load_seg_cache(env, R_CS, selector | 3, 0, 0xffffffff, @@ -1120,6 +1125,10 @@ void helper_sysret(CPUX86State *env, int dflag) DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | DESC_W_MASK | DESC_A_MASK); + + cpu_load_eflags(env, (uint32_t)(env->regs[11]), TF_MASK | AC_MASK + | ID_MASK | IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | + NT_MASK); } else #endif {