Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions src/wh_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,22 +51,34 @@ static int _checkAddrAgainstAllowList(const whDmaAddrList allowList, void* addr,
size_t size)
{
uintptr_t startAddr = (uintptr_t)addr;
uintptr_t endAddr = startAddr + size;
int i = 0;
uintptr_t endAddr;
int i = 0;

if (0 == size) {
return WH_ERROR_BADARGS;
}

/* Reject if the requested range would wrap the address space */
if (startAddr > UINTPTR_MAX - size) {
return WH_ERROR_BADARGS;
}
endAddr = startAddr + size;

/* Check if the address range is fully within a allowlist entry */
for (i = 0; i < WOLFHSM_CFG_DMAADDR_COUNT; i++) {
uintptr_t allowListStartAddr = (uintptr_t)allowList[i].addr;
uintptr_t allowListEndAddr = allowListStartAddr + allowList[i].size;
uintptr_t allowListEndAddr;

if (0 == allowList[i].size) {
continue;
}

/* Skip allow list entries that would wrap the address space */
if (allowListStartAddr > UINTPTR_MAX - allowList[i].size) {
continue;
}
allowListEndAddr = allowListStartAddr + allowList[i].size;

if (startAddr >= allowListStartAddr && endAddr <= allowListEndAddr) {
return WH_ERROR_OK;
}
Expand Down
5 changes: 5 additions & 0 deletions test/wh_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "wh_test_posix_threadsafe_stress.h"
#include "wh_test_crypto_affinity.h"
#include "wh_test_timeout.h"
#include "wh_test_dma.h"

#if defined(WOLFHSM_CFG_CERTIFICATE_MANAGER)
#include "wh_test_cert.h"
Expand Down Expand Up @@ -87,6 +88,10 @@ int whTest_Unit(void)

#endif /* WOLFHSM_CFG_CERTIFICATE_MANAGER && !WOLFHSM_CFG_NO_CRYPTO */

#ifdef WOLFHSM_CFG_DMA
WH_TEST_ASSERT(0 == whTest_Dma());
#endif

/* Comm tests */
WH_TEST_ASSERT(0 == whTest_Comm());
WH_TEST_ASSERT(0 == whTest_ClientServer());
Expand Down
171 changes: 171 additions & 0 deletions test/wh_test_dma.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/*
* Copyright (C) 2026 wolfSSL Inc.
*
* This file is part of wolfHSM.
*
* wolfHSM is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfHSM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with wolfHSM. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* test/wh_test_dma.c
*
* Tests for DMA allow list boundary checking, including integer overflow
* detection on the end-address computation.
*/

#include "wolfhsm/wh_settings.h"

#ifdef WOLFHSM_CFG_DMA

#include <stdint.h>
#include <stddef.h>
#include <string.h>

#include "wolfhsm/wh_error.h"
#include "wolfhsm/wh_dma.h"

#include "wh_test_common.h"
#include "wh_test_dma.h"

static int whTest_DmaAllowListBasic(void)
{
int rc;
whDmaAddrAllowList allowList;

memset(&allowList, 0, sizeof(allowList));

allowList.readList[0].addr = (void*)((uintptr_t)0x10000);
allowList.readList[0].size = 0x10000;

WH_TEST_PRINT(" Testing basic allow list acceptance...\n");
rc = wh_Dma_CheckMemOperAgainstAllowList(
&allowList, WH_DMA_OPER_CLIENT_READ_PRE,
(void*)((uintptr_t)0x10000), 0x1000);
WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK);

WH_TEST_PRINT(" Testing basic allow list rejection...\n");
rc = wh_Dma_CheckMemOperAgainstAllowList(
&allowList, WH_DMA_OPER_CLIENT_READ_PRE,
(void*)((uintptr_t)0x30000), 0x1000);
WH_TEST_ASSERT_RETURN(rc == WH_ERROR_ACCESS);

WH_TEST_PRINT(" Testing zero-size rejection...\n");
rc = wh_Dma_CheckMemOperAgainstAllowList(
&allowList, WH_DMA_OPER_CLIENT_READ_PRE,
(void*)((uintptr_t)0x10000), 0);
WH_TEST_ASSERT_RETURN(rc == WH_ERROR_BADARGS);

WH_TEST_PRINT(" Testing NULL allowlist passthrough...\n");
rc = wh_Dma_CheckMemOperAgainstAllowList(
NULL, WH_DMA_OPER_CLIENT_READ_PRE,
(void*)((uintptr_t)0x10000), 0x1000);
WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK);

return WH_ERROR_OK;
}

static int whTest_DmaAllowListOverflow(void)
{
int rc;
whDmaAddrAllowList allowList;
uintptr_t maliciousAddr;
size_t maliciousSize;

memset(&allowList, 0, sizeof(allowList));

/*
* Allow list region: [0x10000, 0x20000)
* allowListEndAddr = 0x10000 + 0x10000 = 0x20000 (no overflow)
*/
allowList.readList[0].addr = (void*)((uintptr_t)0x10000);
allowList.readList[0].size = 0x10000;

/*
* Craft a request whose endAddr wraps around to land inside the allow list:
* startAddr = UINTPTR_MAX - 0xFF (near top of address space)
* size = 0x20100
* endAddr = (UINTPTR_MAX - 0xFF) + 0x20100
* = UINTPTR_MAX + 0x20001
* = 0x20000 (truncated on any width)
*
* Without overflow protection the check sees:
* startAddr(huge) >= allowListStartAddr(0x10000) -> TRUE
* endAddr(0x20000) <= allowListEndAddr(0x20000) -> TRUE
* and incorrectly allows access to memory at the top of the address space.
*/
maliciousAddr = UINTPTR_MAX - 0xFF;
maliciousSize = 0x20100;

WH_TEST_PRINT(" Testing request end-address overflow "
"(sizeof(uintptr_t)=%u)...\n",
(unsigned)sizeof(uintptr_t));
rc = wh_Dma_CheckMemOperAgainstAllowList(
&allowList, WH_DMA_OPER_CLIENT_READ_PRE,
(void*)maliciousAddr, maliciousSize);
WH_TEST_ASSERT_RETURN(rc != WH_ERROR_OK);

/*
* Second vector: addr = UINTPTR_MAX, size = 1
* endAddr = UINTPTR_MAX + 1 = 0 (wraps to zero)
*/
WH_TEST_PRINT(" Testing boundary wrap addr=UINTPTR_MAX size=1...\n");
rc = wh_Dma_CheckMemOperAgainstAllowList(
&allowList, WH_DMA_OPER_CLIENT_READ_PRE,
(void*)UINTPTR_MAX, 1);
WH_TEST_ASSERT_RETURN(rc != WH_ERROR_OK);

/*
* Third vector: size = UINTPTR_MAX with a non-zero start address.
* addr = 1, size = UINTPTR_MAX
* endAddr = 1 + UINTPTR_MAX = 0 (wraps to zero)
*/
WH_TEST_PRINT(" Testing maximum size overflow addr=1 "
"size=UINTPTR_MAX...\n");
rc = wh_Dma_CheckMemOperAgainstAllowList(
&allowList, WH_DMA_OPER_CLIENT_READ_PRE,
(void*)((uintptr_t)1), (size_t)UINTPTR_MAX);
WH_TEST_ASSERT_RETURN(rc != WH_ERROR_OK);

/* Also test the write list path */
memset(&allowList, 0, sizeof(allowList));
allowList.writeList[0].addr = (void*)((uintptr_t)0x10000);
allowList.writeList[0].size = 0x10000;

WH_TEST_PRINT(" Testing write-path overflow...\n");
rc = wh_Dma_CheckMemOperAgainstAllowList(
&allowList, WH_DMA_OPER_CLIENT_WRITE_PRE,
(void*)maliciousAddr, maliciousSize);
WH_TEST_ASSERT_RETURN(rc != WH_ERROR_OK);

return WH_ERROR_OK;
}

int whTest_Dma(void)
{
WH_TEST_PRINT("Testing DMA allow list checks...\n");

WH_TEST_RETURN_ON_FAIL(whTest_DmaAllowListBasic());
WH_TEST_RETURN_ON_FAIL(whTest_DmaAllowListOverflow());

WH_TEST_PRINT("DMA allow list tests PASSED\n");
return WH_ERROR_OK;
}

#else /* !WOLFHSM_CFG_DMA */

int whTest_Dma(void)
{
return 0;
}

#endif /* WOLFHSM_CFG_DMA */
29 changes: 29 additions & 0 deletions test/wh_test_dma.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2026 wolfSSL Inc.
*
* This file is part of wolfHSM.
*
* wolfHSM is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfHSM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with wolfHSM. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* test/wh_test_dma.h
*
* DMA allow list boundary check tests
*/
#ifndef TEST_WH_TEST_DMA_H_
#define TEST_WH_TEST_DMA_H_

int whTest_Dma(void);

#endif /* TEST_WH_TEST_DMA_H_ */
Loading