From patchwork Wed Sep 20 15:08:52 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Beulich X-Patchwork-Id: 9961619 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 868D1602D8 for ; Wed, 20 Sep 2017 15:11:11 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 74A1929093 for ; Wed, 20 Sep 2017 15:11:11 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 72DA0291B7; Wed, 20 Sep 2017 15:11:11 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 892EA29093 for ; Wed, 20 Sep 2017 15:11:05 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dugcU-0004o9-8G; Wed, 20 Sep 2017 15:08:58 +0000 Received: from mail6.bemta6.messagelabs.com ([193.109.254.103]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dugcT-0004o0-E0 for xen-devel@lists.xenproject.org; Wed, 20 Sep 2017 15:08:57 +0000 Received: from [85.158.143.35] by server-1.bemta-6.messagelabs.com id 91/58-03414-88482C95; Wed, 20 Sep 2017 15:08:56 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrEIsWRWlGSWpSXmKPExsXS6fjDS7ej5VC kwfz5nBbft0xmcmD0OPzhCksAYxRrZl5SfkUCa0bLlWNsBdM1Kjp+fGdtYLwq18XIySEkkCdx acFSdhCbV8BOYuveW2wgtoSAocTphTdZuhg5OFgEVCUaN6uBhNkE1CXanm1nBQmLCBhInDuaB GIyC+hLbFvHAlIhLOAsMWPfZxaI4XYSR04uZwIp4RUQlPi7QxgkzCygJfHw1y0WCFtbYtnC18 wQU6Qllv/jmMDIOwuhYRaShllIGmYhNCxgZFnFqFGcWlSWWqRrZKSXVJSZnlGSm5iZo2toYKa Xm1pcnJiempOYVKyXnJ+7iREYXgxAsINxzfzAQ4ySHExKoryZjYcihfiS8lMqMxKLM+KLSnNS iw8xynBwKEnw8jYD5QSLUtNTK9Iyc4CBDpOW4OBREuF1BknzFhck5hZnpkOkTjHqcnTcvPuHS YglLz8vVUqc1xykSACkKKM0D24ELOouMcpKCfMyAh0lxFOQWpSbWYIq/4pRnINRSZg3E2QKT2 ZeCdymV0BHMAEdkb3hAMgRJYkIKakGRlZ/VZOFjusWrvwmbD9p1x6L+B/di6o8Qh7s2+Cnrqh +oumBS3qCCl/GYZUzr3ZVz5bi8S+cfs69/O5j2dAPFzc8+CfdcWfPLO6qkCDPHitFsXzew3+V fIxD7B+5WFacz37xbY/ZivnZf8t379zHHnBAlWOiMs9XnS82r64kJFWfVLt/0Lm2W4mlOCPRU Iu5qDgRABEismm1AgAA X-Env-Sender: JBeulich@suse.com X-Msg-Ref: server-8.tower-21.messagelabs.com!1505920134!83689328!1 X-Originating-IP: [137.65.248.74] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 9.4.45; banners=-,-,- X-VirusChecked: Checked Received: (qmail 54644 invoked from network); 20 Sep 2017 15:08:55 -0000 Received: from prv-mh.provo.novell.com (HELO prv-mh.provo.novell.com) (137.65.248.74) by server-8.tower-21.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 20 Sep 2017 15:08:55 -0000 Received: from INET-PRV-MTA by prv-mh.provo.novell.com with Novell_GroupWise; Wed, 20 Sep 2017 09:08:53 -0600 Message-Id: <59C2A0A4020000780017D82A@prv-mh.provo.novell.com> X-Mailer: Novell GroupWise Internet Agent 14.2.2 Date: Wed, 20 Sep 2017 09:08:52 -0600 From: "Jan Beulich" To: "xen-devel" References: <59C2A0A4020000780017D82A@prv-mh.provo.novell.com> Mime-Version: 1.0 Content-Disposition: inline Cc: Andrew Cooper Subject: [Xen-devel] [PATCH] x86/PV: fix/generalize guest nul selector handling X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP FS/GS base (and limit) aren't being cleared by the loading of a nul selector into the segment register on AMD CPUs. Therefore, if an outgoing vCPU has a non-null base in one of these registers and the subsequent incoming vCPU has a non-zero but nul selector in the respective register(s), the selector value(s) would be loaded without clearing the segment base(s) in the hidden register portion. Since the ABI states "zero" in its description of the fields, it is worth noting that the chosen approach to fix this alters the written down ABI. I consider this preferrable over enforcing the previously written down behavior, as nul selectors are far more likely to be what was meant from the beginning. The adjustments also eliminate an inconsistency between FS and GS handling: Old code had an extra pointless (gs_base_user was always zero when DIRTY_GS was set) conditional for GS. The old bitkeeper changeset has no explanation for this asymmetry. Inspired by Linux commit e137a4d8f4dd2e277e355495b6b2cb241a8693c3. Signed-off-by: Jan Beulich --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -1260,30 +1260,28 @@ static void load_segments(struct vcpu *n if ( unlikely((dirty_segment_mask & DIRTY_ES) | uregs->es) ) all_segs_okay &= loadsegment(es, uregs->es); - /* - * Either selector != 0 ==> reload. - * Also reload to reset FS_BASE if it was non-zero. - */ - if ( unlikely((dirty_segment_mask & (DIRTY_FS | DIRTY_FS_BASE)) | - uregs->fs) ) + /* Either selector != 0 ==> reload. */ + if ( unlikely((dirty_segment_mask & DIRTY_FS) | uregs->fs) ) + { all_segs_okay &= loadsegment(fs, uregs->fs); + /* non-nul selector updates fs_base */ + if ( uregs->fs & ~3 ) + dirty_segment_mask &= ~DIRTY_FS_BASE; + } - /* - * Either selector != 0 ==> reload. - * Also reload to reset GS_BASE if it was non-zero. - */ - if ( unlikely((dirty_segment_mask & (DIRTY_GS | DIRTY_GS_BASE_USER)) | - uregs->gs) ) - { - /* Reset GS_BASE with user %gs? */ - if ( (dirty_segment_mask & DIRTY_GS) || !n->arch.pv_vcpu.gs_base_user ) - all_segs_okay &= loadsegment(gs, uregs->gs); + /* Either selector != 0 ==> reload. */ + if ( unlikely((dirty_segment_mask & DIRTY_GS) | uregs->gs) ) + { + all_segs_okay &= loadsegment(gs, uregs->gs); + /* non-nul selector updates gs_base_user */ + if ( uregs->gs & ~3 ) + dirty_segment_mask &= ~DIRTY_GS_BASE_USER; } if ( !is_pv_32bit_vcpu(n) ) { /* This can only be non-zero if selector is NULL. */ - if ( n->arch.pv_vcpu.fs_base ) + if ( n->arch.pv_vcpu.fs_base | (dirty_segment_mask & DIRTY_FS_BASE) ) wrfsbase(n->arch.pv_vcpu.fs_base); /* Most kernels have non-zero GS base, so don't bother testing. */ @@ -1291,7 +1289,8 @@ static void load_segments(struct vcpu *n wrmsrl(MSR_SHADOW_GS_BASE, n->arch.pv_vcpu.gs_base_kernel); /* This can only be non-zero if selector is NULL. */ - if ( n->arch.pv_vcpu.gs_base_user ) + if ( n->arch.pv_vcpu.gs_base_user | + (dirty_segment_mask & DIRTY_GS_BASE_USER) ) wrgsbase(n->arch.pv_vcpu.gs_base_user); /* If in kernel mode then switch the GS bases around. */ @@ -1426,22 +1425,22 @@ static void save_segments(struct vcpu *v if ( regs->fs || is_pv_32bit_vcpu(v) ) { dirty_segment_mask |= DIRTY_FS; - v->arch.pv_vcpu.fs_base = 0; /* != 0 selector kills fs_base */ + /* non-nul selector kills fs_base */ + if ( regs->fs & ~3 ) + v->arch.pv_vcpu.fs_base = 0; } - else if ( v->arch.pv_vcpu.fs_base ) - { + if ( v->arch.pv_vcpu.fs_base ) dirty_segment_mask |= DIRTY_FS_BASE; - } if ( regs->gs || is_pv_32bit_vcpu(v) ) { dirty_segment_mask |= DIRTY_GS; - v->arch.pv_vcpu.gs_base_user = 0; /* != 0 selector kills gs_base_user */ + /* non-nul selector kills gs_base_user */ + if ( regs->gs & ~3 ) + v->arch.pv_vcpu.gs_base_user = 0; } - else if ( v->arch.pv_vcpu.gs_base_user ) - { + if ( v->arch.pv_vcpu.gs_base_user ) dirty_segment_mask |= DIRTY_GS_BASE_USER; - } this_cpu(dirty_segment_mask) = dirty_segment_mask; } --- a/xen/include/public/arch-x86/xen-x86_64.h +++ b/xen/include/public/arch-x86/xen-x86_64.h @@ -203,8 +203,8 @@ struct cpu_user_regs { uint16_t ss, _pad2[3]; uint16_t es, _pad3[3]; uint16_t ds, _pad4[3]; - uint16_t fs, _pad5[3]; /* Non-zero => takes precedence over fs_base. */ - uint16_t gs, _pad6[3]; /* Non-zero => takes precedence over gs_base_usr. */ + uint16_t fs, _pad5[3]; /* Non-nul => takes precedence over fs_base. */ + uint16_t gs, _pad6[3]; /* Non-nul => takes precedence over gs_base_user. */ }; typedef struct cpu_user_regs cpu_user_regs_t; DEFINE_XEN_GUEST_HANDLE(cpu_user_regs_t);