Linux s390 Architecture development
 help / color / mirror / Atom feed
* [PATCH v3] s390/cpacf: Unpoison instruction results
@ 2026-08-14 12:15 Ilya Leoshkevich
  2026-08-14 12:27 ` sashiko-bot
  0 siblings, 1 reply; 3+ messages in thread
From: Ilya Leoshkevich @ 2026-08-14 12:15 UTC (permalink / raw)
  To: Harald Freudenberger, Holger Dengler, Heiko Carstens,
	Vasily Gorbik, Alexander Gordeev
  Cc: linux-s390, linux-kernel, Ilya Leoshkevich

Stop KMSAN from complaining about CPACF outputs being uninitialized.

Do not unpoison variable-length parameter blocks: mapping function
codes (like CPACF_KIMD_SHA_256) to lengths will be ugly. So let the
callers do this once the need arises.

Also do not touch cpacf_kma(): this wrapper does not handle cc 1 and
cc2 at the moment and has to be reworked.

Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---

v2: https://lore.kernel.org/all/20260807122132.3592583-1-iii@linux.ibm.com/
v2 -> v3: Drop cpacf_kma() change, add R-b (Harald).

v1: https://lore.kernel.org/linux-s390/20260806190223.3292580-1-iii@linux.ibm.com/
v1 -> v2: Unpoison outputs of more instructions (Sashiko).

 arch/s390/include/asm/cpacf.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/s390/include/asm/cpacf.h b/arch/s390/include/asm/cpacf.h
index a83683169d98d..6174552d856dc 100644
--- a/arch/s390/include/asm/cpacf.h
+++ b/arch/s390/include/asm/cpacf.h
@@ -301,6 +301,7 @@ static __always_inline void __cpacf_query(unsigned int opcode,
 					  cpacf_mask_t *mask)
 {
 	__cpacf_query_insn(opcode, mask, CPACF_FC_QUERY);
+	kmsan_unpoison_memory(mask, sizeof(*mask));
 }
 
 static __always_inline int __cpacf_check_opcode(unsigned int opcode)
@@ -370,6 +371,7 @@ static __always_inline int cpacf_query_func(unsigned int opcode,
 static __always_inline void __cpacf_qai(unsigned int opcode, cpacf_qai_t *qai)
 {
 	__cpacf_query_insn(opcode, qai, CPACF_FC_QUERY_AUTH_INFO);
+	kmsan_unpoison_memory(qai, sizeof(*qai));
 }
 
 /**
@@ -422,6 +424,7 @@ static inline int cpacf_km(unsigned long func, void *param,
 		  [opc] "i" (CPACF_KM)
 		: "cc", "memory", "0", "1");
 
+	kmsan_unpoison_memory(dest, src_len - s.odd);
 	return src_len - s.odd;
 }
 
@@ -454,6 +457,7 @@ static inline int cpacf_kmc(unsigned long func, void *param,
 		  [opc] "i" (CPACF_KMC)
 		: "cc", "memory", "0", "1");
 
+	kmsan_unpoison_memory(dest, src_len - s.odd);
 	return src_len - s.odd;
 }
 
@@ -587,6 +591,7 @@ static inline int cpacf_kmctr(unsigned long func, void *param, u8 *dest,
 		  [opc] "i" (CPACF_KMCTR)
 		: "cc", "memory", "0", "1");
 
+	kmsan_unpoison_memory(dest, src_len - s.odd);
 	return src_len - s.odd;
 }
 
@@ -619,6 +624,7 @@ static inline void cpacf_prno(unsigned long func, void *param,
 		: [fc] "d" (func), [pba] "d" ((unsigned long)param),
 		  [seed] "d" (s.pair), [opc] "i" (CPACF_PRNO)
 		: "cc", "memory", "0", "1");
+	kmsan_unpoison_memory(dest, dest_len);
 }
 
 /**
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v3] s390/cpacf: Unpoison instruction results
  2026-08-14 12:15 [PATCH v3] s390/cpacf: Unpoison instruction results Ilya Leoshkevich
@ 2026-08-14 12:27 ` sashiko-bot
  2026-08-14 13:54   ` Ilya Leoshkevich
  0 siblings, 1 reply; 3+ messages in thread
From: sashiko-bot @ 2026-08-14 12:27 UTC (permalink / raw)
  To: Ilya Leoshkevich
  Cc: Christian Borntraeger, linux-s390, Vasily Gorbik, Heiko Carstens,
	Alexander Gordeev

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

New issues:
- [High] Unconditional KMSAN unpoisoning masks partial completions and information leaks.

Pre-existing issues:
- [Critical] Silent ignoring of PRNO and TRNG partial completions causes critical information leaks.
- [High] Silent ignoring of KMA operation failures causes cryptographic protocol violations.
--

--- Patch [1]: [PATCH v3] s390/cpacf: Unpoison instruction results ---
commit c65c87d6cf548eaef4bd0b06821cb0e68caaa4c3
Author: Ilya Leoshkevich <iii@linux.ibm.com>

s390/cpacf: Unpoison instruction results

This commit suppresses KMSAN uninitialized memory warnings for CPACF
outputs by adding kmsan_unpoison_memory() calls to multiple wrappers.
It intentionally avoids modifying variable-length parameter blocks and
the cpacf_kma() wrapper.

> Also do not touch cpacf_kma(): this wrapper does not handle cc 1 and
> cc2 at the moment and has to be reworked.

[Severity: High]
This is a pre-existing issue, but does silently falling through on Condition
Code 1 and 2 in cpacf_kma() cause callers (like gcm_aes_crypt) to accept
cryptographic errors?

By returning void when the KMA instruction encounters an error (such as
incorrect AAD/plaintext lengths or a hardware abort), callers have no way
of knowing the operation failed. This could result in partially written or
completely uninitialized ciphertext, plaintext, and tags being processed as
valid data.


> diff --git a/arch/s390/include/asm/cpacf.h b/arch/s390/include/asm/cpacf.h
> index a83683169d98d..6174552d856dc 100644
> --- a/arch/s390/include/asm/cpacf.h
> +++ b/arch/s390/include/asm/cpacf.h

[ ... ]

> @@ -619,6 +624,7 @@ static inline void cpacf_prno(unsigned long func, void *param,
>  		: [fc] "d" (func), [pba] "d" ((unsigned long)param),
>  		  [seed] "d" (s.pair), [opc] "i" (CPACF_PRNO)
>  		: "cc", "memory", "0", "1");
> +	kmsan_unpoison_memory(dest, dest_len);

[Severity: High]
Does unpoisoning the requested length (dest_len) instead of the written length
(dest_len - d.odd) mask partial completions?

When cpacf_prno() terminates early (e.g., returning Condition Code 1 due to
entropy exhaustion), the hardware only partially fills the destination buffer.
Unconditionally unpoisoning the requested length blinds KMSAN to the
uninitialized tail of the buffer, potentially hiding active kernel memory
information leaks. 

It appears the pre-existing cpacf_trng() wrapper suffers from the same
issue, unpoisoning ucbuf_len and cbuf_len unconditionally.


[Severity: Critical]
This is a pre-existing issue, but does the silent exit on Condition Code 1
in cpacf_trng() cause uninitialized kernel memory to be copied to userspace?

Looking at cpacf_trng() in arch/s390/include/asm/cpacf.h, the assembly only
loops on Condition Code 3:

	asm volatile (
		"	lghi	0,%[fc]\n"
		"0:	.insn	rre,%[opc] << 16,%[ucbuf],%[cbuf]\n"
		"	brc	1,0b"	  /* handle partial completion */
		: [ucbuf] "+&d" (u.pair), [cbuf] "+&d" (c.pair)
		: [fc] "K" (CPACF_PRNO_TRNG), [opc] "i" (CPACF_PRNO)
		: "cc", "memory", "0");

If hardware TRNG entropy is exhausted, it returns CC 1 and falls through,
discarding the unwritten byte counters (c.odd) and returning void.

Because the wrapper returns void, trng_read() in
drivers/char/hw_random/s390-trng.c falsely assumes the entire buffer allocated
with kmalloc(..., GFP_KERNEL) was filled:

	cpacf_trng(NULL, 0, p, n);
	atomic64_add(n, &trng_dev_counter);
	if (copy_to_user(ubuf, p, n)) {

Can this sequence leak uninitialized kernel heap memory to any unprivileged
local user reading from /dev/trng until entropy runs out?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260814121559.1240939-1-iii@linux.ibm.com?part=1

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v3] s390/cpacf: Unpoison instruction results
  2026-08-14 12:27 ` sashiko-bot
@ 2026-08-14 13:54   ` Ilya Leoshkevich
  0 siblings, 0 replies; 3+ messages in thread
From: Ilya Leoshkevich @ 2026-08-14 13:54 UTC (permalink / raw)
  To: sashiko-reviews
  Cc: Christian Borntraeger, linux-s390, Vasily Gorbik, Heiko Carstens,
	Alexander Gordeev



On 8/14/26 14:27, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
> 
> New issues:
> - [High] Unconditional KMSAN unpoisoning masks partial completions and information leaks.
> 
> Pre-existing issues:
> - [Critical] Silent ignoring of PRNO and TRNG partial completions causes critical information leaks.
> - [High] Silent ignoring of KMA operation failures causes cryptographic protocol violations.
> --
> 
> --- Patch [1]: [PATCH v3] s390/cpacf: Unpoison instruction results ---
> commit c65c87d6cf548eaef4bd0b06821cb0e68caaa4c3
> Author: Ilya Leoshkevich <iii@linux.ibm.com>
> 
> s390/cpacf: Unpoison instruction results
> 
> This commit suppresses KMSAN uninitialized memory warnings for CPACF
> outputs by adding kmsan_unpoison_memory() calls to multiple wrappers.
> It intentionally avoids modifying variable-length parameter blocks and
> the cpacf_kma() wrapper.
> 
>> Also do not touch cpacf_kma(): this wrapper does not handle cc 1 and
>> cc2 at the moment and has to be reworked.
> 
> [Severity: High]
> This is a pre-existing issue, but does silently falling through on Condition
> Code 1 and 2 in cpacf_kma() cause callers (like gcm_aes_crypt) to accept
> cryptographic errors?
> 
> By returning void when the KMA instruction encounters an error (such as
> incorrect AAD/plaintext lengths or a hardware abort), callers have no way
> of knowing the operation failed. This could result in partially written or
> completely uninitialized ciphertext, plaintext, and tags being processed as
> valid data.

Yes. As stated in the commit message and discussed in v2, this will be
addressed separately.

>> diff --git a/arch/s390/include/asm/cpacf.h b/arch/s390/include/asm/cpacf.h
>> index a83683169d98d..6174552d856dc 100644
>> --- a/arch/s390/include/asm/cpacf.h
>> +++ b/arch/s390/include/asm/cpacf.h
> 
> [ ... ]
> 
>> @@ -619,6 +624,7 @@ static inline void cpacf_prno(unsigned long func, void *param,
>>   		: [fc] "d" (func), [pba] "d" ((unsigned long)param),
>>   		  [seed] "d" (s.pair), [opc] "i" (CPACF_PRNO)
>>   		: "cc", "memory", "0", "1");
>> +	kmsan_unpoison_memory(dest, dest_len);
> 
> [Severity: High]
> Does unpoisoning the requested length (dest_len) instead of the written length
> (dest_len - d.odd) mask partial completions?
> 
> When cpacf_prno() terminates early (e.g., returning Condition Code 1 due to
> entropy exhaustion), the hardware only partially fills the destination buffer.
> Unconditionally unpoisoning the requested length blinds KMSAN to the
> uninitialized tail of the buffer, potentially hiding active kernel memory
> information leaks.
> 
> It appears the pre-existing cpacf_trng() wrapper suffers from the same
> issue, unpoisoning ucbuf_len and cbuf_len unconditionally.

PRNO cannot return CC 1. The only documented values are 0 (normal
completion) and 3 (partial completion).

> [Severity: Critical]
> This is a pre-existing issue, but does the silent exit on Condition Code 1
> in cpacf_trng() cause uninitialized kernel memory to be copied to userspace?
> 
> Looking at cpacf_trng() in arch/s390/include/asm/cpacf.h, the assembly only
> loops on Condition Code 3:
> 
> 	asm volatile (
> 		"	lghi	0,%[fc]\n"
> 		"0:	.insn	rre,%[opc] << 16,%[ucbuf],%[cbuf]\n"
> 		"	brc	1,0b"	  /* handle partial completion */
> 		: [ucbuf] "+&d" (u.pair), [cbuf] "+&d" (c.pair)
> 		: [fc] "K" (CPACF_PRNO_TRNG), [opc] "i" (CPACF_PRNO)
> 		: "cc", "memory", "0");
> 
> If hardware TRNG entropy is exhausted, it returns CC 1 and falls through,
> discarding the unwritten byte counters (c.odd) and returning void.
> 
> Because the wrapper returns void, trng_read() in
> drivers/char/hw_random/s390-trng.c falsely assumes the entire buffer allocated
> with kmalloc(..., GFP_KERNEL) was filled:
> 
> 	cpacf_trng(NULL, 0, p, n);
> 	atomic64_add(n, &trng_dev_counter);
> 	if (copy_to_user(ubuf, p, n)) {
> 
> Can this sequence leak uninitialized kernel heap memory to any unprivileged
> local user reading from /dev/trng until entropy runs out?

Same as above.

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-08-14 13:54 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-14 12:15 [PATCH v3] s390/cpacf: Unpoison instruction results Ilya Leoshkevich
2026-08-14 12:27 ` sashiko-bot
2026-08-14 13:54   ` Ilya Leoshkevich

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox