| From b38cf46addff8bae06a403719aa11a99a3bfd8ca Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 8 Apr 2024 09:08:31 -0500 |
| Subject: powerpc/pseries: Enforce hcall result buffer validity and size |
| |
| From: Nathan Lynch <nathanl@linux.ibm.com> |
| |
| [ Upstream commit ff2e185cf73df480ec69675936c4ee75a445c3e4 ] |
| |
| plpar_hcall(), plpar_hcall9(), and related functions expect callers to |
| provide valid result buffers of certain minimum size. Currently this |
| is communicated only through comments in the code and the compiler has |
| no idea. |
| |
| For example, if I write a bug like this: |
| |
| long retbuf[PLPAR_HCALL_BUFSIZE]; // should be PLPAR_HCALL9_BUFSIZE |
| plpar_hcall9(H_ALLOCATE_VAS_WINDOW, retbuf, ...); |
| |
| This compiles with no diagnostics emitted, but likely results in stack |
| corruption at runtime when plpar_hcall9() stores results past the end |
| of the array. (To be clear this is a contrived example and I have not |
| found a real instance yet.) |
| |
| To make this class of error less likely, we can use explicitly-sized |
| array parameters instead of pointers in the declarations for the hcall |
| APIs. When compiled with -Warray-bounds[1], the code above now |
| provokes a diagnostic like this: |
| |
| error: array argument is too small; |
| is of size 32, callee requires at least 72 [-Werror,-Warray-bounds] |
| 60 | plpar_hcall9(H_ALLOCATE_VAS_WINDOW, retbuf, |
| | ^ ~~~~~~ |
| |
| [1] Enabled for LLVM builds but not GCC for now. See commit |
| 0da6e5fd6c37 ("gcc: disable '-Warray-bounds' for gcc-13 too") and |
| related changes. |
| |
| Signed-off-by: Nathan Lynch <nathanl@linux.ibm.com> |
| Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> |
| Link: https://msgid.link/20240408-pseries-hvcall-retbuf-v1-1-ebc73d7253cf@linux.ibm.com |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| arch/powerpc/include/asm/hvcall.h | 8 ++++---- |
| 1 file changed, 4 insertions(+), 4 deletions(-) |
| |
| diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h |
| index 51172625fa3a5..7a8495660c2f8 100644 |
| --- a/arch/powerpc/include/asm/hvcall.h |
| +++ b/arch/powerpc/include/asm/hvcall.h |
| @@ -524,7 +524,7 @@ long plpar_hcall_norets_notrace(unsigned long opcode, ...); |
| * Used for all but the craziest of phyp interfaces (see plpar_hcall9) |
| */ |
| #define PLPAR_HCALL_BUFSIZE 4 |
| -long plpar_hcall(unsigned long opcode, unsigned long *retbuf, ...); |
| +long plpar_hcall(unsigned long opcode, unsigned long retbuf[static PLPAR_HCALL_BUFSIZE], ...); |
| |
| /** |
| * plpar_hcall_raw: - Make a hypervisor call without calculating hcall stats |
| @@ -538,7 +538,7 @@ long plpar_hcall(unsigned long opcode, unsigned long *retbuf, ...); |
| * plpar_hcall, but plpar_hcall_raw works in real mode and does not |
| * calculate hypervisor call statistics. |
| */ |
| -long plpar_hcall_raw(unsigned long opcode, unsigned long *retbuf, ...); |
| +long plpar_hcall_raw(unsigned long opcode, unsigned long retbuf[static PLPAR_HCALL_BUFSIZE], ...); |
| |
| /** |
| * plpar_hcall9: - Make a pseries hypervisor call with up to 9 return arguments |
| @@ -549,8 +549,8 @@ long plpar_hcall_raw(unsigned long opcode, unsigned long *retbuf, ...); |
| * PLPAR_HCALL9_BUFSIZE to size the return argument buffer. |
| */ |
| #define PLPAR_HCALL9_BUFSIZE 9 |
| -long plpar_hcall9(unsigned long opcode, unsigned long *retbuf, ...); |
| -long plpar_hcall9_raw(unsigned long opcode, unsigned long *retbuf, ...); |
| +long plpar_hcall9(unsigned long opcode, unsigned long retbuf[static PLPAR_HCALL9_BUFSIZE], ...); |
| +long plpar_hcall9_raw(unsigned long opcode, unsigned long retbuf[static PLPAR_HCALL9_BUFSIZE], ...); |
| |
| /* pseries hcall tracing */ |
| extern struct static_key hcall_tracepoint_key; |
| -- |
| 2.43.0 |
| |