| From 430fa71027b6ac9bb0ce5532b8d0676777d4219a Mon Sep 17 00:00:00 2001 |
| From: Peter Oberparleiter <oberpar@linux.ibm.com> |
| Date: Mon, 18 Aug 2025 12:21:52 +0200 |
| Subject: s390/sclp: Fix SCCB present check |
| |
| From: Peter Oberparleiter <oberpar@linux.ibm.com> |
| |
| commit 430fa71027b6ac9bb0ce5532b8d0676777d4219a upstream. |
| |
| Tracing code called by the SCLP interrupt handler contains early exits |
| if the SCCB address associated with an interrupt is NULL. This check is |
| performed after physical to virtual address translation. |
| |
| If the kernel identity mapping does not start at address zero, the |
| resulting virtual address is never zero, so that the NULL checks won't |
| work. Subsequently this may result in incorrect accesses to the first |
| page of the identity mapping. |
| |
| Fix this by introducing a function that handles the NULL case before |
| address translation. |
| |
| Fixes: ada1da31ce34 ("s390/sclp: sort out physical vs virtual pointers usage") |
| Cc: stable@vger.kernel.org |
| Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com> |
| Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com> |
| Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/s390/char/sclp.c | 11 +++++++++-- |
| 1 file changed, 9 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/s390/char/sclp.c |
| +++ b/drivers/s390/char/sclp.c |
| @@ -76,6 +76,13 @@ unsigned long sclp_console_full; |
| /* The currently active SCLP command word. */ |
| static sclp_cmdw_t active_cmd; |
| |
| +static inline struct sccb_header *sclpint_to_sccb(u32 sccb_int) |
| +{ |
| + if (sccb_int) |
| + return __va(sccb_int); |
| + return NULL; |
| +} |
| + |
| static inline void sclp_trace(int prio, char *id, u32 a, u64 b, bool err) |
| { |
| struct sclp_trace_entry e; |
| @@ -619,7 +626,7 @@ __sclp_find_req(u32 sccb) |
| |
| static bool ok_response(u32 sccb_int, sclp_cmdw_t cmd) |
| { |
| - struct sccb_header *sccb = (struct sccb_header *)__va(sccb_int); |
| + struct sccb_header *sccb = sclpint_to_sccb(sccb_int); |
| struct evbuf_header *evbuf; |
| u16 response; |
| |
| @@ -658,7 +665,7 @@ static void sclp_interrupt_handler(struc |
| |
| /* INT: Interrupt received (a=intparm, b=cmd) */ |
| sclp_trace_sccb(0, "INT", param32, active_cmd, active_cmd, |
| - (struct sccb_header *)__va(finished_sccb), |
| + sclpint_to_sccb(finished_sccb), |
| !ok_response(finished_sccb, active_cmd)); |
| |
| if (finished_sccb) { |