From nobody Fri Mar 27 01:30:54 2026 Received: from mail-oo1-f74.google.com (mail-oo1-f74.google.com [209.85.161.74]) (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 606B83C8707 for ; Mon, 23 Mar 2026 17:54:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.161.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774288446; cv=none; b=uwnn71hHz6UY6xfzGm0FABzM9lrFlB9CUvV0lopqlNlVyvaZoTEc6qGdEkJCi068n3lovZrVfF1JBYiNMDi/GSAdtiwlTqtG+rX+WwEFB2cCHvYrbcvkh9+09FgEXsLJT61rdyJlbKEfnHp0zucnO1C7ix2eGxcO6H/oELx2TI0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774288446; c=relaxed/simple; bh=FjP+aluhuSk+QvkW7jIfR0+lzCaysUDCcukwZWJE8gA=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=SrsMW6ak3wSi5M15NDK6+iepj50x0itwpAZvMUNF/VPAuupmdyKQj6BzFIjXlT4hayj9kWAUL5toTOXPr9dyXhtlXplxcl3k/V7fbdrb0dsXvvIYKm4UaIlE6eqFoxBMd2ZNX+V9yhjGSMp8bJVZlspTqGKVTBDcPxbL6HCmj9I= 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=C5wvDHKd; arc=none smtp.client-ip=209.85.161.74 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="C5wvDHKd" Received: by mail-oo1-f74.google.com with SMTP id 006d021491bc7-67de194504eso34546196eaf.1 for ; Mon, 23 Mar 2026 10:54:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1774288443; x=1774893243; 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=2zwENltoNbnweMynAxDGHTh9/E9UWCZ6oWdo8zpud4I=; b=C5wvDHKdjptnX0GHraZh5uWtuaNat+VFLuRMiKWrSO+LtBv39RvZq5h1hVTibiAn0e Ai/Y4zQfR/52FyT58L/8dfZAJNltSo6/JuSeFyJlD3UFaSDiDeE/zzWozzrqzMPFELdU tbCaPqefea/N3uw+WDnU3DBsVAigDDBhsTlpFvsyCaRr1aS0WCwwPyhYoBV4usfwX7iw Ce/mIx6oPpDWyUoFCN87/7yMW7XwJjyk35bUGzofWhw/ixviRSjQypW0CIoA8OpsO9SO qdTPQPZgaVMX4w6E5lH2OIeX1gMmKLPnO9i6YpJ0p4qdU3U1k+Lj/TzqyTsjQuHdEguX SkRg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774288443; x=1774893243; 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=2zwENltoNbnweMynAxDGHTh9/E9UWCZ6oWdo8zpud4I=; b=NSSPKAcLkyr7Z4MM64oT6SiLRcl8WbWweTM/l6bqcahwn+RLOuBVNwZeAKIOxKciRU BREfSStnCO4YYTf4/fmS5GvTUQwwz7NUnMtVQ7JvVhxy85ZTj1Umww5K9rG13bL7d/Gm hdnSIgGABtSNM+4WTOGdP9io6ap9hlcpdPikQ9O7k8aDRggNpNmdWuhw4PHHSgBVLShW lfFrEFDSHLimVH/cqLOBGKUg9JXmkYRw4anJf7ekvRis4pJZjGjqSX4LC2+hPncbvUAN j2sGdvgcq/N5Dlxqb3J1qTDz1Z+2G8bmA/NmkK29FJvB6lj6Ph+Fy1HJdK6jWbFBiAoc 34MA== X-Forwarded-Encrypted: i=1; AJvYcCXwTANexzLxx+Q1WfquvunQxvl0kxUYVX873+zXf3XPcgnbJAt72eMu1hKSmqHONbKwoc6dXKNythVNCtE=@vger.kernel.org X-Gm-Message-State: AOJu0Yxwrh7rpDsq2/ZpsAodTDPUOmMI4A5m9ZHMCyKTaBBZojURCxb9 vQTvpbCjzUURb6uBXvct/zH3BkQX0bxUup+tfPal54nO+17k5K3sfWtE7Jo2TH2c/1y/6cm7aQD 13YQDOA== X-Received: from ilff9.prod.google.com ([2002:a05:6e02:5e09:b0:4f7:a419:df90]) (user=avagin job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6820:8ca:b0:67c:e54:2a7c with SMTP id 006d021491bc7-67c22f92886mr8704682eaf.61.1774288443094; Mon, 23 Mar 2026 10:54:03 -0700 (PDT) Date: Mon, 23 Mar 2026 17:53:37 +0000 In-Reply-To: <20260323175340.3361311-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: <20260323175340.3361311-1-avagin@google.com> X-Mailer: git-send-email 2.53.0.983.g0bb29b3bc5-goog Message-ID: <20260323175340.3361311-2-avagin@google.com> Subject: [PATCH 1/4] exec: inherit HWCAPs from the parent process From: Andrei Vagin To: Kees Cook , Andrew Morton Cc: Marek Szyprowski , Cyrill Gorcunov , Mike Rapoport , Alexander Mikhalitsyn , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-mm@kvack.org, criu@lists.linux.dev, Catalin Marinas , Will Deacon , linux-arm-kernel@lists.infradead.org, Chen Ridong , Christian Brauner , David Hildenbrand , Eric Biederman , Lorenzo Stoakes , Michal Koutny , Andrei Vagin , Alexander Mikhalitsyn Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Introduces a mechanism to inherit hardware capabilities (AT_HWCAP, AT_HWCAP2, etc.) from a parent process when they have been modified via prctl. To support C/R operations (snapshots, live migration) in heterogeneous clusters, we must ensure that processes utilize CPU features available on all potential target nodes. To solve this, we need to advertise a common feature set across the cluster. This patch adds a new mm flag MMF_USER_HWCAP, which is set when the auxiliary vector is modified via prctl(PR_SET_MM, PR_SET_MM_AUXV). When execve() is called, if the current process has MMF_USER_HWCAP set, the HWCAP values are extracted from the current auxiliary vector and stored in the linux_binprm structure. These values are then used to populate the auxiliary vector of the new process, effectively inheriting the hardware capabilities. The inherited HWCAPs are masked with the hardware capabilities supported by the current kernel to ensure that we don't report more features than actually supported. This is important to avoid unexpected behavior, especially for processes with additional privileges. Reviewed-by: Cyrill Gorcunov Reviewed-by: Alexander Mikhalitsyn Signed-off-by: Andrei Vagin Tested-by: Marek Szyprowski --- fs/binfmt_elf.c | 13 ++++++--- fs/binfmt_elf_fdpic.c | 13 ++++++--- fs/exec.c | 62 ++++++++++++++++++++++++++++++++++++++++ include/linux/binfmts.h | 11 +++++++ include/linux/mm_types.h | 2 ++ kernel/fork.c | 3 ++ kernel/sys.c | 5 +++- 7 files changed, 100 insertions(+), 9 deletions(-) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index fb857faaf0d6..d99db73c76f0 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -183,6 +183,7 @@ create_elf_tables(struct linux_binprm *bprm, const stru= ct elfhdr *exec, int ei_index; const struct cred *cred =3D current_cred(); struct vm_area_struct *vma; + bool user_hwcap =3D mm_flags_test(MMF_USER_HWCAP, mm); =20 /* * In some cases (e.g. Hyper-Threading), we want to avoid L1 @@ -247,7 +248,8 @@ create_elf_tables(struct linux_binprm *bprm, const stru= ct elfhdr *exec, */ ARCH_DLINFO; #endif - NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP); + NEW_AUX_ENT(AT_HWCAP, user_hwcap ? + (bprm->hwcap & ELF_HWCAP) : ELF_HWCAP); NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE); NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); NEW_AUX_ENT(AT_PHDR, phdr_addr); @@ -265,13 +267,16 @@ create_elf_tables(struct linux_binprm *bprm, const st= ruct elfhdr *exec, NEW_AUX_ENT(AT_SECURE, bprm->secureexec); NEW_AUX_ENT(AT_RANDOM, (elf_addr_t)(unsigned long)u_rand_bytes); #ifdef ELF_HWCAP2 - NEW_AUX_ENT(AT_HWCAP2, ELF_HWCAP2); + NEW_AUX_ENT(AT_HWCAP2, user_hwcap ? + (bprm->hwcap2 & ELF_HWCAP2) : ELF_HWCAP2); #endif #ifdef ELF_HWCAP3 - NEW_AUX_ENT(AT_HWCAP3, ELF_HWCAP3); + NEW_AUX_ENT(AT_HWCAP3, user_hwcap ? + (bprm->hwcap3 & ELF_HWCAP3) : ELF_HWCAP3); #endif #ifdef ELF_HWCAP4 - NEW_AUX_ENT(AT_HWCAP4, ELF_HWCAP4); + NEW_AUX_ENT(AT_HWCAP4, user_hwcap ? + (bprm->hwcap4 & ELF_HWCAP4) : ELF_HWCAP4); #endif NEW_AUX_ENT(AT_EXECFN, bprm->exec); if (k_platform) { diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 95b65aab7daa..92c88471455a 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -508,6 +508,7 @@ static int create_elf_fdpic_tables(struct linux_binprm = *bprm, unsigned long flags =3D 0; int ei_index; elf_addr_t *elf_info; + bool user_hwcap =3D mm_flags_test(MMF_USER_HWCAP, mm); =20 #ifdef CONFIG_MMU /* In some cases (e.g. Hyper-Threading), we want to avoid L1 evictions @@ -629,15 +630,19 @@ static int create_elf_fdpic_tables(struct linux_binpr= m *bprm, */ ARCH_DLINFO; #endif - NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP); + NEW_AUX_ENT(AT_HWCAP, user_hwcap ? + (bprm->hwcap & ELF_HWCAP) : ELF_HWCAP); #ifdef ELF_HWCAP2 - NEW_AUX_ENT(AT_HWCAP2, ELF_HWCAP2); + NEW_AUX_ENT(AT_HWCAP2, user_hwcap ? + (bprm->hwcap2 & ELF_HWCAP2) : ELF_HWCAP2); #endif #ifdef ELF_HWCAP3 - NEW_AUX_ENT(AT_HWCAP3, ELF_HWCAP3); + NEW_AUX_ENT(AT_HWCAP3, user_hwcap ? + (bprm->hwcap3 & ELF_HWCAP3) : ELF_HWCAP3); #endif #ifdef ELF_HWCAP4 - NEW_AUX_ENT(AT_HWCAP4, ELF_HWCAP4); + NEW_AUX_ENT(AT_HWCAP4, user_hwcap ? + (bprm->hwcap4 & ELF_HWCAP4) : ELF_HWCAP4); #endif NEW_AUX_ENT(AT_PAGESZ, PAGE_SIZE); NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); diff --git a/fs/exec.c b/fs/exec.c index 9ea3a775d51e..1cd7d87a0e79 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1775,6 +1775,65 @@ static int bprm_execve(struct linux_binprm *bprm) return retval; } =20 +static void inherit_hwcap(struct linux_binprm *bprm) +{ + struct mm_struct *mm =3D current->mm; + bool compat =3D in_compat_syscall(); + int i, n; + +#ifdef ELF_HWCAP4 + n =3D 4; +#elif defined(ELF_HWCAP3) + n =3D 3; +#elif defined(ELF_HWCAP2) + n =3D 2; +#else + n =3D 1; +#endif + + for (i =3D 0; n && i < AT_VECTOR_SIZE; i +=3D 2) { + unsigned long type, val; + + if (!compat) { + type =3D mm->saved_auxv[i]; + val =3D mm->saved_auxv[i + 1]; + } else { + compat_uptr_t *auxv =3D (compat_uptr_t *)mm->saved_auxv; + + type =3D auxv[i]; + val =3D auxv[i + 1]; + } + + switch (type) { + case AT_NULL: + goto done; + case AT_HWCAP: + bprm->hwcap =3D val; + break; +#ifdef ELF_HWCAP2 + case AT_HWCAP2: + bprm->hwcap2 =3D val; + break; +#endif +#ifdef ELF_HWCAP3 + case AT_HWCAP3: + bprm->hwcap3 =3D val; + break; +#endif +#ifdef ELF_HWCAP4 + case AT_HWCAP4: + bprm->hwcap4 =3D val; + break; +#endif + default: + continue; + } + n--; + } +done: + mm_flags_set(MMF_USER_HWCAP, bprm->mm); +} + static int do_execveat_common(int fd, struct filename *filename, struct user_arg_ptr argv, struct user_arg_ptr envp, @@ -1843,6 +1902,9 @@ static int do_execveat_common(int fd, struct filename= *filename, current->comm, bprm->filename); } =20 + if (mm_flags_test(MMF_USER_HWCAP, current->mm)) + inherit_hwcap(bprm); + return bprm_execve(bprm); } =20 diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 65abd5ab8836..94a3dcf9b1d2 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -2,6 +2,7 @@ #ifndef _LINUX_BINFMTS_H #define _LINUX_BINFMTS_H =20 +#include #include #include #include @@ -67,6 +68,16 @@ struct linux_binprm { unsigned long exec; =20 struct rlimit rlim_stack; /* Saved RLIMIT_STACK used during exec. */ + unsigned long hwcap; +#ifdef ELF_HWCAP2 + unsigned long hwcap2; +#endif +#ifdef ELF_HWCAP3 + unsigned long hwcap3; +#endif +#ifdef ELF_HWCAP4 + unsigned long hwcap4; +#endif =20 char buf[BINPRM_BUF_SIZE]; } __randomize_layout; diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 3cc8ae722886..62dde645f469 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -1919,6 +1919,8 @@ enum { #define MMF_TOPDOWN 31 /* mm searches top down by default */ #define MMF_TOPDOWN_MASK BIT(MMF_TOPDOWN) =20 +#define MMF_USER_HWCAP 32 /* user-defined HWCAPs */ + #define MMF_INIT_LEGACY_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK |\ MMF_DISABLE_THP_MASK | MMF_HAS_MDWE_MASK |\ MMF_VM_MERGE_ANY_MASK | MMF_TOPDOWN_MASK) diff --git a/kernel/fork.c b/kernel/fork.c index bc2bf58b93b6..2ac277aa078c 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1105,6 +1105,9 @@ static struct mm_struct *mm_init(struct mm_struct *mm= , struct task_struct *p, =20 __mm_flags_overwrite_word(mm, mmf_init_legacy_flags(flags)); mm->def_flags =3D current->mm->def_flags & VM_INIT_DEF_MASK; + + if (mm_flags_test(MMF_USER_HWCAP, current->mm)) + mm_flags_set(MMF_USER_HWCAP, mm); } else { __mm_flags_overwrite_word(mm, default_dump_filter); mm->def_flags =3D 0; diff --git a/kernel/sys.c b/kernel/sys.c index cdbf8513caf6..e4b0fa2f6845 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -2157,8 +2157,10 @@ static int prctl_set_mm_map(int opt, const void __us= er *addr, unsigned long data * not introduce additional locks here making the kernel * more complex. */ - if (prctl_map.auxv_size) + if (prctl_map.auxv_size) { memcpy(mm->saved_auxv, user_auxv, sizeof(user_auxv)); + mm_flags_set(MMF_USER_HWCAP, mm); + } =20 mmap_read_unlock(mm); return 0; @@ -2190,6 +2192,7 @@ static int prctl_set_auxv(struct mm_struct *mm, unsig= ned long addr, =20 task_lock(current); memcpy(mm->saved_auxv, user_auxv, len); + mm_flags_set(MMF_USER_HWCAP, mm); task_unlock(current); =20 return 0; --=20 2.53.0.983.g0bb29b3bc5-goog From nobody Fri Mar 27 01:30:54 2026 Received: from mail-oo1-f73.google.com (mail-oo1-f73.google.com [209.85.161.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 A897F3B19BC for ; Mon, 23 Mar 2026 17:54:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.161.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774288447; cv=none; b=FLJTA9TQl055Iu0AX4amntkkNg+yE0TrnrzUfBOF12LyMh0h10Tvm2aZ30nePF/A9F9Pln6vSO83r+hehWhz3J1WA2AaahPGXt3T9Bdi9Vy8wHJqrlnUUkkX1N0yX5W7j1jiiPgcAZgohc6e17oFkxigZkx4lggIHAgI9IP594c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774288447; c=relaxed/simple; bh=wiZBFK4qXH25jZiOk6ppSpqqegoRmcuyypAI5viwsM8=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=tYjKs1CCnqJZagANnNJpJk2gI6otGBhHVkD+7/LqOE0KuYHUDfCMd53trqJ/tTPXBwS5xobd/LMkNUMseO5DBK5JtZwl2axiiYWItI0gZZvECxfF9SJUoN0JTfbCIhF5ARqaU2uX2q6HfGVE8FSt6L1jJnxI6ahIo8MhhIKm8sI= 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=C5D+84Bt; arc=none smtp.client-ip=209.85.161.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="C5D+84Bt" Received: by mail-oo1-f73.google.com with SMTP id 006d021491bc7-67de194504eso34546445eaf.1 for ; Mon, 23 Mar 2026 10:54:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1774288445; x=1774893245; 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=QvFV/sENwdGTW4IuMAnR3v5SRp3rVtVMFXWSWmq9Pi8=; b=C5D+84Bt077pL5hmkaZb0+hA3fcQus9KpCw2KdguTHGAnoOSll3iQDIkDnrHLx+/Ex HhAQyPxVN+eyFi2akwYrJiLFD80iI90uW5ZGGyViIxXcS4ebnj4ZaSh0ijnVXXa2xMNs ro5CXJq6TixblU02AoquIigpI2JiHMIrDr1QL7jnIf19oSTQLr/H5IHyLaE6pED4kMeV YmTwn77M5z5pkkN/cPUfazwC+ZaHmcXOrPfKCvQI+YylG8T5cTIMaiOSFR5/IuqsJLvI 7Lo8QP+eXn4m76u2y2IiOBuMrmgzdAC7j3JCjGnVkfNzoJGpZOqjQ8L7rI4eGmoKbtIk LLQg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774288445; x=1774893245; 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=QvFV/sENwdGTW4IuMAnR3v5SRp3rVtVMFXWSWmq9Pi8=; b=ZgNNViBCSU0aTR8LWnbNvn4NznpfX0TGUd5OvJOyMmaidBtYdWIAn60pVNFzSkwPN7 UX9mahG4vGf2X2qbZDwDxlTWKPLogJWQuQP9KLGuDRDg0IV3fxlacKylFJQkoed4ZExS oS0x48rqsvQJFEttjUhjI/5WdNCJCpbUO44x9ObPVumoss4TdLEOYZMR7uCxuYgZBRJ/ adqeCB7nNl+AWoB1DxKTwJu1NsnqeS25ObGwfoYhh5oC2AvWlrsg+u6QzjWYAFAp15zr cDwCVZ3Cxk+LXWZCEnkGbSfn6yiIVP8KQUjaAh3GSseIzIWVDTEHdMKIi77j6fdDYC0z 3QKA== X-Forwarded-Encrypted: i=1; AJvYcCUyjFkcLAjT9hbPDwA3g7Xb/VxQn0jTmWFVcH/vRl1YHKpOU9vW9ggMy7FFbycFu6iISqIFBQdomWqNFIM=@vger.kernel.org X-Gm-Message-State: AOJu0YylotkB28WlYJMDm71kLIGQuclEr4rpcAKMqP9YyfnaBF/Db+uK en8U+J56nLoqX29xt5enqq4Syx8vK4NdTLutVFKUI7IxhUSLHyr39LSogsvbT/7nxrA8NaiXuxP cGPdnKg== X-Received: from ilbbq1.prod.google.com ([2002:a05:6e02:2381:b0:4f8:6375:8930]) (user=avagin job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6820:174e:b0:67b:d754:9524 with SMTP id 006d021491bc7-67c22f4ed5dmr9551868eaf.36.1774288444594; Mon, 23 Mar 2026 10:54:04 -0700 (PDT) Date: Mon, 23 Mar 2026 17:53:38 +0000 In-Reply-To: <20260323175340.3361311-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: <20260323175340.3361311-1-avagin@google.com> X-Mailer: git-send-email 2.53.0.983.g0bb29b3bc5-goog Message-ID: <20260323175340.3361311-3-avagin@google.com> Subject: [PATCH 2/4] arm64: elf: clear MMF_USER_HWCAP on architecture switch From: Andrei Vagin To: Kees Cook , Andrew Morton Cc: Marek Szyprowski , Cyrill Gorcunov , Mike Rapoport , Alexander Mikhalitsyn , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-mm@kvack.org, criu@lists.linux.dev, Catalin Marinas , Will Deacon , linux-arm-kernel@lists.infradead.org, Chen Ridong , Christian Brauner , David Hildenbrand , Eric Biederman , Lorenzo Stoakes , Michal Koutny , Andrei Vagin Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The HWCAP bits have different meanings between AArch64 and AArch32, so HWCAP inheritance is not applicable when switching architectures. Inherited HWCAP vectors can lead to unpredictable side effects. For example, bit 0 in AArch64 signifies FP support, whereas in AArch32 it signifies SWP instruction support. Fix this by clearing the MMF_USER_HWCAP flag in SET_PERSONALITY and COMPAT_SET_PERSONALITY if the architecture is changing. This ensures that create_elf_tables() will use the default kernel HWCAPs for the new process. Signed-off-by: Andrei Vagin --- arch/arm64/include/asm/elf.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h index d2779d604c7b..2049d42e2e6a 100644 --- a/arch/arm64/include/asm/elf.h +++ b/arch/arm64/include/asm/elf.h @@ -160,7 +160,10 @@ typedef struct user_fpsimd_state elf_fpregset_t; =20 #define SET_PERSONALITY(ex) \ ({ \ - clear_thread_flag(TIF_32BIT); \ + if (test_thread_flag(TIF_32BIT)) { \ + mm_flags_clear(MMF_USER_HWCAP, current->mm); \ + clear_thread_flag(TIF_32BIT); \ + } \ current->personality &=3D ~READ_IMPLIES_EXEC; \ }) =20 @@ -223,8 +226,11 @@ int compat_elf_check_arch(const struct elf32_hdr *); */ #define COMPAT_SET_PERSONALITY(ex) \ ({ \ - set_thread_flag(TIF_32BIT); \ - }) + if (!test_thread_flag(TIF_32BIT)) { \ + mm_flags_clear(MMF_USER_HWCAP, current->mm); \ + set_thread_flag(TIF_32BIT); \ + } \ +}) #ifdef CONFIG_COMPAT_VDSO #define COMPAT_ARCH_DLINFO \ do { \ --=20 2.53.0.983.g0bb29b3bc5-goog From nobody Fri Mar 27 01:30:54 2026 Received: from mail-oi1-f202.google.com (mail-oi1-f202.google.com [209.85.167.202]) (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 4ACA63C6611 for ; Mon, 23 Mar 2026 17:54:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774288450; cv=none; b=sW+KRBVt5meNc1dPHE56DRqCLJCZpNTahR6gWYkjOs3MmcDdPf6Dds+8e3IETH+dW2SRcVFnGmzTiesgWMWx0grtoau6vEcBeK7VZO5wsRni2nIoYmhCE55VcHs0uhM1u/ZAYMeV2QM5pDkUPgVXeTEIs4VUGjmm0tItiQz3PTc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774288450; c=relaxed/simple; bh=IeY0RLDHZw+aV4EbbM8a2QRICo/GVGaL04vytj3zin0=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=aYamml1klmEYTWr204wJkb1MUz6m9h4sD1qxP8+EbipI1AzDCKpBtId2xdHsMASQWElSVDIV1gT2DMDCBQSV1hbYYRySH9PQJdx9NGgnMVY6EYKbOm4mul/XEdCcBNYOIO44rUPKBEz6mg/HAzqYpLMp7pc0BlnfimK9wAd0nEI= 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=fcFiFE6F; arc=none smtp.client-ip=209.85.167.202 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="fcFiFE6F" Received: by mail-oi1-f202.google.com with SMTP id 5614622812f47-467b2af6710so2853799b6e.2 for ; Mon, 23 Mar 2026 10:54:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1774288446; x=1774893246; darn=vger.kernel.org; h=content-transfer-encoding:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:from:to:cc:subject:date:message-id :reply-to; bh=6mLJgPLWSuoj/P2MAtrzoRO0g8BMHCjkX0hvTYs5nb0=; b=fcFiFE6FCl3Zzyw+2twqkp0JK8bAiq6rxFUQ+kqSIP4zUnSjiy7Dy0MC+dU+xpiKNY boVaGOIRQ6+LiEKqddUXjxnRryWnwLqmYg4g1IRI4S5pDMfACjs/FJFthRFarXoeQMsW 2dHtrJVzmrpMiW4UHfzyc7B0oMEmRMPYH0Dgo0K1z4lUJCyMit5lzDoPSH+rv5hdyKRM mVYmNsbPk1mcgzFVNMlW6PJXj4YGdSELJSMCyKdwO2b9aWB/ZS3nkkqswkhBmiVHUu7L tLkowAubtLDxiVGso1O3aTn08DfRS1E5whIGWR3aYtadIx62/CTaCxGGnn5mwxeDILYk Niww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774288446; x=1774893246; h=content-transfer-encoding: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=6mLJgPLWSuoj/P2MAtrzoRO0g8BMHCjkX0hvTYs5nb0=; b=H/1DGI4RbEIKa7PMlFmePecus+xegoY2Lss9EqflLGWfpArHh/9K9nd6epHJ9HisXz nih9JapH8W55g2PSY2gP9hPrua/eEPhYD+XyBvo8JlHGSVaYyxQTwEhxV+HAeij3vkKv acA+DAsYPjwixVYvPxmhuJXAX4WoKhlJR/yeh3e0qP3qaJ483PE2YjuRPOh5O+BYKtvk U1S44vLTRJk/PCQkzDqD0zyaAn7paaNGlFnd1u8O0mnmdHrh7nWbYYduJ7afeu9rfPfk oRBqoPL7QE6kn5GYyEJg5g0ohYY/DBjXWdWNgnYM4Lv5NUNPi2LjwkHR/RkWQR5fog6g hcyg== X-Forwarded-Encrypted: i=1; AJvYcCUyka8RN9aFN52fpVsKGbsbB7D6E3xIMRfAaW9UjnbAXNDvgEAm/DLru3TyR+nmHpcZPcZwoNxRLzQoskQ=@vger.kernel.org X-Gm-Message-State: AOJu0YwZ+rQfN8w1VsuoqYzY+mZuU5lGC2o4Z0ipDxR+Z33p0PPDEz/k WPLDRVRqE3M6dC0kNhBYGJwEzkQh03d0AyF57jE5UMRtiHHlRzUhnnV/+aBRsoFVgEUB50JbP8f abP9E4A== X-Received: from ilbeb14.prod.google.com ([2002:a05:6e02:460e:b0:4f8:5be9:9dbe]) (user=avagin job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6820:612:b0:67d:ec7b:cc9d with SMTP id 006d021491bc7-67dec7bd049mr3051580eaf.18.1774288445933; Mon, 23 Mar 2026 10:54:05 -0700 (PDT) Date: Mon, 23 Mar 2026 17:53:39 +0000 In-Reply-To: <20260323175340.3361311-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: <20260323175340.3361311-1-avagin@google.com> X-Mailer: git-send-email 2.53.0.983.g0bb29b3bc5-goog Message-ID: <20260323175340.3361311-4-avagin@google.com> Subject: [PATCH 3/4] mm: synchronize saved_auxv access with arg_lock From: Andrei Vagin To: Kees Cook , Andrew Morton Cc: Marek Szyprowski , Cyrill Gorcunov , Mike Rapoport , Alexander Mikhalitsyn , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-mm@kvack.org, criu@lists.linux.dev, Catalin Marinas , Will Deacon , linux-arm-kernel@lists.infradead.org, Chen Ridong , Christian Brauner , David Hildenbrand , Eric Biederman , Lorenzo Stoakes , Michal Koutny , Andrei Vagin , Alexander Mikhalitsyn Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The mm->saved_auxv array stores the auxiliary vector, which can be modified via prctl(PR_SET_MM_AUXV) or prctl(PR_SET_MM_MAP). Previously, accesses to saved_auxv were not synchronized. This was a intentional trade-off, as the vector was only used to provide information to userspace via /proc/PID/auxv or prctl(PR_GET_AUXV), and consistency between the auxv values left to userspace. With the introduction of hardware capability (HWCAP) inheritance during execve, the kernel now relies on the contents of saved_auxv to configure the execution environment of new processes. An unsynchronized read during execve could result in a new process inheriting an inconsistent set of capabilities if the parent process updates its auxiliary vector concurrently. While it is still not strictly required to guarantee the consistency of auxv values on the kernel side, doing so is relatively straightforward. This change implements synchronization using arg_lock. Reviewed-by: Alexander Mikhalitsyn Reviewed-by: Cyrill Gorcunov Reviewed-by: Michal Koutn=C3=BD Signed-off-by: Andrei Vagin --- fs/exec.c | 2 ++ fs/proc/base.c | 12 +++++++++--- include/linux/mm_types.h | 1 - kernel/fork.c | 7 ++++++- kernel/sys.c | 29 ++++++++++++++--------------- 5 files changed, 31 insertions(+), 20 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index 1cd7d87a0e79..dea868d058fa 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1791,6 +1791,7 @@ static void inherit_hwcap(struct linux_binprm *bprm) n =3D 1; #endif =20 + spin_lock(&mm->arg_lock); for (i =3D 0; n && i < AT_VECTOR_SIZE; i +=3D 2) { unsigned long type, val; =20 @@ -1831,6 +1832,7 @@ static void inherit_hwcap(struct linux_binprm *bprm) n--; } done: + spin_unlock(&mm->arg_lock); mm_flags_set(MMF_USER_HWCAP, bprm->mm); } =20 diff --git a/fs/proc/base.c b/fs/proc/base.c index 4c863d17dfb4..b5496cec888e 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1083,14 +1083,20 @@ static ssize_t auxv_read(struct file *file, char __= user *buf, { struct mm_struct *mm =3D file->private_data; unsigned int nwords =3D 0; + unsigned long saved_auxv[AT_VECTOR_SIZE]; =20 if (!mm) return 0; + + spin_lock(&mm->arg_lock); + memcpy(saved_auxv, mm->saved_auxv, sizeof(saved_auxv)); + spin_unlock(&mm->arg_lock); + do { nwords +=3D 2; - } while (mm->saved_auxv[nwords - 2] !=3D 0); /* AT_NULL */ - return simple_read_from_buffer(buf, count, ppos, mm->saved_auxv, - nwords * sizeof(mm->saved_auxv[0])); + } while (saved_auxv[nwords - 2] !=3D 0); /* AT_NULL */ + return simple_read_from_buffer(buf, count, ppos, saved_auxv, + nwords * sizeof(saved_auxv[0])); } =20 static const struct file_operations proc_auxv_operations =3D { diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 62dde645f469..10351af5851b 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -1255,7 +1255,6 @@ struct mm_struct { unsigned long start_code, end_code, start_data, end_data; unsigned long start_brk, brk, start_stack; unsigned long arg_start, arg_end, env_start, env_end; - unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */ =20 #ifdef CONFIG_ARCH_HAS_ELF_CORE_EFLAGS diff --git a/kernel/fork.c b/kernel/fork.c index 2ac277aa078c..3880ce0d44f9 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1106,8 +1106,13 @@ static struct mm_struct *mm_init(struct mm_struct *m= m, struct task_struct *p, __mm_flags_overwrite_word(mm, mmf_init_legacy_flags(flags)); mm->def_flags =3D current->mm->def_flags & VM_INIT_DEF_MASK; =20 - if (mm_flags_test(MMF_USER_HWCAP, current->mm)) + if (mm_flags_test(MMF_USER_HWCAP, current->mm)) { + spin_lock(¤t->mm->arg_lock); mm_flags_set(MMF_USER_HWCAP, mm); + memcpy(mm->saved_auxv, current->mm->saved_auxv, + sizeof(mm->saved_auxv)); + spin_unlock(¤t->mm->arg_lock); + } } else { __mm_flags_overwrite_word(mm, default_dump_filter); mm->def_flags =3D 0; diff --git a/kernel/sys.c b/kernel/sys.c index e4b0fa2f6845..c679b5797e73 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -2147,20 +2147,11 @@ static int prctl_set_mm_map(int opt, const void __u= ser *addr, unsigned long data mm->arg_end =3D prctl_map.arg_end; mm->env_start =3D prctl_map.env_start; mm->env_end =3D prctl_map.env_end; - spin_unlock(&mm->arg_lock); - - /* - * Note this update of @saved_auxv is lockless thus - * if someone reads this member in procfs while we're - * updating -- it may get partly updated results. It's - * known and acceptable trade off: we leave it as is to - * not introduce additional locks here making the kernel - * more complex. - */ if (prctl_map.auxv_size) { - memcpy(mm->saved_auxv, user_auxv, sizeof(user_auxv)); mm_flags_set(MMF_USER_HWCAP, mm); + memcpy(mm->saved_auxv, user_auxv, sizeof(user_auxv)); } + spin_unlock(&mm->arg_lock); =20 mmap_read_unlock(mm); return 0; @@ -2190,10 +2181,10 @@ static int prctl_set_auxv(struct mm_struct *mm, uns= igned long addr, =20 BUILD_BUG_ON(sizeof(user_auxv) !=3D sizeof(mm->saved_auxv)); =20 - task_lock(current); - memcpy(mm->saved_auxv, user_auxv, len); + spin_lock(&mm->arg_lock); mm_flags_set(MMF_USER_HWCAP, mm); - task_unlock(current); + memcpy(mm->saved_auxv, user_auxv, len); + spin_unlock(&mm->arg_lock); =20 return 0; } @@ -2481,9 +2472,17 @@ static inline int prctl_get_mdwe(unsigned long arg2,= unsigned long arg3, static int prctl_get_auxv(void __user *addr, unsigned long len) { struct mm_struct *mm =3D current->mm; + unsigned long auxv[AT_VECTOR_SIZE]; unsigned long size =3D min_t(unsigned long, sizeof(mm->saved_auxv), len); =20 - if (size && copy_to_user(addr, mm->saved_auxv, size)) + if (!size) + return sizeof(mm->saved_auxv); + + spin_lock(&mm->arg_lock); + memcpy(auxv, mm->saved_auxv, size); + spin_unlock(&mm->arg_lock); + + if (copy_to_user(addr, auxv, size)) return -EFAULT; return sizeof(mm->saved_auxv); } --=20 2.53.0.983.g0bb29b3bc5-goog From nobody Fri Mar 27 01:30:54 2026 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 9418C3CCA09 for ; Mon, 23 Mar 2026 17:54:08 +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=1774288451; cv=none; b=N9QOY3+Z9mKURkz3EHUvV7j/B3H39tZxIvzoe+fGuTJ6GOKp495sIaXpg5ux8nwE28GyviX/s5ykNyEtz7J9ZunjjohVMi/RXLYtUOBhHp87C6gC1rb/G43cR3dgHm/XecWUdz/EAkaPh+8icMQOqp34n89FAb+78vS/toDs/Og= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774288451; c=relaxed/simple; bh=L2zTtGTNTw3phxOrswp+iUaPq/4BsNNONZQKwH6jDDA=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=mwsM1YHLTG/kEFpITlqCQgf40Y/XeRATMAh2qbmcKWtxGympfzg21useNGAuQ+x85hbUzVIVgiTYyHcgh4Y5HG+2FclC7KOVq44pKiASOnycKQobZRj7jzVzSYVcAdCq37lGq9cZbL2AWI/Wg+uIKnntl8KYNZg6Y9rzZ5bXpa8= 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=W4cK75Uy; 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="W4cK75Uy" Received: by mail-ot1-f73.google.com with SMTP id 46e09a7af769-7d7f7164b12so19032628a34.1 for ; Mon, 23 Mar 2026 10:54:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1774288447; x=1774893247; 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=Vz01D+Qvtpuy+jqrKUW1E7zaDqaJMt9I2Ue5ziSPeb0=; b=W4cK75UyBcl7snsjvR7ZgphxNiZClz8sYs3aDFPe/nYIy2WEr/FwzB7rtaTkcEaa/5 vXkHvrursI4QcGyn3sYyvgSDa/5O0RLZAp5fpLlSPE0eRUmyKcDVi/LgrCEwslAEvc7P D0/AxJ3LPJX/g+wHwSgQe6f7bnDySXI39b5v0GrCM8BiOs9spi2P21OchCi1kjv1iBPv nOer0zVuRg7Ni1x2WeXc3LxcJZIYax8gUhsOv6wWJbp1aXRALQqlqUw4z7F9mXeyAzwi cP7U+RmYh79kPvC/qwyyYHPWlu9p73WEZ+aaMwC/3Uj9Frl1jFHlSvGibqGFJgXf4DSh A67w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774288447; x=1774893247; 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=Vz01D+Qvtpuy+jqrKUW1E7zaDqaJMt9I2Ue5ziSPeb0=; b=TXgWqDcJY4k2DfhSi7y1fYTuN176ooRLg9SjK4TdBlw03aKro19qjTbh1Kgt+fgt1M da5DiFXkBsEI6+WxBgu41iunxz4dbXu2l1ZhCLY8FYUuBY61Id/3pHlymbkdDpN+50IO eV9t3NBrFXXDsp+IMfxgkJgeXVssyH7AkWONZCxt3OpnTTIBYpfAX/fiyInsnC6DYO7U B4GvUHEfMKGzY5j4Hzoh+hFJ2DEvEJqyuT/cYvGAhWR9Pf+MCU/HZZglK02xh1i7o4lc nAo9sTXu01qBxBu4UtrTSWmQ0zyXpNsgXiR4sLLfQNuIFoncR1+Z7Yr+Rsc2zDre292W YAXQ== X-Forwarded-Encrypted: i=1; AJvYcCUSuFy8165KmULb8ltPJoZ50UUqUJ37Bs8ppa7MVxkRlf6i4usAy13065qpcOD0Xs9ATYnZnVavqspef+k=@vger.kernel.org X-Gm-Message-State: AOJu0YzTki3PO296FzGS23D7ZMomI90qEnKK/Ll1O0o+y10PC8UQ/kLd dTWBX1vNifXSvp7uzlWxCW14nEcx8nJf/qZwWkdkZYF6dbG5OkCIAGZUlVuWjCke08kyADHM4kU OiBe41w== X-Received: from jalw26.prod.google.com ([2002:a05:6638:379a:b0:5d4:6a6a:67ca]) (user=avagin job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6820:200e:b0:67d:eeb7:476f with SMTP id 006d021491bc7-67deeb74d00mr2420094eaf.0.1774288447326; Mon, 23 Mar 2026 10:54:07 -0700 (PDT) Date: Mon, 23 Mar 2026 17:53:40 +0000 In-Reply-To: <20260323175340.3361311-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: <20260323175340.3361311-1-avagin@google.com> X-Mailer: git-send-email 2.53.0.983.g0bb29b3bc5-goog Message-ID: <20260323175340.3361311-5-avagin@google.com> Subject: [PATCH 4/4] selftests/exec: add test for HWCAP inheritance From: Andrei Vagin To: Kees Cook , Andrew Morton Cc: Marek Szyprowski , Cyrill Gorcunov , Mike Rapoport , Alexander Mikhalitsyn , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-mm@kvack.org, criu@lists.linux.dev, Catalin Marinas , Will Deacon , linux-arm-kernel@lists.infradead.org, Chen Ridong , Christian Brauner , David Hildenbrand , Eric Biederman , Lorenzo Stoakes , Michal Koutny , Andrei Vagin , Alexander Mikhalitsyn Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Verify that HWCAPs are correctly inherited/preserved across execve() when modified via prctl(PR_SET_MM_AUXV). The test performs the following steps: * reads the current AUXV using prctl(PR_GET_AUXV); * finds an HWCAP entry and toggles its most significant bit; * replaces the AUXV of the current process with the modified one using prctl(PR_SET_MM, PR_SET_MM_AUXV); * executes itself to verify that the new program sees the modified HWCAP value. Reviewed-by: Alexander Mikhalitsyn Reviewed-by: Cyrill Gorcunov Reviewed-by: Kees Cook Signed-off-by: Andrei Vagin --- tools/testing/selftests/exec/.gitignore | 1 + tools/testing/selftests/exec/Makefile | 1 + tools/testing/selftests/exec/hwcap_inherit.c | 105 +++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 tools/testing/selftests/exec/hwcap_inherit.c diff --git a/tools/testing/selftests/exec/.gitignore b/tools/testing/selfte= sts/exec/.gitignore index 7f3d1ae762ec..2ff245fd0ba6 100644 --- a/tools/testing/selftests/exec/.gitignore +++ b/tools/testing/selftests/exec/.gitignore @@ -19,3 +19,4 @@ null-argv xxxxxxxx* pipe S_I*.test +hwcap_inherit \ No newline at end of file diff --git a/tools/testing/selftests/exec/Makefile b/tools/testing/selftest= s/exec/Makefile index 45a3cfc435cf..e73005965e05 100644 --- a/tools/testing/selftests/exec/Makefile +++ b/tools/testing/selftests/exec/Makefile @@ -20,6 +20,7 @@ TEST_FILES :=3D Makefile TEST_GEN_PROGS +=3D recursion-depth TEST_GEN_PROGS +=3D null-argv TEST_GEN_PROGS +=3D check-exec +TEST_GEN_PROGS +=3D hwcap_inherit =20 EXTRA_CLEAN :=3D $(OUTPUT)/subdir.moved $(OUTPUT)/execveat.moved $(OUTPUT)= /xxxxx* \ $(OUTPUT)/S_I*.test diff --git a/tools/testing/selftests/exec/hwcap_inherit.c b/tools/testing/s= elftests/exec/hwcap_inherit.c new file mode 100644 index 000000000000..1b43b2dbb1d0 --- /dev/null +++ b/tools/testing/selftests/exec/hwcap_inherit.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../kselftest.h" + +static int find_msb(unsigned long v) +{ + return sizeof(v)*8 - __builtin_clzl(v) - 1; +} + +int main(int argc, char *argv[]) +{ + unsigned long auxv[1024], hwcap, new_hwcap, hwcap_idx; + int size, hwcap_type =3D 0, hwcap_feature, count, status; + char hwcap_str[32], hwcap_type_str[32]; + pid_t pid; + + if (argc > 1 && strcmp(argv[1], "verify") =3D=3D 0) { + unsigned long type =3D strtoul(argv[2], NULL, 16); + unsigned long expected =3D strtoul(argv[3], NULL, 16); + unsigned long hwcap =3D getauxval(type); + + if (hwcap !=3D expected) { + ksft_print_msg("HWCAP mismatch: type %lx, expected %lx, got %lx\n", + type, expected, hwcap); + return 1; + } + ksft_print_msg("HWCAP matched: %lx\n", hwcap); + return 0; + } + + ksft_print_header(); + ksft_set_plan(1); + + size =3D prctl(PR_GET_AUXV, auxv, sizeof(auxv), 0, 0); + if (size =3D=3D -1) + ksft_exit_fail_perror("prctl(PR_GET_AUXV)"); + + count =3D size / sizeof(unsigned long); + + /* Find the "latest" feature and try to mask it out. */ + for (int i =3D 0; i < count - 1; i +=3D 2) { + hwcap =3D auxv[i + 1]; + if (hwcap =3D=3D 0) + continue; + switch (auxv[i]) { + case AT_HWCAP4: + case AT_HWCAP3: + case AT_HWCAP2: + case AT_HWCAP: + hwcap_type =3D auxv[i]; + hwcap_feature =3D find_msb(hwcap); + hwcap_idx =3D i + 1; + break; + default: + continue; + } + } + if (hwcap_type =3D=3D 0) + ksft_exit_skip("No features found, skipping test\n"); + hwcap =3D auxv[hwcap_idx]; + new_hwcap =3D hwcap ^ (1UL << hwcap_feature); + auxv[hwcap_idx] =3D new_hwcap; + + if (prctl(PR_SET_MM, PR_SET_MM_AUXV, auxv, size, 0) < 0) { + if (errno =3D=3D EPERM) + ksft_exit_skip("prctl(PR_SET_MM_AUXV) requires CAP_SYS_RESOURCE\n"); + ksft_exit_fail_perror("prctl(PR_SET_MM_AUXV)"); + } + + pid =3D fork(); + if (pid < 0) + ksft_exit_fail_perror("fork"); + if (pid =3D=3D 0) { + char *new_argv[] =3D { argv[0], "verify", hwcap_type_str, hwcap_str, NUL= L }; + + snprintf(hwcap_str, sizeof(hwcap_str), "%lx", new_hwcap); + snprintf(hwcap_type_str, sizeof(hwcap_type_str), "%x", hwcap_type); + + execv(argv[0], new_argv); + perror("execv"); + exit(1); + } + + if (waitpid(pid, &status, 0) =3D=3D -1) + ksft_exit_fail_perror("waitpid"); + if (status !=3D 0) + ksft_exit_fail_msg("HWCAP inheritance failed (status %d)\n", status); + + ksft_test_result_pass("HWCAP inheritance succeeded\n"); + ksft_exit_pass(); + return 0; +} --=20 2.53.0.983.g0bb29b3bc5-goog