From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-ot1-f73.google.com (mail-ot1-f73.google.com [209.85.210.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 10ED036897F for ; Tue, 26 May 2026 20:50:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.73 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779828663; cv=none; b=qGbuMhzM//ENY4Mbco7iVZeTI3WA8DYzDVuczdf9+k4Rm/Y7zFZWDPcQxCatbsT8S3uNgMvcknWWgy0fnXUz4NlKeNPzIuAUd6WVXc/I4l6ZTuA5M21/gnYqQ1MRr2dZjMyjg72iN1oy9gaYFkgGM8tmpTr+bK+frc7MC3DuM5Y= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779828663; c=relaxed/simple; bh=Y/Hu9e3zSHfwdWFG+X3/uktTcNCH7rQMAM/1ljhN7z4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=PSZTDhyxPun7yMjLomdsAdjmCKwGORex50SVTwadNnpxx0qDgzXwJ9+P77VnaW3mL3a4L9uf0IGU2QVf7o3qqX1Z8NRzae+MBbbL5Ho24rw9gig9zdIzRm7wh/dBFo42e44/fNc9p0vM2qSfzmFIkyxTzA1q3wWgGPQCriSSjEI= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--avagin.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=QA5BKsh+; arc=none smtp.client-ip=209.85.210.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--avagin.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="QA5BKsh+" Received: by mail-ot1-f73.google.com with SMTP id 46e09a7af769-7e4de59797fso19524461a34.3 for ; Tue, 26 May 2026 13:50:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1779828659; x=1780433459; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=n8KUXA/d96RBjC0Y4Zfx1FxudOdO0Ayo4L4twhKZSeU=; b=QA5BKsh+vMyVdyHKHL68CIv/ck/N+Oz18/cTSXK9ucwsv0IFzQSFWpfdktqGxY3Nk4 OpD5i3KYzv/deTw7dN/2T4ROPum5DpCNo59/Bz+NR/vjceWft4Fozizi6hy/o5UDHmcG Bj4qmuWfOqxaq3rYNYQJioVjyRB6On7iJzCh2q5y18GDA3UHw+VkyWsP7CMUimshhR3P aYFsDMf8uyWGJIRicgmd8FAvhw7V7M4Ah2NpO2QcTCCgOLwzrWuMuSh0h9iH1j9TTLlt zJPXYv2UDftQdCXpzXg+RbOOrgNrrHZr3j9g6ulfzDVT51IbR6FNjebgZKCvntP/XNsX HQQg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779828659; x=1780433459; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=n8KUXA/d96RBjC0Y4Zfx1FxudOdO0Ayo4L4twhKZSeU=; b=OpVEa0AFsvjPE9VE8xmIQPBZC6/3KfUdssYYsbMiT7BEXQ488TEpIkFo7gAiff9Z0d zLJ5muTB5sL5WGWMBsX4yFNrXtm63C289G5OXFDk1EDfWLK2voVUxHaB/zWB6q0Z5uGT 3XtfL7f3in43IAOGUlrVLbTkYy6KN75CEYFTaHdxN7E1DUNBR6Q5FO7Gsv11kc9DV0fQ t6Qi/ly3jibJjct7/esvBGmeFaG45mW08ILimpF6xZOV4JxFgAkDuLlf5uXWnqXT+R9e Q0JTbjoU+WIXVI/e4GlWMCxNRh7jV2WqD9aV3x/ADVRbQdGL8OJQV4MDSRD5/BU7f1Op G6HA== X-Gm-Message-State: AOJu0Yx926GwKillaFPKyBOEUcT9R2OzjYAYg1i4zOH8KpkqH4tVFuIO HD0KJO5Prffv0Yxqhy6WJ/dBL1H8ttUaPmAFBvJtBhNEYYZMUCkCZKQAPRJxv/CRcOzpu6eC4HQ o0H6oVQ== X-Received: from jahe16.prod.google.com ([2002:a05:6638:85d0:b0:5d9:476f:67cd]) (user=avagin job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6820:1f05:b0:69b:bf80:2db3 with SMTP id 006d021491bc7-69d7ec8a6aamr11327290eaf.44.1779828658872; Tue, 26 May 2026 13:50:58 -0700 (PDT) Date: Tue, 26 May 2026 20:50:47 +0000 In-Reply-To: <20260526205047.3339490-1-avagin@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260526205047.3339490-1-avagin@google.com> X-Mailer: git-send-email 2.54.0.746.g67dd491aae-goog Message-ID: <20260526205047.3339490-6-avagin@google.com> Subject: [PATCH 5/5] selftests/x86: Add a consistency test for signal frames From: Andrei Vagin To: Thomas Gleixner , Ingo Molnar Cc: linux-kernel@vger.kernel.org, criu@lists.linux.dev, Borislav Petkov , Dave Hansen , x86@kernel.org, Andrei Vagin , "H. Peter Anvin" , "Chang S. Bae" Content-Type: text/plain; charset="UTF-8" Extend sigframe_portability test to include a consistency check. Verify that the kernel correctly rejects signal frames where the xstate_size is too small for the enabled features in the xfeatures mask. Refactor the test to use separate helpers for portability and consistency test cases, each with its own signal handler. Signed-off-by: Andrei Vagin --- .../selftests/x86/sigframe_portability.c | 106 +++++++++++++----- tools/testing/selftests/x86/xstate.h | 5 + 2 files changed, 81 insertions(+), 30 deletions(-) diff --git a/tools/testing/selftests/x86/sigframe_portability.c b/tools/testing/selftests/x86/sigframe_portability.c index 8888079a153a..a60aa4d20dd1 100644 --- a/tools/testing/selftests/x86/sigframe_portability.c +++ b/tools/testing/selftests/x86/sigframe_portability.c @@ -17,13 +17,14 @@ #include "xstate.h" /* - * This test verifies the portability of the signal frame. - * It simulates a scenario where a signal frame is created on a system with - * fewer xstate features and restored on a system with more features. + * This test verifies the portability and consistency of the signal frame. + * Portability: A frame created on a system with fewer features can be + * restored on a system with more features. + * Consistency: The kernel rejects frames where xstate_size is insufficient + * for the features enabled in xfeatures. */ #define SIGFRAME_XSTATE_HDR_OFFSET 512 - #define XSTATE_SSE_ONLY_SIZE (SIGFRAME_XSTATE_HDR_OFFSET + XSAVE_HDR_SIZE) #define XFEATURE_MASK_FPSSE ((1 << XFEATURE_FP) | (1 << XFEATURE_SSE)) @@ -55,7 +56,17 @@ static void check_avx_support(void) #define TEST_YMMH_VAL (0x5656565656565656UL) -static void handle_signal(int sig, siginfo_t *si, void *ucp) +static void read_ymm0(uint64_t *v) +{ + asm volatile ("vmovdqu %%ymm0, %0" : "=m" (*(char (*)[32])v)); +} + +static void write_ymm0(uint64_t *v) +{ + asm volatile ("vmovdqu %0, %%ymm0" : : "m" (*(char (*)[32])v)); +} + +static void handle_portability(int sig, siginfo_t *si, void *ucp) { ucontext_t *uc = ucp; void *fp = uc->uc_mcontext.fpregs; @@ -72,18 +83,14 @@ static void handle_signal(int sig, siginfo_t *si, void *ucp) xbuf = (struct xsave_buffer *)fp; - if (sw->xstate_size < xstate_size_ymm) { - snprintf(sig_err_buf, SIGNAL_BUF_LEN, - "xstate size is too small: %d (expected %d or greater)", - sw->xstate_size, xstate_size_ymm); - return; - } - + /* Shrink the frame to just YMM size */ sw->xstate_size = xstate_size_ymm; xfeatures = get_xstatebv(xbuf); xfeatures &= XFEATURE_MASK_FPSSE | (1 << XFEATURE_YMM); set_xstatebv(xbuf, xfeatures); + /* Also update sw->xfeatures as the kernel relies on it */ + set_fpx_sw_bytes_features(fp, xfeatures); *(uint32_t *)(fp + sw->xstate_size) = FP_XSTATE_MAGIC2; @@ -96,26 +103,12 @@ static void handle_signal(int sig, siginfo_t *si, void *ucp) memset(fp + sw->xstate_size + 4, 0, sw->extended_size - sw->xstate_size - 4); } -static void read_ymm0(uint64_t *v) -{ - asm volatile ("vmovdqu %%ymm0, %0" : "=m" (*(char (*)[32])v)); -} - -static void write_ymm0(uint64_t *v) -{ - asm volatile ("vmovdqu %0, %%ymm0" : : "m" (*(char (*)[32])v)); -} - -int main(void) +static void test_portability(void) { uint64_t v[4] = {0, 0, 0, 0}; - ksft_print_header(); - ksft_set_plan(1); - - check_avx_support(); - - sethandler(SIGUSR1, handle_signal, 0); + sig_err_buf[0] = 0; + sethandler(SIGUSR1, handle_portability, 0); v[0] = 0x1111111111111111ULL; v[1] = 0x2222222222222222ULL; @@ -130,13 +123,66 @@ int main(void) if (sig_err_buf[0]) ksft_test_result_fail("%s\n", sig_err_buf); else if (v[2] == TEST_YMMH_VAL && v[3] == (TEST_YMMH_VAL + 1)) - ksft_test_result_pass("YMM state restored correctly\n"); + ksft_test_result_pass("YMM state restored correctly from shrunk frame\n"); else ksft_test_result_fail( "Got upper bits: 0x%lx 0x%lx (expected %lx %lx)\n", v[2], v[3], TEST_YMMH_VAL, TEST_YMMH_VAL + 1); clearhandler(SIGUSR1); +} + +static void handle_consistency(int sig, siginfo_t *si, void *ucp) +{ + ucontext_t *uc = ucp; + void *fp = uc->uc_mcontext.fpregs; + struct _fpx_sw_bytes *sw = get_fpx_sw_bytes(fp); + + /* The origin frame contains an AVX state. */ + sw->xstate_size = XSTATE_SSE_ONLY_SIZE; + + *(uint32_t *)(fp + sw->xstate_size) = FP_XSTATE_MAGIC2; +} + +static void test_consistency(void) +{ + uint64_t v[4] = {0, 0, 0, 0}; + + sig_err_buf[0] = 0; + sethandler(SIGUSR2, handle_consistency, 0); + + v[0] = 0x1111111111111111ULL; + v[1] = 0x2222222222222222ULL; + v[2] = 0x3333333333333333ULL; + v[3] = 0x4444444444444444ULL; + write_ymm0(v); + + raise(SIGUSR2); + v[0] = v[1] = v[2] = v[3] = 0; + read_ymm0(v); + + /* + * When inconsistent, the kernel should have fallen back to + * FX-only mode, so YMM upper bits should be zero (init state). + */ + if (v[2] == 0 && v[3] == 0) + ksft_test_result_pass("Inconsistent size correctly rejected\n"); + else + ksft_test_result_fail("Inconsistent size was NOT rejected: 0x%lx 0x%lx\n", + v[2], v[3]); + + clearhandler(SIGUSR2); +} + +int main(void) +{ + ksft_print_header(); + ksft_set_plan(2); + + check_avx_support(); + + test_portability(); + test_consistency(); ksft_finished(); return 0; diff --git a/tools/testing/selftests/x86/xstate.h b/tools/testing/selftests/x86/xstate.h index b24501b621f3..c531667b66ad 100644 --- a/tools/testing/selftests/x86/xstate.h +++ b/tools/testing/selftests/x86/xstate.h @@ -182,6 +182,11 @@ static inline uint64_t get_fpx_sw_bytes_features(void *buffer) return *(uint64_t *)(buffer + SW_BYTES_BV_OFFSET); } +static inline void set_fpx_sw_bytes_features(void *buffer, uint64_t features) +{ + *(uint64_t *)(buffer + SW_BYTES_BV_OFFSET) = features; +} + static inline void set_rand_data(struct xstate_info *xstate, struct xsave_buffer *xbuf) { int *ptr = (int *)&xbuf->bytes[xstate->xbuf_offset]; -- 2.54.0.746.g67dd491aae-goog