Skip to content

Commit d7221b4

Browse files
committed
Fix integer overflow in DMA allow list boundary check
Add overflow guards to _checkAddrAgainstAllowList to prevent address-space wraparound from bypassing the allow list on 32-bit and 64-bit systems. Reject requests where addr + size overflows, and skip allow list entries whose own range overflows. Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
1 parent 01fe072 commit d7221b4

File tree

4 files changed

+220
-3
lines changed

4 files changed

+220
-3
lines changed

src/wh_dma.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,22 +51,34 @@ static int _checkAddrAgainstAllowList(const whDmaAddrList allowList, void* addr,
5151
size_t size)
5252
{
5353
uintptr_t startAddr = (uintptr_t)addr;
54-
uintptr_t endAddr = startAddr + size;
55-
int i = 0;
54+
uintptr_t endAddr;
55+
int i = 0;
5656

5757
if (0 == size) {
5858
return WH_ERROR_BADARGS;
5959
}
6060

61+
/* Reject if the requested range would wrap the address space */
62+
if (startAddr > UINTPTR_MAX - size) {
63+
return WH_ERROR_BADARGS;
64+
}
65+
endAddr = startAddr + size;
66+
6167
/* Check if the address range is fully within a allowlist entry */
6268
for (i = 0; i < WOLFHSM_CFG_DMAADDR_COUNT; i++) {
6369
uintptr_t allowListStartAddr = (uintptr_t)allowList[i].addr;
64-
uintptr_t allowListEndAddr = allowListStartAddr + allowList[i].size;
70+
uintptr_t allowListEndAddr;
6571

6672
if (0 == allowList[i].size) {
6773
continue;
6874
}
6975

76+
/* Skip allow list entries that would wrap the address space */
77+
if (allowListStartAddr > UINTPTR_MAX - allowList[i].size) {
78+
continue;
79+
}
80+
allowListEndAddr = allowListStartAddr + allowList[i].size;
81+
7082
if (startAddr >= allowListStartAddr && endAddr <= allowListEndAddr) {
7183
return WH_ERROR_OK;
7284
}

test/wh_test.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "wh_test_posix_threadsafe_stress.h"
4545
#include "wh_test_crypto_affinity.h"
4646
#include "wh_test_timeout.h"
47+
#include "wh_test_dma.h"
4748

4849
#if defined(WOLFHSM_CFG_CERTIFICATE_MANAGER)
4950
#include "wh_test_cert.h"
@@ -87,6 +88,10 @@ int whTest_Unit(void)
8788

8889
#endif /* WOLFHSM_CFG_CERTIFICATE_MANAGER && !WOLFHSM_CFG_NO_CRYPTO */
8990

91+
#ifdef WOLFHSM_CFG_DMA
92+
WH_TEST_ASSERT(0 == whTest_Dma());
93+
#endif
94+
9095
/* Comm tests */
9196
WH_TEST_ASSERT(0 == whTest_Comm());
9297
WH_TEST_ASSERT(0 == whTest_ClientServer());

test/wh_test_dma.c

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
/*
2+
* Copyright (C) 2026 wolfSSL Inc.
3+
*
4+
* This file is part of wolfHSM.
5+
*
6+
* wolfHSM is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* wolfHSM is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with wolfHSM. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
/*
20+
* test/wh_test_dma.c
21+
*
22+
* Tests for DMA allow list boundary checking, including integer overflow
23+
* detection on the end-address computation.
24+
*/
25+
26+
#include "wolfhsm/wh_settings.h"
27+
28+
#ifdef WOLFHSM_CFG_DMA
29+
30+
#include <stdint.h>
31+
#include <stddef.h>
32+
#include <string.h>
33+
34+
#include "wolfhsm/wh_error.h"
35+
#include "wolfhsm/wh_dma.h"
36+
37+
#include "wh_test_common.h"
38+
#include "wh_test_dma.h"
39+
40+
static int whTest_DmaAllowListBasic(void)
41+
{
42+
int rc;
43+
whDmaAddrAllowList allowList;
44+
45+
memset(&allowList, 0, sizeof(allowList));
46+
47+
allowList.readList[0].addr = (void*)((uintptr_t)0x10000);
48+
allowList.readList[0].size = 0x10000;
49+
50+
WH_TEST_PRINT(" Testing basic allow list acceptance...\n");
51+
rc = wh_Dma_CheckMemOperAgainstAllowList(
52+
&allowList, WH_DMA_OPER_CLIENT_READ_PRE,
53+
(void*)((uintptr_t)0x10000), 0x1000);
54+
WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK);
55+
56+
WH_TEST_PRINT(" Testing basic allow list rejection...\n");
57+
rc = wh_Dma_CheckMemOperAgainstAllowList(
58+
&allowList, WH_DMA_OPER_CLIENT_READ_PRE,
59+
(void*)((uintptr_t)0x30000), 0x1000);
60+
WH_TEST_ASSERT_RETURN(rc == WH_ERROR_ACCESS);
61+
62+
WH_TEST_PRINT(" Testing zero-size rejection...\n");
63+
rc = wh_Dma_CheckMemOperAgainstAllowList(
64+
&allowList, WH_DMA_OPER_CLIENT_READ_PRE,
65+
(void*)((uintptr_t)0x10000), 0);
66+
WH_TEST_ASSERT_RETURN(rc == WH_ERROR_BADARGS);
67+
68+
WH_TEST_PRINT(" Testing NULL allowlist passthrough...\n");
69+
rc = wh_Dma_CheckMemOperAgainstAllowList(
70+
NULL, WH_DMA_OPER_CLIENT_READ_PRE,
71+
(void*)((uintptr_t)0x10000), 0x1000);
72+
WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK);
73+
74+
return WH_ERROR_OK;
75+
}
76+
77+
static int whTest_DmaAllowListOverflow(void)
78+
{
79+
int rc;
80+
whDmaAddrAllowList allowList;
81+
uintptr_t maliciousAddr;
82+
size_t maliciousSize;
83+
84+
memset(&allowList, 0, sizeof(allowList));
85+
86+
/*
87+
* Allow list region: [0x10000, 0x20000)
88+
* allowListEndAddr = 0x10000 + 0x10000 = 0x20000 (no overflow)
89+
*/
90+
allowList.readList[0].addr = (void*)((uintptr_t)0x10000);
91+
allowList.readList[0].size = 0x10000;
92+
93+
/*
94+
* Craft a request whose endAddr wraps around to land inside the allow list:
95+
* startAddr = UINTPTR_MAX - 0xFF (near top of address space)
96+
* size = 0x20100
97+
* endAddr = (UINTPTR_MAX - 0xFF) + 0x20100
98+
* = UINTPTR_MAX + 0x20001
99+
* = 0x20000 (truncated on any width)
100+
*
101+
* Without overflow protection the check sees:
102+
* startAddr(huge) >= allowListStartAddr(0x10000) -> TRUE
103+
* endAddr(0x20000) <= allowListEndAddr(0x20000) -> TRUE
104+
* and incorrectly allows access to memory at the top of the address space.
105+
*/
106+
maliciousAddr = UINTPTR_MAX - 0xFF;
107+
maliciousSize = 0x20100;
108+
109+
WH_TEST_PRINT(" Testing request end-address overflow "
110+
"(sizeof(uintptr_t)=%u)...\n",
111+
(unsigned)sizeof(uintptr_t));
112+
rc = wh_Dma_CheckMemOperAgainstAllowList(
113+
&allowList, WH_DMA_OPER_CLIENT_READ_PRE,
114+
(void*)maliciousAddr, maliciousSize);
115+
WH_TEST_ASSERT_RETURN(rc != WH_ERROR_OK);
116+
117+
/*
118+
* Second vector: addr = UINTPTR_MAX, size = 1
119+
* endAddr = UINTPTR_MAX + 1 = 0 (wraps to zero)
120+
*/
121+
WH_TEST_PRINT(" Testing boundary wrap addr=UINTPTR_MAX size=1...\n");
122+
rc = wh_Dma_CheckMemOperAgainstAllowList(
123+
&allowList, WH_DMA_OPER_CLIENT_READ_PRE,
124+
(void*)UINTPTR_MAX, 1);
125+
WH_TEST_ASSERT_RETURN(rc != WH_ERROR_OK);
126+
127+
/*
128+
* Third vector: size = UINTPTR_MAX with a non-zero start address.
129+
* addr = 1, size = UINTPTR_MAX
130+
* endAddr = 1 + UINTPTR_MAX = 0 (wraps to zero)
131+
*/
132+
WH_TEST_PRINT(" Testing maximum size overflow addr=1 "
133+
"size=UINTPTR_MAX...\n");
134+
rc = wh_Dma_CheckMemOperAgainstAllowList(
135+
&allowList, WH_DMA_OPER_CLIENT_READ_PRE,
136+
(void*)((uintptr_t)1), (size_t)UINTPTR_MAX);
137+
WH_TEST_ASSERT_RETURN(rc != WH_ERROR_OK);
138+
139+
/* Also test the write list path */
140+
memset(&allowList, 0, sizeof(allowList));
141+
allowList.writeList[0].addr = (void*)((uintptr_t)0x10000);
142+
allowList.writeList[0].size = 0x10000;
143+
144+
WH_TEST_PRINT(" Testing write-path overflow...\n");
145+
rc = wh_Dma_CheckMemOperAgainstAllowList(
146+
&allowList, WH_DMA_OPER_CLIENT_WRITE_PRE,
147+
(void*)maliciousAddr, maliciousSize);
148+
WH_TEST_ASSERT_RETURN(rc != WH_ERROR_OK);
149+
150+
return WH_ERROR_OK;
151+
}
152+
153+
int whTest_Dma(void)
154+
{
155+
WH_TEST_PRINT("Testing DMA allow list checks...\n");
156+
157+
WH_TEST_RETURN_ON_FAIL(whTest_DmaAllowListBasic());
158+
WH_TEST_RETURN_ON_FAIL(whTest_DmaAllowListOverflow());
159+
160+
WH_TEST_PRINT("DMA allow list tests PASSED\n");
161+
return WH_ERROR_OK;
162+
}
163+
164+
#else /* !WOLFHSM_CFG_DMA */
165+
166+
int whTest_Dma(void)
167+
{
168+
return 0;
169+
}
170+
171+
#endif /* WOLFHSM_CFG_DMA */

test/wh_test_dma.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright (C) 2026 wolfSSL Inc.
3+
*
4+
* This file is part of wolfHSM.
5+
*
6+
* wolfHSM is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* wolfHSM is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with wolfHSM. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
/*
20+
* test/wh_test_dma.h
21+
*
22+
* DMA allow list boundary check tests
23+
*/
24+
#ifndef TEST_WH_TEST_DMA_H_
25+
#define TEST_WH_TEST_DMA_H_
26+
27+
int whTest_Dma(void);
28+
29+
#endif /* TEST_WH_TEST_DMA_H_ */

0 commit comments

Comments
 (0)