From: Yo'av Moshe <linux@yoavmoshe.com>
To: Frank Li <Frank.Li@nxp.com>,
Sascha Hauer <s.hauer@pengutronix.de>,
Russell King <linux@armlinux.org.uk>
Cc: Pengutronix Kernel Team <kernel@pengutronix.de>,
Fabio Estevam <festevam@gmail.com>,
Nathan Chancellor <nathan@kernel.org>,
Nick Desaulniers <ndesaulniers@google.com>,
Bill Wendling <morbo@google.com>,
Justin Stitt <justinstitt@google.com>,
imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org,
llvm@lists.linux.dev, stable@vger.kernel.org,
linux-kernel@vger.kernel.org, Yo'av Moshe <linux@yoavmoshe.com>
Subject: [PATCH v4] ARM: imx: Fix suspend/resume crash with Clang CFI
Date: Thu, 27 Aug 2026 21:45:08 +0200 [thread overview]
Message-ID: <20260827194508.446733-1-linux@yoavmoshe.com> (raw)
In-Reply-To: <20260718111340.159896-1-linux@yoavmoshe.com>
The suspend code that runs from OCRAM is copied there with fncpy(),
which does not copy the kCFI type hash preceding the function. With
CONFIG_CFI=y the indirect call through imx6_suspend_in_ocram_fn
therefore panics.
Keep the call covered by CFI instead of exempting it:
- Declare imx6_suspend() with SYM_TYPED_FUNC_START() so a type hash
is emitted for it. fncpy() requires the entry point to be 8-byte
aligned, and the macro's alignment applies to the hash rather than
the entry that follows it, so pad manually before the macro.
- Add a cfi_type member at the end of struct imx6_cpu_pm_info, which
directly precedes the OCRAM copy of the function. It fits in the
struct's tail padding, so no sizes or offsets change. Fill it using
cfi_get_func_hash(), putting the hash where the caller's CFI check
expects it: four bytes before the function entry.
Also mark ccm_base, suspend_ocram_base and imx6_suspend_in_ocram_fn
as __ro_after_init: they are only written during __init, and the
function pointer in particular should not be writable afterwards.
Suggested-by: Nick Desaulniers <ndesaulniers@google.com>
Cc: stable@vger.kernel.org
Signed-off-by: Yo'av Moshe <linux@yoavmoshe.com>
---
Tested on a Kobo Clara HD (i.MX6SLL) running postmarketOS
(clang/LLVM, CONFIG_CFI=y): suspend and resume work.
Changes in v4, all following Nick's suggestions:
- Drop the v3 __nocfi wrapper; keep the indirect call CFI-checked.
- Store the hash in a cfi_type member in the struct's tail padding
instead of open-coded pointer arithmetic.
- Use cfi_get_func_hash() instead of reading the hash manually.
- Use SYM_TYPED_FUNC_START()/SYM_FUNC_END() instead of ENTRY()/
ENDPROC() with a hand-rolled __CFI_TYPE.
Note: linux/uaccess.h is included before linux/cfi.h because
cfi_get_func_hash() uses get_kernel_nofault() and cfi.h does not
include uaccess.h itself.
arch/arm/mach-imx/pm-imx6.c | 25 ++++++++++++++++++++++---
arch/arm/mach-imx/suspend-imx6.S | 14 ++++++++++++--
2 files changed, 34 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c
index a671ca4..2d3d3cd 100644
--- a/arch/arm/mach-imx/pm-imx6.c
+++ b/arch/arm/mach-imx/pm-imx6.c
@@ -4,6 +4,8 @@
* Copyright 2011 Linaro Ltd.
*/
+#include <linux/uaccess.h>
+#include <linux/cfi.h>
#include <linux/clk/imx.h>
#include <linux/delay.h>
#include <linux/init.h>
@@ -61,9 +63,9 @@
#define MX6Q_SUSPEND_OCRAM_SIZE 0x1000
#define MX6_MAX_MMDC_IO_NUM 33
-static void __iomem *ccm_base;
-static void __iomem *suspend_ocram_base;
-static void (*imx6_suspend_in_ocram_fn)(void __iomem *ocram_vbase);
+static void __iomem *ccm_base __ro_after_init;
+static void __iomem *suspend_ocram_base __ro_after_init;
+static void (*imx6_suspend_in_ocram_fn)(void __iomem *ocram_vbase) __ro_after_init;
/*
* suspend ocram space layout:
@@ -229,8 +231,18 @@ struct imx6_cpu_pm_info {
struct imx6_pm_base l2_base;
u32 mmdc_io_num; /* Number of MMDC IOs which need saved/restored. */
u32 mmdc_io_val[MX6_MAX_MMDC_IO_NUM][2]; /* To save offset and value */
+ u32 cfi_type; /* kCFI type hash of imx6_suspend() */
} __aligned(8);
+/*
+ * The ocram copy of imx6_suspend() starts right after struct imx6_cpu_pm_info,
+ * and the CFI check on the indirect call reads the kCFI type hash from the
+ * four bytes preceding the function entry, so cfi_type must occupy the last
+ * four bytes of the struct, i.e. fit into its tail padding.
+ */
+static_assert(offsetofend(struct imx6_cpu_pm_info, cfi_type) ==
+ sizeof(struct imx6_cpu_pm_info));
+
void imx6_set_int_mem_clk_lpm(bool enable)
{
u32 val = readl_relaxed(ccm_base + CGPR);
@@ -568,6 +580,13 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata)
mmdc_offset_array[i]);
}
+ /*
+ * Mask out the Thumb bit, as cfi_get_func_hash() expects the
+ * function's actual start address. Returns 0 if CONFIG_CFI=n.
+ */
+ pm_info->cfi_type =
+ cfi_get_func_hash((void *)((uintptr_t)&imx6_suspend & ~1UL));
+
imx6_suspend_in_ocram_fn = fncpy(
suspend_ocram_base + sizeof(*pm_info),
&imx6_suspend,
diff --git a/arch/arm/mach-imx/suspend-imx6.S b/arch/arm/mach-imx/suspend-imx6.S
index 63ccc2d..f60c4e5 100644
--- a/arch/arm/mach-imx/suspend-imx6.S
+++ b/arch/arm/mach-imx/suspend-imx6.S
@@ -3,6 +3,7 @@
* Copyright 2014 Freescale Semiconductor, Inc.
*/
+#include <linux/cfi_types.h>
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/asm-offsets.h>
@@ -148,7 +149,16 @@
.endm
-ENTRY(imx6_suspend)
+#ifdef CONFIG_CFI
+ /*
+ * Pad the location counter so that the type hash emitted by
+ * SYM_TYPED_FUNC_START() below ends on an 8-byte boundary:
+ * fncpy() requires the function entry to be 8-byte aligned.
+ */
+ .align 3
+ .4byte 0
+#endif
+SYM_TYPED_FUNC_START(imx6_suspend)
ldr r1, [r0, #PM_INFO_PBASE_OFFSET]
ldr r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
@@ -329,4 +339,4 @@ resume:
resume_mmdc
ret lr
-ENDPROC(imx6_suspend)
+SYM_FUNC_END(imx6_suspend)
--
2.55.0
next prev parent reply other threads:[~2026-08-27 19:46 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-18 11:13 [PATCH v3] ARM: imx: Fix suspend/resume crash with Clang CFI Yo'av Moshe
2026-07-20 16:53 ` Nick Desaulniers
2026-07-21 5:20 ` Yo'av Moshe
2026-07-20 19:29 ` Sami Tolvanen
2026-07-21 5:29 ` Yo'av Moshe
2026-07-21 18:09 ` Nathan Chancellor
2026-07-22 12:53 ` Yo'av Moshe
2026-07-22 15:00 ` Sami Tolvanen
2026-07-22 17:46 ` Yo'av Moshe
2026-07-22 18:03 ` Sami Tolvanen
2026-07-23 13:30 ` Yo'av Moshe
2026-07-23 19:21 ` Sami Tolvanen
2026-07-23 19:55 ` Yo'av Moshe
2026-07-24 15:53 ` Sami Tolvanen
2026-07-24 20:49 ` Nick Desaulniers
2026-07-26 15:36 ` Yo'av Moshe
2026-08-17 17:45 ` Yo'av Moshe
2026-08-17 21:31 ` Frank Li
2026-08-17 21:58 ` Nick Desaulniers
2026-08-24 14:09 ` Yo'av Moshe
2026-08-25 17:33 ` Nick Desaulniers
2026-08-27 16:55 ` Yo'av Moshe
2026-08-27 19:45 ` Yo'av Moshe [this message]
2026-08-28 18:29 ` [PATCH v4] " Nick Desaulniers
2026-08-28 18:45 ` Sami Tolvanen
2026-08-28 20:19 ` Nick Desaulniers
2026-08-28 20:50 ` Sami Tolvanen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260827194508.446733-1-linux@yoavmoshe.com \
--to=linux@yoavmoshe.com \
--cc=Frank.Li@nxp.com \
--cc=festevam@gmail.com \
--cc=imx@lists.linux.dev \
--cc=justinstitt@google.com \
--cc=kernel@pengutronix.de \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=llvm@lists.linux.dev \
--cc=morbo@google.com \
--cc=nathan@kernel.org \
--cc=ndesaulniers@google.com \
--cc=s.hauer@pengutronix.de \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox