[1/1] x86/vdso: use the right GDT_ENTRY_CPUNODE for 32-bit getcpu() on 64-bit kernel
Message ID | 20230311084824.2340-1-xin3.li@intel.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:5915:0:0:0:0:0 with SMTP id v21csp200025wrd; Sat, 11 Mar 2023 01:34:42 -0800 (PST) X-Google-Smtp-Source: AK7set9jvq8moz07xw5xox4kY5HqGQ+OGRkKu5RKrmQpu7dYUB/cGQJSpp/5oRdR0yLK1JaHxv7Z X-Received: by 2002:a05:6a20:244a:b0:d3:76e0:89fd with SMTP id t10-20020a056a20244a00b000d376e089fdmr1572290pzc.50.1678527282147; Sat, 11 Mar 2023 01:34:42 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1678527282; cv=none; d=google.com; s=arc-20160816; b=fGDIVklO110b7JmcmVnYVPS11xyBrzqbaNzIiLWlrtyvRM5Agqf/aqNWYJKSIitBWp lRZ/cDNpsYbApsAWv2xYTFcbTpDGFwY3xrvTJ1CTnrJ/YjRy1HaDnYDGP3Ri8q6D7lHu jDnZ/w1WQujGQH/U1TBZPiGKJoFPrLw0M8oV/9Rw5k51eoA2MBcCDs2SuVFy1QY4EsVV tV+Hb80to6k4EoIJ+IT0ParnIXrq21ew1DlnEB5ue2wWQ55b8EmctvHCvF658u9E3pRh ZW+zEVLsnY1IRUmuWg03N/SWLngM+wluPO5wmUByUridH9HK/xRDYE+ItiUwUiyAf681 5QLg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:dkim-signature; bh=JDQ+wNhSAGEL6/cCUboVucANIkeGnzMDsZ5qjhrkXEU=; b=J32URxS4ZubuHMktTbqe9by8/HfuoLSEfA+22Q+k/9BDK9ozReX9UDD3vX64e8DjO/ YLfI5NQ+oeLMnqEfn0WHY+kuffSDa+Ss/qa7XVKmKXCU2NvQS6MAXUsOjVII5TaZOXes UorUh6p4d758LHBt46N9wMrZxxuUewrpERhNExLEM+t4izzsNeIDJlVxgBa0opFzREqF alRPofR/YdvetFSPnZrxJv8OwV9WbkUwyEz66yhN6pQU6IIU19OjQNEEW13r9gTCafml KLn4P2R8WWF/SulWRogBV9OohsfjbeUeH3F7XChhkcMNAQg+pIHGVky5H8eEoAfsE7vP hGVA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=Bg1P2NFq; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id z125-20020a636583000000b004fac6261103si1759899pgb.843.2023.03.11.01.34.29; Sat, 11 Mar 2023 01:34:42 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=Bg1P2NFq; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231138AbjCKJSA (ORCPT <rfc822;carlos.wei.hk@gmail.com> + 99 others); Sat, 11 Mar 2023 04:18:00 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38698 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230380AbjCKJRc (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Sat, 11 Mar 2023 04:17:32 -0500 Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8932111F2CC for <linux-kernel@vger.kernel.org>; Sat, 11 Mar 2023 01:15:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1678526107; x=1710062107; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=QYHrC8S+S28GyYZreVjvOCjkTbPe4ZnFhoCEntFwAjw=; b=Bg1P2NFqzMabTnUGM3Uc9eCNpCtJ+wExa5zZMM7uoky42ogpUaI6miHv gYls6nKd+mvsBTez6k7CyKPJQQzDgkeusEnzCcMvJvHKmFLhMNT74FRBV OLjeJ4Tp+du8R7QyIvqtJfyAD2lLcHr8d70/ldSEx1/Od2k0oSs6e9sW9 uRIMhVTEzIOcaf7qZ7JhTyZtA0m3Cki6ifWfOIeXTlhdy0MyWNkgRKpWs nndr9CiVF+XffJFkQ5Q/QsBFpeYui03B5PS1ZIUjbA9gNYH5tAwdU9uTP yFArAIqptO3g3EtJfzHocx/eKDcHsBZu5l6mHcFS0ej+nnfFBO01IDhEW A==; X-IronPort-AV: E=McAfee;i="6500,9779,10645"; a="317279543" X-IronPort-AV: E=Sophos;i="5.98,252,1673942400"; d="scan'208";a="317279543" Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 11 Mar 2023 01:14:15 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10645"; a="742283372" X-IronPort-AV: E=Sophos;i="5.98,252,1673942400"; d="scan'208";a="742283372" Received: from unknown (HELO fred..) ([172.25.112.68]) by fmsmga008.fm.intel.com with ESMTP; 11 Mar 2023 01:14:14 -0800 From: Xin Li <xin3.li@intel.com> To: linux-kernel@vger.kernel.org, x86@kernel.org Cc: tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, hpa@zytor.com, bigeasy@linutronix.de, yujie.liu@intel.com, shan.kang@intel.com Subject: [PATCH 1/1] x86/vdso: use the right GDT_ENTRY_CPUNODE for 32-bit getcpu() on 64-bit kernel Date: Sat, 11 Mar 2023 00:48:24 -0800 Message-Id: <20230311084824.2340-1-xin3.li@intel.com> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-4.4 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_MED, SPF_HELO_NONE,SPF_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1760063423408604768?= X-GMAIL-MSGID: =?utf-8?q?1760063423408604768?= |
Series |
[1/1] x86/vdso: use the right GDT_ENTRY_CPUNODE for 32-bit getcpu() on 64-bit kernel
|
|
Commit Message
Li, Xin3
March 11, 2023, 8:48 a.m. UTC
The vDSO getcpu() reads CPU ID from the GDT_ENTRY_CPUNODE entry when the RDPID
instruction is not available. And GDT_ENTRY_CPUNODE is defined as 28 on 32-bit
Linux kernel and 15 on 64-bit. But the 32-bit getcpu() on 64-bit Linux kernel
is compiled with 32-bit Linux kernel GDT_ENTRY_CPUNODE, i.e., 28, beyond the
64-bit Linux kernel GDT limit. Thus, it just fails _silently_.
Compile the 32-bit getcpu() on 64-bit Linux kernel with the 64-bit Linux kernel
GDT_ENTRY_CPUNODE.
Fixes: 877cff5296faa6e ("x86/vdso: Fake 32bit VDSO build on 64bit compile for vgetcpu")
Reported-by: kernel test robot <yujie.liu@intel.com>
https://lore.kernel.org/oe-lkp/202303020903.b01fd1de-yujie.liu@intel.com/
Reported-by: Shan Kang <shan.kang@intel.com>
Signed-off-by: Xin Li <xin3.li@intel.com>
---
arch/x86/include/asm/segment.h | 4 ++++
1 file changed, 4 insertions(+)
Comments
On 3/11/23 00:48, Xin Li wrote: > #define GDT_ENTRY_ESPFIX_SS 26 > #define GDT_ENTRY_PERCPU 27 > +#ifndef BUILD_VDSO32_64 > #define GDT_ENTRY_CPUNODE 28 > +#else > +#define GDT_ENTRY_CPUNODE 15 > +#endif Isn't this kinda a hack? First, it means that we'll now have two duplicate versions of this: #define GDT_ENTRY_CPUNODE 15 in the same file. Second, if any other users of fake_32bit_build.h for the VDSO show up, they'll need a similar #ifdef. I think I'd much rather if we define all of the GDT_ENTRY_* macros in *one* place, then make that *one* place depend on BUILD_VDSO32_64. Also, about the *silent* failure... Do we not have a selftest for this somewhere?
> > +#ifndef BUILD_VDSO32_64 > > #define GDT_ENTRY_CPUNODE 28 > > +#else > > +#define GDT_ENTRY_CPUNODE 15 > > +#endif > > Isn't this kinda a hack? > > First, it means that we'll now have two duplicate versions of this: > > #define GDT_ENTRY_CPUNODE 15 > > in the same file. > > Second, if any other users of fake_32bit_build.h for the VDSO show up, they'll > need a similar #ifdef. > > I think I'd much rather if we define all of the GDT_ENTRY_* macros in > *one* place, then make that *one* place depend on BUILD_VDSO32_64. Sounds a better way, let me try. > Also, about the *silent* failure... Do we not have a selftest for this somewhere? When lsl is used, we should check ZF which indicates whether the segment limit is loaded successfully. Seems we need to refactor vdso_read_cpunode() a bit. Xin
> > I think I'd much rather if we define all of the GDT_ENTRY_* macros in > > *one* place, then make that *one* place depend on BUILD_VDSO32_64. > > Sounds a better way, let me try. Hi Dave, I tried the following patch, and it works: diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h index 794f69625780..9d6411c65920 100644 --- a/arch/x86/include/asm/segment.h +++ b/arch/x86/include/asm/segment.h @@ -56,7 +56,7 @@ #define GDT_ENTRY_INVALID_SEG 0 -#ifdef CONFIG_X86_32 +#if defined(CONFIG_X86_32) && !defined(BUILD_VDSO32_64) /* * The layout of the per-CPU GDT under Linux: * It's simpler and looks reasonable to me. Is it what you suggested? Thanks! Xin > > > Also, about the *silent* failure... Do we not have a selftest for this > somewhere? > > When lsl is used, we should check ZF which indicates whether the segment limit is > loaded successfully. Seems we need to refactor vdso_read_cpunode() a bit. > > Xin
> -----Original Message----- > From: Li, Xin3 <xin3.li@intel.com> > Sent: Monday, March 13, 2023 10:43 AM > To: Hansen, Dave <dave.hansen@intel.com>; linux-kernel@vger.kernel.org; > x86@kernel.org > Cc: tglx@linutronix.de; mingo@redhat.com; bp@alien8.de; > dave.hansen@linux.intel.com; hpa@zytor.com; bigeasy@linutronix.de; Liu, Yujie > <yujie.liu@intel.com>; Kang, Shan <shan.kang@intel.com> > Subject: RE: [PATCH 1/1] x86/vdso: use the right GDT_ENTRY_CPUNODE for 32-bit > getcpu() on 64-bit kernel > > > > +#ifndef BUILD_VDSO32_64 > > > #define GDT_ENTRY_CPUNODE 28 > > > +#else > > > +#define GDT_ENTRY_CPUNODE 15 > > > +#endif > > > > Isn't this kinda a hack? > > > > First, it means that we'll now have two duplicate versions of this: > > > > #define GDT_ENTRY_CPUNODE 15 > > > > in the same file. > > > > Second, if any other users of fake_32bit_build.h for the VDSO show up, they'll > > need a similar #ifdef. > > > > I think I'd much rather if we define all of the GDT_ENTRY_* macros in > > *one* place, then make that *one* place depend on BUILD_VDSO32_64. > > Sounds a better way, let me try. > > > Also, about the *silent* failure... Do we not have a selftest for this somewhere? > > When lsl is used, we should check ZF which indicates whether the segment limit > is loaded successfully. Seems we need to refactor vdso_read_cpunode() a bit. Hi Dave, How about the following patch to address the silent failure? diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h index 794f69625780..d75ce4afff5b 100644 --- a/arch/x86/include/asm/segment.h +++ b/arch/x86/include/asm/segment.h @@ -254,7 +254,10 @@ static inline void vdso_read_cpunode(unsigned *cpu, unsigned *node) * * If RDPID is available, use it. */ - alternative_io ("lsl %[seg],%[p]", + alternative_io ("lsl %[seg],%[p]\n" + "jz 1f\n" + "mov $-1,%[p]\n" + "1:", ".byte 0xf3,0x0f,0xc7,0xf8", /* RDPID %eax/rax */ X86_FEATURE_RDPID, [p] "=a" (p), [seg] "r" (__CPUNODE_SEG)); And the test then reports CPU id 4095 (not a big enough #), which can be used to indicate a failure of the lsl instruction: ~/selftests$ sudo ./run_kselftest.sh -t x86:test_vsyscall_32 TAP version 13 1..1 # selftests: x86: test_vsyscall_32 # [RUN] test gettimeofday() # vDSO time offsets: 0.000028 0.000000 # [OK] vDSO gettimeofday()'s timeval was okay # [RUN] test time() # [OK] vDSO time() is okay # [RUN] getcpu() on CPU 0 # [FAIL] vDSO reported CPU 4095 but should be 0 # [FAIL] vDSO reported node 65535 but should be 0 # [RUN] getcpu() on CPU 1 # [FAIL] vDSO reported CPU 4095 but should be 1 # [FAIL] vDSO reported node 65535 but should be 0 not ok 1 selftests: x86: test_vsyscall_32 # exit=1 Thanks! Xin
> > > > +#ifndef BUILD_VDSO32_64 > > > > #define GDT_ENTRY_CPUNODE 28 > > > > +#else > > > > +#define GDT_ENTRY_CPUNODE 15 > > > > +#endif > > > > > > Isn't this kinda a hack? > > > > > > First, it means that we'll now have two duplicate versions of this: > > > > > > #define GDT_ENTRY_CPUNODE 15 > > > > > > in the same file. > > > > > > Second, if any other users of fake_32bit_build.h for the VDSO show > > > up, they'll need a similar #ifdef. > > > > > > I think I'd much rather if we define all of the GDT_ENTRY_* macros > > > in > > > *one* place, then make that *one* place depend on BUILD_VDSO32_64. > > > > Sounds a better way, let me try. > > > > > Also, about the *silent* failure... Do we not have a selftest for this somewhere? > > > > When lsl is used, we should check ZF which indicates whether the > > segment limit is loaded successfully. Seems we need to refactor > vdso_read_cpunode() a bit. > > Hi Dave, > > How about the following patch to address the silent failure? > > diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h > index 794f69625780..d75ce4afff5b 100644 > --- a/arch/x86/include/asm/segment.h > +++ b/arch/x86/include/asm/segment.h > @@ -254,7 +254,10 @@ static inline void vdso_read_cpunode(unsigned *cpu, > unsigned *node) > * > * If RDPID is available, use it. > */ > - alternative_io ("lsl %[seg],%[p]", > + alternative_io ("lsl %[seg],%[p]\n" > + "jz 1f\n" > + "mov $-1,%[p]\n" > + "1:", > ".byte 0xf3,0x0f,0xc7,0xf8", /* RDPID %eax/rax */ > X86_FEATURE_RDPID, > [p] "=a" (p), [seg] "r" (__CPUNODE_SEG)); > > > And the test then reports CPU id 4095 (not a big enough #), which can be used to > indicate a failure of the lsl instruction: Having to say, it's a *bad* idea to use a special # to indicate an error. But there is also no reasonable errno for getcpu() to return to its caller, saying "we had a problem in the syscall's kernel implementation". > > ~/selftests$ sudo ./run_kselftest.sh -t x86:test_vsyscall_32 TAP version 13 > 1..1 > # selftests: x86: test_vsyscall_32 > # [RUN] test gettimeofday() > # vDSO time offsets: 0.000028 0.000000 > # [OK] vDSO gettimeofday()'s timeval was okay # [RUN] test time() # [OK] vDSO > time() is okay # [RUN] getcpu() on CPU 0 > # [FAIL] vDSO reported CPU 4095 but should be 0 > # [FAIL] vDSO reported node 65535 but should be 0 > # [RUN] getcpu() on CPU 1 > # [FAIL] vDSO reported CPU 4095 but should be 1 > # [FAIL] vDSO reported node 65535 but should be 0 > not ok 1 selftests: x86: test_vsyscall_32 # exit=1 > > Thanks! > Xin
On March 29, 2023 4:11:09 PM PDT, "Li, Xin3" <xin3.li@intel.com> wrote: >> > > > +#ifndef BUILD_VDSO32_64 >> > > > #define GDT_ENTRY_CPUNODE 28 >> > > > +#else >> > > > +#define GDT_ENTRY_CPUNODE 15 >> > > > +#endif >> > > >> > > Isn't this kinda a hack? >> > > >> > > First, it means that we'll now have two duplicate versions of this: >> > > >> > > #define GDT_ENTRY_CPUNODE 15 >> > > >> > > in the same file. >> > > >> > > Second, if any other users of fake_32bit_build.h for the VDSO show >> > > up, they'll need a similar #ifdef. >> > > >> > > I think I'd much rather if we define all of the GDT_ENTRY_* macros >> > > in >> > > *one* place, then make that *one* place depend on BUILD_VDSO32_64. >> > >> > Sounds a better way, let me try. >> > >> > > Also, about the *silent* failure... Do we not have a selftest for this somewhere? >> > >> > When lsl is used, we should check ZF which indicates whether the >> > segment limit is loaded successfully. Seems we need to refactor >> vdso_read_cpunode() a bit. >> >> Hi Dave, >> >> How about the following patch to address the silent failure? >> >> diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h >> index 794f69625780..d75ce4afff5b 100644 >> --- a/arch/x86/include/asm/segment.h >> +++ b/arch/x86/include/asm/segment.h >> @@ -254,7 +254,10 @@ static inline void vdso_read_cpunode(unsigned *cpu, >> unsigned *node) >> * >> * If RDPID is available, use it. >> */ >> - alternative_io ("lsl %[seg],%[p]", >> + alternative_io ("lsl %[seg],%[p]\n" >> + "jz 1f\n" >> + "mov $-1,%[p]\n" >> + "1:", >> ".byte 0xf3,0x0f,0xc7,0xf8", /* RDPID %eax/rax */ >> X86_FEATURE_RDPID, >> [p] "=a" (p), [seg] "r" (__CPUNODE_SEG)); >> >> >> And the test then reports CPU id 4095 (not a big enough #), which can be used to >> indicate a failure of the lsl instruction: > >Having to say, it's a *bad* idea to use a special # to indicate an error. >But there is also no reasonable errno for getcpu() to return to its caller, >saying "we had a problem in the syscall's kernel implementation". > >> >> ~/selftests$ sudo ./run_kselftest.sh -t x86:test_vsyscall_32 TAP version 13 >> 1..1 >> # selftests: x86: test_vsyscall_32 >> # [RUN] test gettimeofday() >> # vDSO time offsets: 0.000028 0.000000 >> # [OK] vDSO gettimeofday()'s timeval was okay # [RUN] test time() # [OK] vDSO >> time() is okay # [RUN] getcpu() on CPU 0 >> # [FAIL] vDSO reported CPU 4095 but should be 0 >> # [FAIL] vDSO reported node 65535 but should be 0 >> # [RUN] getcpu() on CPU 1 >> # [FAIL] vDSO reported CPU 4095 but should be 1 >> # [FAIL] vDSO reported node 65535 but should be 0 >> not ok 1 selftests: x86: test_vsyscall_32 # exit=1 >> >> Thanks! >> Xin > I don't think we should put a test in the vdso implementation. We need a self test, to be sure, and we should check that LSL works standalone (because of Oracle et al), but putting an assert like this in the vdso is like of odd at best. If we *do* put in a test, it should trap to the kernel, not return an errno, because it is the equivalent of putting a BUG() in the kernel. In this case we can even do better, because we can execute the getcpu system call at that point. But... why? We generally trust the kernel implementation.
diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h index 794f69625780..d3b4f8797054 100644 --- a/arch/x86/include/asm/segment.h +++ b/arch/x86/include/asm/segment.h @@ -119,7 +119,11 @@ #define GDT_ENTRY_ESPFIX_SS 26 #define GDT_ENTRY_PERCPU 27 +#ifndef BUILD_VDSO32_64 #define GDT_ENTRY_CPUNODE 28 +#else +#define GDT_ENTRY_CPUNODE 15 +#endif #define GDT_ENTRY_DOUBLEFAULT_TSS 31