From nobody Wed Nov 5 14:28:09 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 15348716960634.812221167118423; Tue, 21 Aug 2018 10:14:56 -0700 (PDT) Received: from localhost ([::1]:54996 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fsAF4-0003V4-SC for importer@patchew.org; Tue, 21 Aug 2018 13:14:54 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:33323) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fsA4V-0001nJ-7b for qemu-devel@nongnu.org; Tue, 21 Aug 2018 13:04:06 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fsA4R-0006eU-9Z for qemu-devel@nongnu.org; Tue, 21 Aug 2018 13:03:58 -0400 Received: from mail-wm0-x22b.google.com ([2a00:1450:400c:c09::22b]:51286) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fsA4I-0006MQ-KH for qemu-devel@nongnu.org; Tue, 21 Aug 2018 13:03:48 -0400 Received: by mail-wm0-x22b.google.com with SMTP id y2-v6so3644170wma.1 for ; Tue, 21 Aug 2018 10:03:42 -0700 (PDT) Received: from 640k.lan (dynamic-adsl-78-12-184-244.clienti.tiscali.it. [78.12.184.244]) by smtp.gmail.com with ESMTPSA id v6-v6sm2608955wmc.43.2018.08.21.10.03.39 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 21 Aug 2018 10:03:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=G/Fi3so4FAZss/HYU5AK/SuYH5z/6vZPYomc5cVoprU=; b=oM2EOHPPyqALCf2YKbHCEqO6S8z7CYdm+YwdEX/N0Zv7J+GumV4bOaG/NXhxNTDSza VN5/esd9sp69hQdYL/xhzx7XQqSAO4HBLFpYNsCV2Dil87TjCJAt6J3EodxXKEV67aQ+ 9ge1bgtLauRBnG9Yoi7C95/r4weXLAg2ANUAS8mVu1DKFh/NDipXHE5YfY88q0628wS2 VtiQplWw8F0Vh+lOUcQANqBqi6CN46DdWm8l4FgexAQVAGX+dYiIcpZWfUpaeHIGhGDp GKAlM/IKUB2WPTDnQXaeeHp1kA01CtVHSOHjyFx/9K/zd8arJXKD4ebzguKMXuljsGQn 0BhA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=G/Fi3so4FAZss/HYU5AK/SuYH5z/6vZPYomc5cVoprU=; b=mt7VwKioiktPQM10I/kv4rVPagy5y0tHjvXZ4Nc7gwnOuqj4ewliVu+hhTH5BBZqA/ TrAx+IGzLYe+UP8CQEuiumzCuONKlP61aDVIT7Uyf6Ae5J1WTOS2zrwH/OPfoaQ6NRX5 vXDEcZGNK6cHepxMji2PPzb+bBOMnjGYqgdBrD0ET4i6tKe9nNVfEpamNZ84xk/eqjU6 eEAmZZ47daG2/tRsZhBu6Y0XS3X8w5YHJE7Npwj3wAChrzcRAPwptbyCzWp1KZukb5NO G8onyfh1OmkorMa7dZK1jAsmHYy5ZAmSTtdAT1fzwAq8LzV7qniFekKZkqQU3MFmAhlF pYZQ== X-Gm-Message-State: APzg51ClB8VbVT0KOdF7vd09OplLMv6qkNJNyaoRrXE1+C/DHlZL+Qj6 ezkY7omeE54YhSdI9PnAtjlG2Gbz X-Google-Smtp-Source: ANB0VdYi5dLZ7xUURzSAb7hsxrMBDxcRP/nn/VzhydX/PHs7/VUkk5zUMFjOzUgKwMcD4vFA+5MdQg== X-Received: by 2002:a1c:a8d0:: with SMTP id r199-v6mr120853wme.97.1534871021159; Tue, 21 Aug 2018 10:03:41 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Tue, 21 Aug 2018 19:02:06 +0200 Message-Id: <1534870966-9287-35-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1534870966-9287-1-git-send-email-pbonzini@redhat.com> References: <1534870966-9287-1-git-send-email-pbonzini@redhat.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:400c:c09::22b Subject: [Qemu-devel] [PULL 34/74] target-i386: Fix lcall/ljmp to call gate in IA-32e mode X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Andrew Oates Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDMRC_1 RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Andrew Oates Currently call gates are always treated as 32-bit gates. In IA-32e mode (either compatibility or 64-bit submode), system segment descriptors are always 64-bit. Treating them as 32-bit has the expected unfortunate effect: only the lower 32 bits of the offset are loaded, the stack pointer is truncated, a bad new stack pointer is loaded from the TSS (if switching privilege levels), etc. This change adds support for 64-bit call gate to the lcall and ljmp instructions. Additionally, there should be a check for non-canonical stack pointers, but I've omitted that since there doesn't seem to be checks for non-canonical addresses in this code elsewhere. I've left the raise_exception_err_ra lines unwapped at 80 columns to match the style in the rest of the file. Signed-off-by: Andrew Oates Message-Id: <20180819181725.34098-1-andrew@andrewoates.com> Signed-off-by: Paolo Bonzini --- target/i386/seg_helper.c | 192 +++++++++++++++++++++++++++++++++++++------= ---- 1 file changed, 152 insertions(+), 40 deletions(-) diff --git a/target/i386/seg_helper.c b/target/i386/seg_helper.c index 00301a0..b2adddc 100644 --- a/target/i386/seg_helper.c +++ b/target/i386/seg_helper.c @@ -518,6 +518,11 @@ static void switch_tss(CPUX86State *env, int tss_selec= tor, =20 static inline unsigned int get_sp_mask(unsigned int e2) { +#ifdef TARGET_X86_64 + if (e2 & DESC_L_MASK) { + return 0; + } else +#endif if (e2 & DESC_B_MASK) { return 0xffffffff; } else { @@ -1640,6 +1645,14 @@ void helper_ljmp_protected(CPUX86State *env, int new= _cs, target_ulong new_eip, rpl =3D new_cs & 3; cpl =3D env->hflags & HF_CPL_MASK; type =3D (e2 >> DESC_TYPE_SHIFT) & 0xf; + +#ifdef TARGET_X86_64 + if (env->efer & MSR_EFER_LMA) { + if (type !=3D 12) { + raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, G= ETPC()); + } + } +#endif switch (type) { case 1: /* 286 TSS */ case 9: /* 386 TSS */ @@ -1662,6 +1675,23 @@ void helper_ljmp_protected(CPUX86State *env, int new= _cs, target_ulong new_eip, if (type =3D=3D 12) { new_eip |=3D (e2 & 0xffff0000); } + +#ifdef TARGET_X86_64 + if (env->efer & MSR_EFER_LMA) { + /* load the upper 8 bytes of the 64-bit call gate */ + if (load_segment_ra(env, &e1, &e2, new_cs + 8, GETPC())) { + raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfff= c, + GETPC()); + } + type =3D (e2 >> DESC_TYPE_SHIFT) & 0x1f; + if (type !=3D 0) { + raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfff= c, + GETPC()); + } + new_eip |=3D ((target_ulong)e1) << 32; + } +#endif + if (load_segment_ra(env, &e1, &e2, gate_cs, GETPC()) !=3D 0) { raise_exception_err_ra(env, EXCP0D_GPF, gate_cs & 0xfffc, = GETPC()); } @@ -1675,11 +1705,22 @@ void helper_ljmp_protected(CPUX86State *env, int ne= w_cs, target_ulong new_eip, (!(e2 & DESC_C_MASK) && (dpl !=3D cpl))) { raise_exception_err_ra(env, EXCP0D_GPF, gate_cs & 0xfffc, = GETPC()); } +#ifdef TARGET_X86_64 + if (env->efer & MSR_EFER_LMA) { + if (!(e2 & DESC_L_MASK)) { + raise_exception_err_ra(env, EXCP0D_GPF, gate_cs & 0xff= fc, GETPC()); + } + if (e2 & DESC_B_MASK) { + raise_exception_err_ra(env, EXCP0D_GPF, gate_cs & 0xff= fc, GETPC()); + } + } +#endif if (!(e2 & DESC_P_MASK)) { raise_exception_err_ra(env, EXCP0D_GPF, gate_cs & 0xfffc, = GETPC()); } limit =3D get_seg_limit(e1, e2); - if (new_eip > limit) { + if (new_eip > limit && + (!(env->hflags & HF_LMA_MASK) || !(e2 & DESC_L_MASK))) { raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); } cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl, @@ -1724,12 +1765,12 @@ void helper_lcall_protected(CPUX86State *env, int n= ew_cs, target_ulong new_eip, int shift, target_ulong next_eip) { int new_stack, i; - uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; - uint32_t ss =3D 0, ss_e1 =3D 0, ss_e2 =3D 0, sp, type, ss_dpl, sp_mask; + uint32_t e1, e2, cpl, dpl, rpl, selector, param_count; + uint32_t ss =3D 0, ss_e1 =3D 0, ss_e2 =3D 0, type, ss_dpl, sp_mask; uint32_t val, limit, old_sp_mask; - target_ulong ssp, old_ssp; + target_ulong ssp, old_ssp, offset, sp; =20 - LOG_PCALL("lcall %04x:%08x s=3D%d\n", new_cs, (uint32_t)new_eip, shift= ); + LOG_PCALL("lcall %04x:" TARGET_FMT_lx " s=3D%d\n", new_cs, new_eip, sh= ift); LOG_PCALL_STATE(CPU(x86_env_get_cpu(env))); if ((new_cs & 0xfffc) =3D=3D 0) { raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); @@ -1807,6 +1848,15 @@ void helper_lcall_protected(CPUX86State *env, int ne= w_cs, target_ulong new_eip, type =3D (e2 >> DESC_TYPE_SHIFT) & 0x1f; dpl =3D (e2 >> DESC_DPL_SHIFT) & 3; rpl =3D new_cs & 3; + +#ifdef TARGET_X86_64 + if (env->efer & MSR_EFER_LMA) { + if (type !=3D 12) { + raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, G= ETPC()); + } + } +#endif + switch (type) { case 1: /* available 286 TSS */ case 9: /* available 386 TSS */ @@ -1833,8 +1883,23 @@ void helper_lcall_protected(CPUX86State *env, int ne= w_cs, target_ulong new_eip, raise_exception_err_ra(env, EXCP0B_NOSEG, new_cs & 0xfffc, GE= TPC()); } selector =3D e1 >> 16; - offset =3D (e2 & 0xffff0000) | (e1 & 0x0000ffff); param_count =3D e2 & 0x1f; + offset =3D (e2 & 0xffff0000) | (e1 & 0x0000ffff); +#ifdef TARGET_X86_64 + if (env->efer & MSR_EFER_LMA) { + /* load the upper 8 bytes of the 64-bit call gate */ + if (load_segment_ra(env, &e1, &e2, new_cs + 8, GETPC())) { + raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, + GETPC()); + } + type =3D (e2 >> DESC_TYPE_SHIFT) & 0x1f; + if (type !=3D 0) { + raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, + GETPC()); + } + offset |=3D ((target_ulong)e1) << 32; + } +#endif if ((selector & 0xfffc) =3D=3D 0) { raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); } @@ -1849,46 +1914,80 @@ void helper_lcall_protected(CPUX86State *env, int n= ew_cs, target_ulong new_eip, if (dpl > cpl) { raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GET= PC()); } +#ifdef TARGET_X86_64 + if (env->efer & MSR_EFER_LMA) { + if (!(e2 & DESC_L_MASK)) { + raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc,= GETPC()); + } + if (e2 & DESC_B_MASK) { + raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc,= GETPC()); + } + shift++; + } +#endif if (!(e2 & DESC_P_MASK)) { raise_exception_err_ra(env, EXCP0B_NOSEG, selector & 0xfffc, G= ETPC()); } =20 if (!(e2 & DESC_C_MASK) && dpl < cpl) { /* to inner privilege */ - get_ss_esp_from_tss(env, &ss, &sp, dpl, GETPC()); - LOG_PCALL("new ss:esp=3D%04x:%08x param_count=3D%d env->regs[R= _ESP]=3D" - TARGET_FMT_lx "\n", ss, sp, param_count, - env->regs[R_ESP]); - if ((ss & 0xfffc) =3D=3D 0) { - raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC= ()); - } - if ((ss & 3) !=3D dpl) { - raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC= ()); - } - if (load_segment_ra(env, &ss_e1, &ss_e2, ss, GETPC()) !=3D 0) { - raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC= ()); - } - ss_dpl =3D (ss_e2 >> DESC_DPL_SHIFT) & 3; - if (ss_dpl !=3D dpl) { - raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC= ()); - } - if (!(ss_e2 & DESC_S_MASK) || - (ss_e2 & DESC_CS_MASK) || - !(ss_e2 & DESC_W_MASK)) { - raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC= ()); - } - if (!(ss_e2 & DESC_P_MASK)) { - raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC= ()); +#ifdef TARGET_X86_64 + if (shift =3D=3D 2) { + sp =3D get_rsp_from_tss(env, dpl); + ss =3D dpl; /* SS =3D NULL selector with RPL =3D new CPL = */ + new_stack =3D 1; + sp_mask =3D 0; + ssp =3D 0; /* SS base is always zero in IA-32e mode */ + LOG_PCALL("new ss:rsp=3D%04x:%016llx env->regs[R_ESP]=3D" + TARGET_FMT_lx "\n", ss, sp, env->regs[R_ESP]); + } else +#endif + { + uint32_t sp32; + get_ss_esp_from_tss(env, &ss, &sp32, dpl, GETPC()); + LOG_PCALL("new ss:esp=3D%04x:%08x param_count=3D%d env->re= gs[R_ESP]=3D" + TARGET_FMT_lx "\n", ss, sp32, param_count, + env->regs[R_ESP]); + sp =3D sp32; + if ((ss & 0xfffc) =3D=3D 0) { + raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, G= ETPC()); + } + if ((ss & 3) !=3D dpl) { + raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, G= ETPC()); + } + if (load_segment_ra(env, &ss_e1, &ss_e2, ss, GETPC()) !=3D= 0) { + raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, G= ETPC()); + } + ss_dpl =3D (ss_e2 >> DESC_DPL_SHIFT) & 3; + if (ss_dpl !=3D dpl) { + raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, G= ETPC()); + } + if (!(ss_e2 & DESC_S_MASK) || + (ss_e2 & DESC_CS_MASK) || + !(ss_e2 & DESC_W_MASK)) { + raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, G= ETPC()); + } + if (!(ss_e2 & DESC_P_MASK)) { + raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, G= ETPC()); + } + + sp_mask =3D get_sp_mask(ss_e2); + ssp =3D get_seg_base(ss_e1, ss_e2); } =20 /* push_size =3D ((param_count * 2) + 8) << shift; */ =20 old_sp_mask =3D get_sp_mask(env->segs[R_SS].flags); old_ssp =3D env->segs[R_SS].base; - - sp_mask =3D get_sp_mask(ss_e2); - ssp =3D get_seg_base(ss_e1, ss_e2); - if (shift) { +#ifdef TARGET_X86_64 + if (shift =3D=3D 2) { + /* XXX: verify if new stack address is canonical */ + PUSHQ_RA(sp, env->segs[R_SS].selector, GETPC()); + PUSHQ_RA(sp, env->regs[R_ESP], GETPC()); + /* parameters aren't supported for 64-bit call gates */ + } else +#endif + if (shift =3D=3D 1) { PUSHL_RA(ssp, sp, sp_mask, env->segs[R_SS].selector, GETPC= ()); PUSHL_RA(ssp, sp, sp_mask, env->regs[R_ESP], GETPC()); for (i =3D param_count - 1; i >=3D 0; i--) { @@ -1917,7 +2016,13 @@ void helper_lcall_protected(CPUX86State *env, int ne= w_cs, target_ulong new_eip, new_stack =3D 0; } =20 - if (shift) { +#ifdef TARGET_X86_64 + if (shift =3D=3D 2) { + PUSHQ_RA(sp, env->segs[R_CS].selector, GETPC()); + PUSHQ_RA(sp, next_eip, GETPC()); + } else +#endif + if (shift =3D=3D 1) { PUSHL_RA(ssp, sp, sp_mask, env->segs[R_CS].selector, GETPC()); PUSHL_RA(ssp, sp, sp_mask, next_eip, GETPC()); } else { @@ -1928,11 +2033,18 @@ void helper_lcall_protected(CPUX86State *env, int n= ew_cs, target_ulong new_eip, /* from this point, not restartable */ =20 if (new_stack) { - ss =3D (ss & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_SS, ss, - ssp, - get_seg_limit(ss_e1, ss_e2), - ss_e2); +#ifdef TARGET_X86_64 + if (shift =3D=3D 2) { + cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0); + } else +#endif + { + ss =3D (ss & ~3) | dpl; + cpu_x86_load_seg_cache(env, R_SS, ss, + ssp, + get_seg_limit(ss_e1, ss_e2), + ss_e2); + } } =20 selector =3D (selector & ~3) | dpl; --=20 1.8.3.1