VirtualBox

source: vbox/trunk/src/VBox/Devices/testcase/tstDeviceIoFuzz.cpp

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.8 KB
Line 
1/* $Id: tstDeviceIoFuzz.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * tstDeviceSsmFuzz - I/O fuzzing testcase.
4 */
5
6/*
7 * Copyright (C) 2021-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_DEFAULT /** @todo */
33#include <VBox/types.h>
34#include <iprt/errcore.h>
35#include <iprt/mem.h>
36#include <iprt/fuzz.h>
37#include <iprt/time.h>
38#include <iprt/rand.h>
39#include <iprt/string.h>
40#include <iprt/stream.h>
41
42#include "tstDeviceBuiltin.h"
43#include "tstDeviceCfg.h"
44#include "tstDeviceInternal.h"
45
46
47/*********************************************************************************************************************************
48* Defined Constants And Macros *
49*********************************************************************************************************************************/
50
51
52/*********************************************************************************************************************************
53* Structures and Typedefs *
54*********************************************************************************************************************************/
55
56
57static const uint32_t g_aAccWidths[] = { 1, 2, 4, 8 };
58
59static PCTSTDEVCFGITEM tstDevSsmFuzzGetCfgItem(PCTSTDEVCFGITEM paCfg, uint32_t cCfgItems, const char *pszName)
60{
61 for (uint32_t i = 0; i < cCfgItems; i++)
62 {
63 if (!RTStrCmp(paCfg[i].pszKey, pszName))
64 return &paCfg[i];
65 }
66
67 return NULL;
68}
69
70
71static uint64_t tstDevSsmFuzzGetCfgU64(PCTSTDEVCFGITEM paCfg, uint32_t cCfgItems, const char *pszName)
72{
73 PCTSTDEVCFGITEM pCfgItem = tstDevSsmFuzzGetCfgItem(paCfg, cCfgItems, pszName);
74 if ( pCfgItem
75 && pCfgItem->enmType == TSTDEVCFGITEMTYPE_INTEGER)
76 return (uint64_t)pCfgItem->u.i64;
77
78 return 0;
79}
80
81
82/**
83 * Entry point for the SSM fuzzer.
84 *
85 * @returns VBox status code.
86 * @param hDut The device under test.
87 * @param paCfg The testcase config.
88 * @param cCfgItems Number of config items.
89 */
90static DECLCALLBACK(int) tstDevIoFuzzEntry(TSTDEVDUT hDut, PCTSTDEVCFGITEM paCfg, uint32_t cCfgItems)
91{
92 /* Determine the amount of I/O port handlers. */
93 uint32_t cIoPortRegs = 0;
94 PRTDEVDUTIOPORT pIoPort;
95 RTListForEach(&hDut->LstIoPorts, pIoPort, RTDEVDUTIOPORT, NdIoPorts)
96 {
97 cIoPortRegs++;
98 }
99
100 /* Determine the amount of MMIO regions. */
101 uint32_t cMmioRegions = 0;
102 PRTDEVDUTMMIO pMmio;
103 RTListForEach(&hDut->LstMmio, pMmio, RTDEVDUTMMIO, NdMmio)
104 {
105 cMmioRegions++;
106 }
107
108 RTRAND hRnd;
109 int rc = RTRandAdvCreateParkMiller(&hRnd);
110 if (RT_SUCCESS(rc))
111 {
112 RTRandAdvSeed(hRnd, 0x123456789);
113 uint64_t cRuntimeMs = tstDevSsmFuzzGetCfgU64(paCfg, cCfgItems, "RuntimeSec") * RT_MS_1SEC_64;
114 uint64_t tsStart = RTTimeMilliTS();
115 uint64_t cFuzzedInputs = 0;
116 RTCritSectEnter(&hDut->pDevIns->pCritSectRoR3->s.CritSect);
117 do
118 {
119 bool fMmio = false;
120
121 if ( cMmioRegions
122 && !cIoPortRegs)
123 fMmio = true;
124 else if ( !cMmioRegions
125 && cIoPortRegs)
126 fMmio = false;
127 else
128 fMmio = RT_BOOL(RTRandAdvU32Ex(hRnd, 0, 1));
129
130 if (fMmio)
131 {
132 uint32_t iMmio = RTRandAdvU32Ex(hRnd, 0, cMmioRegions - 1);
133 RTListForEach(&hDut->LstMmio, pMmio, RTDEVDUTMMIO, NdMmio)
134 {
135 if (!iMmio)
136 break;
137 iMmio--;
138 }
139
140 uint32_t uMin = pMmio->pfnWriteR3 ? 0 : 1;
141 uint32_t uMax = pMmio->pfnReadR3 ? 1 : 0;
142
143 RTGCPHYS offRegion = RTRandAdvU64Ex(hRnd, 0, pMmio->cbRegion);
144 bool fRead = RT_BOOL(uMin == uMax ? uMin : RTRandAdvU32Ex(hRnd, uMin, uMax));
145 bool fRing0 = false;
146
147 if ( ( fRead
148 && pMmio->pfnReadR0)
149 || ( !fRead
150 && pMmio->pfnWriteR0))
151 fRing0 = RT_BOOL(RTRandAdvU32Ex(hRnd, 0, 1));
152
153 uint64_t u64Value = fRead ? 0 : RTRandAdvU64(hRnd);
154 uint32_t cbValue = g_aAccWidths[RTRandAdvU32Ex(hRnd, 0, 3)];
155
156 if (fRead)
157 {
158 if (fRing0)
159 {
160 VBOXSTRICTRC rcStrict = pMmio->pfnReadR0((PPDMDEVINS)hDut->pDevInsR0, pIoPort->pvUserR0, offRegion, &u64Value, cbValue);
161 if (VBOXSTRICTRC_VAL(rcStrict) == VINF_IOM_R3_MMIO_READ)
162 {
163 AssertRelease(pMmio->pfnReadR3);
164 pMmio->pfnReadR3(hDut->pDevIns, pIoPort->pvUserR3, offRegion, &u64Value, cbValue);
165 }
166
167 }
168 else
169 pMmio->pfnReadR3(hDut->pDevIns, pMmio->pvUserR3, offRegion, &u64Value, cbValue);
170 }
171 else
172 {
173 if (fRing0)
174 {
175 VBOXSTRICTRC rcStrict = pMmio->pfnWriteR0((PPDMDEVINS)hDut->pDevInsR0, pIoPort->pvUserR0, offRegion, &u64Value, cbValue);
176 if (VBOXSTRICTRC_VAL(rcStrict) == VINF_IOM_R3_MMIO_WRITE)
177 {
178 AssertRelease(pMmio->pfnWriteR3);
179 pMmio->pfnWriteR3(hDut->pDevIns, pIoPort->pvUserR3, offRegion, &u64Value, cbValue);
180 }
181
182 }
183 else
184 pMmio->pfnWriteR3(hDut->pDevIns, pMmio->pvUserR3, offRegion, &u64Value, cbValue);
185 }
186 }
187 else
188 {
189 uint32_t iIoPort = RTRandAdvU32Ex(hRnd, 0, cIoPortRegs - 1);
190 RTListForEach(&hDut->LstIoPorts, pIoPort, RTDEVDUTIOPORT, NdIoPorts)
191 {
192 if (!iIoPort)
193 break;
194 iIoPort--;
195 }
196
197 uint32_t uMin = pIoPort->pfnOutR3 ? 0 : 1;
198 uint32_t uMax = pIoPort->pfnInR3 ? 1 : 0;
199
200 uint32_t offPort = RTRandAdvU32Ex(hRnd, 0, pIoPort->cPorts);
201 bool fRead = RT_BOOL(uMin == uMax ? uMin : RTRandAdvU32Ex(hRnd, uMin, uMax));
202 bool fRing0 = false;
203
204 if ( ( fRead
205 && pIoPort->pfnInR0)
206 || ( !fRead
207 && pIoPort->pfnOutR3))
208 fRing0 = RT_BOOL(RTRandAdvU32Ex(hRnd, 0, 1));
209
210 uint32_t u32Value = fRead ? 0 : RTRandAdvU32(hRnd);
211 uint32_t cbValue = g_aAccWidths[RTRandAdvU32Ex(hRnd, 0, 2)];
212
213 if (fRead)
214 {
215 if (fRing0)
216 {
217 VBOXSTRICTRC rcStrict = pIoPort->pfnInR0((PPDMDEVINS)hDut->pDevInsR0, pIoPort->pvUserR0, offPort, &u32Value, cbValue);
218 if (VBOXSTRICTRC_VAL(rcStrict) == VINF_IOM_R3_IOPORT_READ)
219 {
220 AssertRelease(pIoPort->pfnInR3);
221 pIoPort->pfnInR3(hDut->pDevIns, pIoPort->pvUserR3, offPort, &u32Value, cbValue);
222 }
223
224 }
225 else
226 pIoPort->pfnInR3(hDut->pDevIns, pIoPort->pvUserR3, offPort, &u32Value, cbValue);
227 }
228 else
229 {
230 if (fRing0)
231 {
232 VBOXSTRICTRC rcStrict = pIoPort->pfnOutR0((PPDMDEVINS)hDut->pDevInsR0, pIoPort->pvUserR0, offPort, u32Value, cbValue);
233 if (VBOXSTRICTRC_VAL(rcStrict) == VINF_IOM_R3_IOPORT_WRITE)
234 {
235 AssertRelease(pIoPort->pfnOutR3);
236 pIoPort->pfnOutR3(hDut->pDevIns, pIoPort->pvUserR3, offPort, u32Value, cbValue);
237 }
238
239 }
240 else
241 pIoPort->pfnOutR3(hDut->pDevIns, pIoPort->pvUserR3, offPort, u32Value, cbValue);
242 }
243 }
244
245 cFuzzedInputs++;
246 } while ( RT_SUCCESS(rc)
247 && RTTimeMilliTS() - tsStart < cRuntimeMs);
248 RTCritSectLeave(&hDut->pDevIns->pCritSectRoR3->s.CritSect);
249
250 RTPrintf("Fuzzed inputs: %u\n", cFuzzedInputs);
251 RTRandAdvDestroy(hRnd);
252 }
253
254 return rc;
255}
256
257
258const TSTDEVTESTCASEREG g_TestcaseIoFuzz =
259{
260 /** szName */
261 "IoFuzz",
262 /** pszDesc */
263 "Fuzzes devices I/O handlers",
264 /** fFlags */
265 0,
266 /** pfnTestEntry */
267 tstDevIoFuzzEntry
268};
269
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use