[PATCH v3] ARM: imx: Fix suspend/resume crash with Clang CFI

Yo'av Moshe posted 1 patch 6 days, 16 hours ago
arch/arm/mach-imx/pm-imx6.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
[PATCH v3] ARM: imx: Fix suspend/resume crash with Clang CFI
Posted by Yo'av Moshe 6 days, 16 hours ago
Relocated suspend code in OCRAM lacks compiler-generated CFI type
signatures. When CONFIG_CFI=y is active, the indirect call to
imx6_suspend_in_ocram_fn triggers a strict CFI violation panic.

To resolve this safely without reducing CFI protection scope:
1. Create a minimal wrapper function imx6_suspend_in_ocram annotated
   with __nocfi to handle the unverified indirect call.
2. Remove the __nocfi annotation from the main imx6q_suspend_finish
   function to preserve full CFI coverage for other indirect calls
   in that scope (such as cpu_do_idle() and flush_cache_all()).
3. Mark global variables ccm_base, suspend_ocram_base, and the
   imx6_suspend_in_ocram_fn pointer as __ro_after_init to prevent
   them from being used as target vectors for CFI bypass exploits.

Cc: stable@vger.kernel.org
Signed-off-by: Yo'av Moshe <linux@yoavmoshe.com>
---
Tested on a Kobo Clara HD (i.MX6SLL SoC) running postmarketOS edge. 
Before this patch, suspending the device caused an immediate silent 
hang requiring a hard-reboot. With this patch applied, suspend and 
resume work successfully.

Differences from v2:
- Restrained __nocfi scope by adding a dedicated, minimal 1-line 
  wrapper function (imx6_suspend_in_ocram) for the OCRAM call, 
  avoiding disabling CFI checks for cpu_do_idle() and flush_cache_all().
- Marked global pointers ccm_base and suspend_ocram_base as
  __ro_after_init to fully neutralize Write-What-Where exploit bypasses.

 arch/arm/mach-imx/pm-imx6.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c
index a671ca498..3d5b960c5 100644
--- a/arch/arm/mach-imx/pm-imx6.c
+++ b/arch/arm/mach-imx/pm-imx6.c
@@ -61,9 +61,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:
@@ -360,6 +360,11 @@ int imx6_set_lpm(enum mxc_cpu_pwr_mode mode)
 	return 0;
 }
 
+static void __nocfi imx6_suspend_in_ocram(void __iomem *ocram_vbase)
+{
+	imx6_suspend_in_ocram_fn(ocram_vbase);
+}
+
 static int imx6q_suspend_finish(unsigned long val)
 {
 	if (!imx6_suspend_in_ocram_fn) {
@@ -374,7 +379,7 @@ static int imx6q_suspend_finish(unsigned long val)
 		if (!((struct imx6_cpu_pm_info *)
 			suspend_ocram_base)->l2_base.vbase)
 			flush_cache_all();
-		imx6_suspend_in_ocram_fn(suspend_ocram_base);
+		imx6_suspend_in_ocram(suspend_ocram_base);
 	}
 
 	return 0;
-- 
2.55.0
Re: [PATCH v3] ARM: imx: Fix suspend/resume crash with Clang CFI
Posted by Sami Tolvanen 4 days, 8 hours ago
On Sat, Jul 18, 2026 at 4:14 AM Yo'av Moshe <linux@yoavmoshe.com> wrote:
>
> Relocated suspend code in OCRAM lacks compiler-generated CFI type
> signatures. When CONFIG_CFI=y is active, the indirect call to
> imx6_suspend_in_ocram_fn triggers a strict CFI violation panic.

Would it be possible to just copy the 4-byte CFI hash prefix to OCRAM
when relocating the function? If not, the __nocfi approach seems
reasonable to me.

Sami
Re: [PATCH v3] ARM: imx: Fix suspend/resume crash with Clang CFI
Posted by Yo'av Moshe 3 days, 22 hours ago
On 2026-07-20 9:29 PM, Sami Tolvanen wrote:
> Would it be possible to just copy the 4-byte CFI hash prefix to OCRAM
> when relocating the function? If not, the __nocfi approach seems
> reasonable to me.
> 
> Sami

I gave this a try - I tried copying 4 bytes from before imx6_suspend
into OCRAM, but when I tested it on physical hardware (Kobo Clara HD),
it still crashed on suspend.

I suspect it's because imx6_suspend is written in assembly
(suspend-imx6.S) rather than C, so Clang doesn't emit a CFI hash prefix
before it in the first place.

Best regards,
Yo'av
Re: [PATCH v3] ARM: imx: Fix suspend/resume crash with Clang CFI
Posted by Nathan Chancellor 3 days, 9 hours ago
On Tue, Jul 21, 2026 at 07:29:50AM +0200, Yo'av Moshe wrote:
> On 2026-07-20 9:29 PM, Sami Tolvanen wrote:
> > Would it be possible to just copy the 4-byte CFI hash prefix to OCRAM
> > when relocating the function? If not, the __nocfi approach seems
> > reasonable to me.
> > 
> > Sami
> 
> I gave this a try - I tried copying 4 bytes from before imx6_suspend
> into OCRAM, but when I tested it on physical hardware (Kobo Clara HD),
> it still crashed on suspend.
> 
> I suspect it's because imx6_suspend is written in assembly
> (suspend-imx6.S) rather than C, so Clang doesn't emit a CFI hash prefix
> before it in the first place.

Does using SYM_TYPED_FUNC_START for imx6_suspend() make that work?
Something like this builds fine for me and I see
__kcfi_typeid_imx6_suspend generated by Clang.

diff --git a/arch/arm/mach-imx/suspend-imx6.S b/arch/arm/mach-imx/suspend-imx6.S
index 63ccc2d0e920..6ded29a38c99 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,7 @@
 
 	.endm
 
-ENTRY(imx6_suspend)
+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 +330,4 @@ resume:
 	resume_mmdc
 
 	ret	lr
-ENDPROC(imx6_suspend)
+SYM_FUNC_END(imx6_suspend)

-- 
Cheers,
Nathan
Re: [PATCH v3] ARM: imx: Fix suspend/resume crash with Clang CFI
Posted by Yo'av Moshe 2 days, 15 hours ago
On 2026-07-21 8:09 PM, Nathan Chancellor wrote:
> Does using SYM_TYPED_FUNC_START for imx6_suspend() make that work?
> Something like this builds fine for me and I see
> __kcfi_typeid_imx6_suspend generated by Clang.
Hi Nathan,

Thanks for the suggestion!

Unfortunately my physical board died, so I couldn't test this on hardware.
However, I gave your patch a try under QEMU emulation (with CONFIG_CFI=y
and copying the 4-byte hash into OCRAM before fncpy), and it still
triggered a CFI panic when suspending:

    __und_svc_finish from imx6q_suspend_finish+0x78/0xd0

It seems like the hash generated for assembly doesn't match what the C code
expects at the call site.

Best regards,
Yo'av
Re: [PATCH v3] ARM: imx: Fix suspend/resume crash with Clang CFI
Posted by Sami Tolvanen 2 days, 12 hours ago
On Wed, Jul 22, 2026 at 5:54 AM Yo'av Moshe <linux@yoavmoshe.com> wrote:
>
> On 2026-07-21 8:09 PM, Nathan Chancellor wrote:
> > Does using SYM_TYPED_FUNC_START for imx6_suspend() make that work?
> > Something like this builds fine for me and I see
> > __kcfi_typeid_imx6_suspend generated by Clang.
> Hi Nathan,
>
> Thanks for the suggestion!
>
> Unfortunately my physical board died, so I couldn't test this on hardware.
> However, I gave your patch a try under QEMU emulation (with CONFIG_CFI=y
> and copying the 4-byte hash into OCRAM before fncpy), and it still
> triggered a CFI panic when suspending:
>
>     __und_svc_finish from imx6q_suspend_finish+0x78/0xd0
>
> It seems like the hash generated for assembly doesn't match what the C code
> expects at the call site.

Are relocations applied to this code before the function is copied?
Because SYM_TYPED_FUNC_START doesn't embed the actual CFI hash in the
binary, just a reference to a symbol that contains the hash, and it
relies on the kernel to apply relocations before indirect calls are
made to the function.

Sami
Re: [PATCH v3] ARM: imx: Fix suspend/resume crash with Clang CFI
Posted by Yo'av Moshe 2 days, 10 hours ago
On 2026-07-22 5:00 PM, Sami Tolvanen wrote:
> Are relocations applied to this code before the function is copied?
> Because SYM_TYPED_FUNC_START doesn't embed the actual CFI hash in the
> binary, just a reference to a symbol that contains the hash, and it
> relies on the kernel to apply relocations before indirect calls are
> made to the function.
Hi Sami,

AFAICT, kernel relocations are already applied at boot before fncpy()
is called during init.

I think the issue might be a parameter mismatch: in C, the pointer is
declared as taking a parameter `void (*)(void __iomem *)`, but in assembly
`imx6_suspend` has no parameters, so Clang generates two different hashes
for them?

Best regards,
Yo'av
Re: [PATCH v3] ARM: imx: Fix suspend/resume crash with Clang CFI
Posted by Sami Tolvanen 2 days, 9 hours ago
On Wed, Jul 22, 2026 at 10:47 AM Yo'av Moshe <linux@yoavmoshe.com> wrote:
>
> I think the issue might be a parameter mismatch: in C, the pointer is
> declared as taking a parameter `void (*)(void __iomem *)`, but in assembly
> `imx6_suspend` has no parameters, so Clang generates two different hashes
> for them?

As long as the C prototype for the assembly function matches the
function pointer type, the hashes should also match. Can you dump the
hash prefix from the OCRAM and compare it to the disassembly of the
call site?

Sami
Re: [PATCH v3] ARM: imx: Fix suspend/resume crash with Clang CFI
Posted by Yo'av Moshe 1 day, 14 hours ago
On 2026-07-22 8:03 PM, Sami Tolvanen wrote:
> As long as the C prototype for the assembly function matches the
> function pointer type, the hashes should also match. Can you dump the
> hash prefix from the OCRAM and compare it to the disassembly of the
> call site?
Here is what I saw when checking the disassembly in vmlinux:

1. Call site expected hash in pm-imx6.c: 0xA488EBFC
2. SYM_TYPED_FUNC_START hash prefix in suspend-imx6.S: 0xd4d4d4d4

It looks like because suspend-imx6.S is an assembly file, Clang emits
the default assembly type ID (0xd4d4d4d4) for it, which doesn't match
the C call site expectation (0xA488EBFC).

Yo'av
Re: [PATCH v3] ARM: imx: Fix suspend/resume crash with Clang CFI
Posted by Sami Tolvanen 1 day, 8 hours ago
On Thu, Jul 23, 2026 at 6:30 AM Yo'av Moshe <linux@yoavmoshe.com> wrote:
>
> On 2026-07-22 8:03 PM, Sami Tolvanen wrote:
> > As long as the C prototype for the assembly function matches the
> > function pointer type, the hashes should also match. Can you dump the
> > hash prefix from the OCRAM and compare it to the disassembly of the
> > call site?
> Here is what I saw when checking the disassembly in vmlinux:
>
> 1. Call site expected hash in pm-imx6.c: 0xA488EBFC
> 2. SYM_TYPED_FUNC_START hash prefix in suspend-imx6.S: 0xd4d4d4d4

What's the value for the __kcfi_typeid_imx6_suspend symbol in
vmlinux.o? I would expect the hash value to look a bit more random.

> It looks like because suspend-imx6.S is an assembly file, Clang emits
> the default assembly type ID (0xd4d4d4d4) for it, which doesn't match
> the C call site expectation (0xA488EBFC).

Clang doesn't actually emit type hashes for assembly functions.
SYM_TYPED_FUNC_START just adds a reference to the
__kcfi_typeid_<functionname> symbol that contains a hash calculated
for the C prototype.

Sami
Re: [PATCH v3] ARM: imx: Fix suspend/resume crash with Clang CFI
Posted by Yo'av Moshe 1 day, 7 hours ago
On 2026-07-23 9:21 PM, Sami Tolvanen wrote:
> What's the value for the __kcfi_typeid_imx6_suspend symbol in
> vmlinux.o? I would expect the hash value to look a bit more random.
Checking vmlinux.o with `llvm-readelf -s vmlinux.o` indeed shows:

  a488ebfc  0 NOTYPE  WEAK  DEFAULT  ABS __kcfi_typeid_imx6_suspend

Yo'av
Re: [PATCH v3] ARM: imx: Fix suspend/resume crash with Clang CFI
Posted by Sami Tolvanen 12 hours ago
On Thu, Jul 23, 2026 at 12:56 PM Yo'av Moshe <linux@yoavmoshe.com> wrote:
>
> On 2026-07-23 9:21 PM, Sami Tolvanen wrote:
> > What's the value for the __kcfi_typeid_imx6_suspend symbol in
> > vmlinux.o? I would expect the hash value to look a bit more random.
> Checking vmlinux.o with `llvm-readelf -s vmlinux.o` indeed shows:
>
>   a488ebfc  0 NOTYPE  WEAK  DEFAULT  ABS __kcfi_typeid_imx6_suspend

OK, so the hashes should match. I can only assume that the hash prefix
doesn't end up getting copied to OCRAM for some reason then, or
perhaps the source of the copy operation doesn't have relocations
applied? Either way, if this turns out to be infeasible, I think the
__nocfi approach is reasonable in this case too.

Sami
Re: [PATCH v3] ARM: imx: Fix suspend/resume crash with Clang CFI
Posted by Nick Desaulniers 7 hours ago
On Fri, Jul 24, 2026 at 8:54 AM Sami Tolvanen <samitolvanen@google.com> wrote:
>
> On Thu, Jul 23, 2026 at 12:56 PM Yo'av Moshe <linux@yoavmoshe.com> wrote:
> >
> > On 2026-07-23 9:21 PM, Sami Tolvanen wrote:
> > > What's the value for the __kcfi_typeid_imx6_suspend symbol in
> > > vmlinux.o? I would expect the hash value to look a bit more random.
> > Checking vmlinux.o with `llvm-readelf -s vmlinux.o` indeed shows:
> >
> >   a488ebfc  0 NOTYPE  WEAK  DEFAULT  ABS __kcfi_typeid_imx6_suspend
>
> OK, so the hashes should match. I can only assume that the hash prefix
> doesn't end up getting copied to OCRAM for some reason then, or

Yeah, Yo'av did you test further modifications that explicitly copy
the hash prefix? I assumed Nathan's change _plus some additional tweak
to copy not just imx6_suspend to OCRAM which I assume the code already
does, but I would imagine you need another change to copy
__kcfi_typeid_imx6_suspend into OCRAM just before the function.  Was
that tested?

> perhaps the source of the copy operation doesn't have relocations
> applied? Either way, if this turns out to be infeasible, I think the
> __nocfi approach is reasonable in this case too.
>
> Sami



-- 
Thanks,
~Nick Desaulniers
Re: [PATCH v3] ARM: imx: Fix suspend/resume crash with Clang CFI
Posted by Nick Desaulniers 4 days, 11 hours ago
On Sat, Jul 18, 2026 at 4:14 AM Yo'av Moshe <linux@yoavmoshe.com> wrote:
>
> Relocated suspend code in OCRAM lacks compiler-generated CFI type
> signatures. When CONFIG_CFI=y is active, the indirect call to
> imx6_suspend_in_ocram_fn triggers a strict CFI violation panic.
>
> To resolve this safely without reducing CFI protection scope:
> 1. Create a minimal wrapper function imx6_suspend_in_ocram annotated
>    with __nocfi to handle the unverified indirect call.
> 2. Remove the __nocfi annotation from the main imx6q_suspend_finish
>    function to preserve full CFI coverage for other indirect calls
>    in that scope (such as cpu_do_idle() and flush_cache_all()).
> 3. Mark global variables ccm_base, suspend_ocram_base, and the
>    imx6_suspend_in_ocram_fn pointer as __ro_after_init to prevent
>    them from being used as target vectors for CFI bypass exploits.
>
> Cc: stable@vger.kernel.org
> Signed-off-by: Yo'av Moshe <linux@yoavmoshe.com>
> ---
> Tested on a Kobo Clara HD (i.MX6SLL SoC) running postmarketOS edge.
> Before this patch, suspending the device caused an immediate silent
> hang requiring a hard-reboot. With this patch applied, suspend and
> resume work successfully.
>
> Differences from v2:
> - Restrained __nocfi scope by adding a dedicated, minimal 1-line
>   wrapper function (imx6_suspend_in_ocram) for the OCRAM call,
>   avoiding disabling CFI checks for cpu_do_idle() and flush_cache_all().
> - Marked global pointers ccm_base and suspend_ocram_base as
>   __ro_after_init to fully neutralize Write-What-Where exploit bypasses.
>
>  arch/arm/mach-imx/pm-imx6.c | 13 +++++++++----
>  1 file changed, 9 insertions(+), 4 deletions(-)
>
> diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c
> index a671ca498..3d5b960c5 100644
> --- a/arch/arm/mach-imx/pm-imx6.c
> +++ b/arch/arm/mach-imx/pm-imx6.c
> @@ -61,9 +61,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;

Are we able to just put __nocfi on the declaration of
`imx6_suspend_in_ocram_fn`, rather than bother with a wrapper
(imx6_suspend_in_ocram)? I don't know if that works, but surely you
can test that quickly?

>
>  /*
>   * suspend ocram space layout:
> @@ -360,6 +360,11 @@ int imx6_set_lpm(enum mxc_cpu_pwr_mode mode)
>         return 0;
>  }
>
> +static void __nocfi imx6_suspend_in_ocram(void __iomem *ocram_vbase)
> +{
> +       imx6_suspend_in_ocram_fn(ocram_vbase);
> +}
> +
>  static int imx6q_suspend_finish(unsigned long val)
>  {
>         if (!imx6_suspend_in_ocram_fn) {
> @@ -374,7 +379,7 @@ static int imx6q_suspend_finish(unsigned long val)
>                 if (!((struct imx6_cpu_pm_info *)
>                         suspend_ocram_base)->l2_base.vbase)
>                         flush_cache_all();
> -               imx6_suspend_in_ocram_fn(suspend_ocram_base);
> +               imx6_suspend_in_ocram(suspend_ocram_base);
>         }
>
>         return 0;
> --
> 2.55.0
>


-- 
Thanks,
~Nick Desaulniers
Re: [PATCH v3] ARM: imx: Fix suspend/resume crash with Clang CFI
Posted by Yo'av Moshe 3 days, 22 hours ago
On 2026-07-20 6:53 PM, Nick Desaulniers wrote:
> 
> Are we able to just put __nocfi on the declaration of
> `imx6_suspend_in_ocram_fn`, rather than bother with a wrapper
> (imx6_suspend_in_ocram)? I don't know if that works, but surely you
> can test that quickly?
Thanks for the suggestion! I tested placing __nocfi directly on the
imx6_suspend_in_ocram_fn variable declaration:

    static void (* __nocfi imx6_suspend_in_ocram_fn)(void __iomem *ocram_vbase);

Unfortunately, Clang ignores no_sanitize("cfi") on variable declarations and
emits a compiler warning:

    warning: 'no_sanitize' attribute argument 'cfi' not supported on a
    global variable [-Wignored-attributes]

Because Clang ignores it, it still injects the CFI check at the call site.
I tested this on physical hardware (Kobo Clara HD), and it crashes on suspend.

Best regards,
Yo'av