]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskBlockIo.c
MdeModulePkg/RamDiskDxe: Restrict on RAM disk size (CVE-2018-12180)
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / RamDiskDxe / RamDiskBlockIo.c
CommitLineData
20752cb8
HW
1/** @file\r
2 Produce EFI_BLOCK_IO_PROTOCOL on a RAM disk device.\r
3\r
38c9fbdc 4 Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>\r
20752cb8
HW
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "RamDiskImpl.h"\r
16\r
17//\r
18// The EFI_BLOCK_IO_PROTOCOL instances that is installed onto the handle\r
19// for newly registered RAM disks\r
20//\r
21EFI_BLOCK_IO_PROTOCOL mRamDiskBlockIoTemplate = {\r
22 EFI_BLOCK_IO_PROTOCOL_REVISION,\r
23 (EFI_BLOCK_IO_MEDIA *) 0,\r
24 RamDiskBlkIoReset,\r
25 RamDiskBlkIoReadBlocks,\r
26 RamDiskBlkIoWriteBlocks,\r
27 RamDiskBlkIoFlushBlocks\r
28};\r
29\r
216fefa3
HW
30//\r
31// The EFI_BLOCK_IO_PROTOCOL2 instances that is installed onto the handle\r
32// for newly registered RAM disks\r
33//\r
34EFI_BLOCK_IO2_PROTOCOL mRamDiskBlockIo2Template = {\r
35 (EFI_BLOCK_IO_MEDIA *) 0,\r
36 RamDiskBlkIo2Reset,\r
37 RamDiskBlkIo2ReadBlocksEx,\r
38 RamDiskBlkIo2WriteBlocksEx,\r
39 RamDiskBlkIo2FlushBlocksEx\r
40};\r
41\r
20752cb8
HW
42\r
43/**\r
216fefa3 44 Initialize the BlockIO & BlockIO2 protocol of a RAM disk device.\r
20752cb8
HW
45\r
46 @param[in] PrivateData Points to RAM disk private data.\r
47\r
48**/\r
49VOID\r
50RamDiskInitBlockIo (\r
51 IN RAM_DISK_PRIVATE_DATA *PrivateData\r
52 )\r
53{\r
54 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
216fefa3 55 EFI_BLOCK_IO2_PROTOCOL *BlockIo2;\r
20752cb8 56 EFI_BLOCK_IO_MEDIA *Media;\r
38c9fbdc 57 UINT32 Remainder;\r
20752cb8 58\r
216fefa3
HW
59 BlockIo = &PrivateData->BlockIo;\r
60 BlockIo2 = &PrivateData->BlockIo2;\r
61 Media = &PrivateData->Media;\r
20752cb8
HW
62\r
63 CopyMem (BlockIo, &mRamDiskBlockIoTemplate, sizeof (EFI_BLOCK_IO_PROTOCOL));\r
216fefa3 64 CopyMem (BlockIo2, &mRamDiskBlockIo2Template, sizeof (EFI_BLOCK_IO2_PROTOCOL));\r
20752cb8
HW
65\r
66 BlockIo->Media = Media;\r
216fefa3 67 BlockIo2->Media = Media;\r
20752cb8
HW
68 Media->RemovableMedia = FALSE;\r
69 Media->MediaPresent = TRUE;\r
70 Media->LogicalPartition = FALSE;\r
71 Media->ReadOnly = FALSE;\r
72 Media->WriteCaching = FALSE;\r
38c9fbdc
HW
73\r
74 for (Media->BlockSize = RAM_DISK_DEFAULT_BLOCK_SIZE;\r
75 Media->BlockSize >= 1;\r
76 Media->BlockSize = Media->BlockSize >> 1) {\r
77 Media->LastBlock = DivU64x32Remainder (PrivateData->Size, Media->BlockSize, &Remainder) - 1;\r
78 if (Remainder == 0) {\r
79 break;\r
80 }\r
81 }\r
82 ASSERT (Media->BlockSize != 0);\r
83\r
84 return;\r
20752cb8
HW
85}\r
86\r
87\r
88/**\r
89 Reset the Block Device.\r
90\r
91 @param This Indicates a pointer to the calling context.\r
92 @param ExtendedVerification Driver may perform diagnostics on reset.\r
93\r
94 @retval EFI_SUCCESS The device was reset.\r
95 @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
96 not be reset.\r
97\r
98**/\r
99EFI_STATUS\r
100EFIAPI\r
101RamDiskBlkIoReset (\r
102 IN EFI_BLOCK_IO_PROTOCOL *This,\r
103 IN BOOLEAN ExtendedVerification\r
104 )\r
105{\r
106 return EFI_SUCCESS;\r
107}\r
108\r
109\r
110/**\r
111 Read BufferSize bytes from Lba into Buffer.\r
112\r
113 @param[in] This Indicates a pointer to the calling context.\r
114 @param[in] MediaId Id of the media, changes every time the media is\r
115 replaced.\r
116 @param[in] Lba The starting Logical Block Address to read from.\r
117 @param[in] BufferSize Size of Buffer, must be a multiple of device block\r
118 size.\r
119 @param[out] Buffer A pointer to the destination buffer for the data.\r
120 The caller is responsible for either having\r
121 implicit or explicit ownership of the buffer.\r
122\r
123 @retval EFI_SUCCESS The data was read correctly from the device.\r
124 @retval EFI_DEVICE_ERROR The device reported an error while performing\r
125 the read.\r
126 @retval EFI_NO_MEDIA There is no media in the device.\r
127 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current\r
128 device.\r
129 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block\r
130 size of the device.\r
131 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not\r
132 valid, or the buffer is not on proper alignment.\r
133\r
134**/\r
135EFI_STATUS\r
136EFIAPI\r
137RamDiskBlkIoReadBlocks (\r
138 IN EFI_BLOCK_IO_PROTOCOL *This,\r
139 IN UINT32 MediaId,\r
140 IN EFI_LBA Lba,\r
141 IN UINTN BufferSize,\r
142 OUT VOID *Buffer\r
143 )\r
144{\r
145 RAM_DISK_PRIVATE_DATA *PrivateData;\r
146 UINTN NumberOfBlocks;\r
147\r
0feca62c
HW
148 PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO (This);\r
149\r
150 if (MediaId != PrivateData->Media.MediaId) {\r
151 return EFI_MEDIA_CHANGED;\r
152 }\r
153\r
20752cb8
HW
154 if (Buffer == NULL) {\r
155 return EFI_INVALID_PARAMETER;\r
156 }\r
157\r
158 if (BufferSize == 0) {\r
159 return EFI_SUCCESS;\r
160 }\r
161\r
20752cb8
HW
162 if ((BufferSize % PrivateData->Media.BlockSize) != 0) {\r
163 return EFI_BAD_BUFFER_SIZE;\r
164 }\r
165\r
166 if (Lba > PrivateData->Media.LastBlock) {\r
167 return EFI_INVALID_PARAMETER;\r
168 }\r
169\r
170 NumberOfBlocks = BufferSize / PrivateData->Media.BlockSize;\r
171 if ((Lba + NumberOfBlocks - 1) > PrivateData->Media.LastBlock) {\r
172 return EFI_INVALID_PARAMETER;\r
173 }\r
174\r
175 CopyMem (\r
176 Buffer,\r
177 (VOID *)(UINTN)(PrivateData->StartingAddr + MultU64x32 (Lba, PrivateData->Media.BlockSize)),\r
178 BufferSize\r
179 );\r
180\r
181 return EFI_SUCCESS;\r
182}\r
183\r
184\r
185/**\r
186 Write BufferSize bytes from Lba into Buffer.\r
187\r
188 @param[in] This Indicates a pointer to the calling context.\r
189 @param[in] MediaId The media ID that the write request is for.\r
190 @param[in] Lba The starting logical block address to be written.\r
191 The caller is responsible for writing to only\r
192 legitimate locations.\r
193 @param[in] BufferSize Size of Buffer, must be a multiple of device block\r
194 size.\r
195 @param[in] Buffer A pointer to the source buffer for the data.\r
196\r
197 @retval EFI_SUCCESS The data was written correctly to the device.\r
198 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
199 @retval EFI_DEVICE_ERROR The device reported an error while performing\r
200 the write.\r
201 @retval EFI_NO_MEDIA There is no media in the device.\r
202 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current\r
203 device.\r
204 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block\r
205 size of the device.\r
206 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not\r
207 valid, or the buffer is not on proper alignment.\r
208\r
209**/\r
210EFI_STATUS\r
211EFIAPI\r
212RamDiskBlkIoWriteBlocks (\r
213 IN EFI_BLOCK_IO_PROTOCOL *This,\r
214 IN UINT32 MediaId,\r
215 IN EFI_LBA Lba,\r
216 IN UINTN BufferSize,\r
217 IN VOID *Buffer\r
218 )\r
219{\r
220 RAM_DISK_PRIVATE_DATA *PrivateData;\r
221 UINTN NumberOfBlocks;\r
222\r
20752cb8
HW
223 PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO (This);\r
224\r
225 if (MediaId != PrivateData->Media.MediaId) {\r
226 return EFI_MEDIA_CHANGED;\r
227 }\r
228\r
229 if (TRUE == PrivateData->Media.ReadOnly) {\r
230 return EFI_WRITE_PROTECTED;\r
231 }\r
232\r
0feca62c
HW
233 if (Buffer == NULL) {\r
234 return EFI_INVALID_PARAMETER;\r
235 }\r
236\r
237 if (BufferSize == 0) {\r
238 return EFI_SUCCESS;\r
239 }\r
240\r
20752cb8
HW
241 if ((BufferSize % PrivateData->Media.BlockSize) != 0) {\r
242 return EFI_BAD_BUFFER_SIZE;\r
243 }\r
244\r
245 if (Lba > PrivateData->Media.LastBlock) {\r
246 return EFI_INVALID_PARAMETER;\r
247 }\r
248\r
249 NumberOfBlocks = BufferSize / PrivateData->Media.BlockSize;\r
250 if ((Lba + NumberOfBlocks - 1) > PrivateData->Media.LastBlock) {\r
251 return EFI_INVALID_PARAMETER;\r
252 }\r
253\r
254 CopyMem (\r
255 (VOID *)(UINTN)(PrivateData->StartingAddr + MultU64x32 (Lba, PrivateData->Media.BlockSize)),\r
256 Buffer,\r
257 BufferSize\r
258 );\r
259\r
260 return EFI_SUCCESS;\r
261}\r
262\r
263\r
264/**\r
265 Flush the Block Device.\r
266\r
267 @param[in] This Indicates a pointer to the calling context.\r
268\r
269 @retval EFI_SUCCESS All outstanding data was written to the device.\r
270 @retval EFI_DEVICE_ERROR The device reported an error while writting\r
271 back the data\r
272 @retval EFI_NO_MEDIA There is no media in the device.\r
273\r
274**/\r
275EFI_STATUS\r
276EFIAPI\r
277RamDiskBlkIoFlushBlocks (\r
278 IN EFI_BLOCK_IO_PROTOCOL *This\r
279 )\r
280{\r
281 return EFI_SUCCESS;\r
282}\r
216fefa3
HW
283\r
284\r
285/**\r
286 Resets the block device hardware.\r
287\r
288 @param[in] This The pointer of EFI_BLOCK_IO2_PROTOCOL.\r
289 @param[in] ExtendedVerification The flag about if extend verificate.\r
290\r
291 @retval EFI_SUCCESS The device was reset.\r
292 @retval EFI_DEVICE_ERROR The block device is not functioning correctly\r
293 and could not be reset.\r
294\r
295**/\r
296EFI_STATUS\r
297EFIAPI\r
298RamDiskBlkIo2Reset (\r
299 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
300 IN BOOLEAN ExtendedVerification\r
301 )\r
302{\r
303 return EFI_SUCCESS;\r
304}\r
305\r
306\r
307/**\r
308 Reads the requested number of blocks from the device.\r
309\r
310 @param[in] This Indicates a pointer to the calling context.\r
311 @param[in] MediaId The media ID that the read request is for.\r
312 @param[in] Lba The starting logical block address to read\r
313 from on the device.\r
314 @param[in, out] Token A pointer to the token associated with the\r
315 transaction.\r
316 @param[in] BufferSize The size of the Buffer in bytes. This must be\r
317 a multiple of the intrinsic block size of the\r
318 device.\r
319 @param[out] Buffer A pointer to the destination buffer for the\r
320 data. The caller is responsible for either\r
321 having implicit or explicit ownership of the\r
322 buffer.\r
323\r
324 @retval EFI_SUCCESS The read request was queued if Token->Event\r
325 is not NULL. The data was read correctly from\r
326 the device if the Token->Event is NULL.\r
327 @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
328 to perform the read operation.\r
329 @retval EFI_NO_MEDIA There is no media in the device.\r
330 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
331 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
332 the intrinsic block size of the device.\r
333 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not\r
334 valid, or the buffer is not on proper\r
335 alignment.\r
336 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
337 lack of resources.\r
338\r
339**/\r
340EFI_STATUS\r
341EFIAPI\r
342RamDiskBlkIo2ReadBlocksEx (\r
343 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
344 IN UINT32 MediaId,\r
345 IN EFI_LBA Lba,\r
346 IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
347 IN UINTN BufferSize,\r
348 OUT VOID *Buffer\r
349 )\r
350{\r
351 RAM_DISK_PRIVATE_DATA *PrivateData;\r
352 EFI_STATUS Status;\r
353\r
354 PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO2 (This);\r
355\r
356 Status = RamDiskBlkIoReadBlocks (\r
357 &PrivateData->BlockIo,\r
358 MediaId,\r
359 Lba,\r
360 BufferSize,\r
361 Buffer\r
362 );\r
363 if (EFI_ERROR (Status)) {\r
364 return Status;\r
365 }\r
366\r
367 //\r
368 // If caller's event is given, signal it after the memory read completes.\r
369 //\r
370 if ((Token != NULL) && (Token->Event != NULL)) {\r
371 Token->TransactionStatus = EFI_SUCCESS;\r
372 gBS->SignalEvent (Token->Event);\r
373 }\r
374\r
375 return EFI_SUCCESS;\r
376}\r
377\r
378\r
379/**\r
380 Writes a specified number of blocks to the device.\r
381\r
382 @param[in] This Indicates a pointer to the calling context.\r
383 @param[in] MediaId The media ID that the write request is for.\r
384 @param[in] Lba The starting logical block address to be\r
385 written. The caller is responsible for\r
386 writing to only legitimate locations.\r
387 @param[in, out] Token A pointer to the token associated with the\r
388 transaction.\r
389 @param[in] BufferSize The size in bytes of Buffer. This must be a\r
390 multiple of the intrinsic block size of the\r
391 device.\r
392 @param[in] Buffer A pointer to the source buffer for the data.\r
393\r
394 @retval EFI_SUCCESS The write request was queued if Event is not\r
395 NULL. The data was written correctly to the\r
396 device if the Event is NULL.\r
397 @retval EFI_WRITE_PROTECTED The device cannot be written to.\r
398 @retval EFI_NO_MEDIA There is no media in the device.\r
399 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
400 @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
401 to perform the write operation.\r
402 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
403 the intrinsic block size of the device.\r
404 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not\r
405 valid, or the buffer is not on proper\r
406 alignment.\r
407 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
408 lack of resources.\r
409\r
410**/\r
411EFI_STATUS\r
412EFIAPI\r
413RamDiskBlkIo2WriteBlocksEx (\r
414 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
415 IN UINT32 MediaId,\r
416 IN EFI_LBA Lba,\r
417 IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
418 IN UINTN BufferSize,\r
419 IN VOID *Buffer\r
420 )\r
421{\r
422 RAM_DISK_PRIVATE_DATA *PrivateData;\r
423 EFI_STATUS Status;\r
424\r
425 PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO2 (This);\r
426\r
427 Status = RamDiskBlkIoWriteBlocks (\r
428 &PrivateData->BlockIo,\r
429 MediaId,\r
430 Lba,\r
431 BufferSize,\r
432 Buffer\r
433 );\r
434 if (EFI_ERROR (Status)) {\r
435 return Status;\r
436 }\r
437\r
438 //\r
439 // If caller's event is given, signal it after the memory write completes.\r
440 //\r
441 if ((Token != NULL) && (Token->Event != NULL)) {\r
442 Token->TransactionStatus = EFI_SUCCESS;\r
443 gBS->SignalEvent (Token->Event);\r
444 }\r
445\r
446 return EFI_SUCCESS;\r
447}\r
448\r
449\r
450/**\r
451 Flushes all modified data to a physical block device.\r
452\r
453 @param[in] This Indicates a pointer to the calling context.\r
454 @param[in, out] Token A pointer to the token associated with the\r
455 transaction.\r
456\r
457 @retval EFI_SUCCESS The flush request was queued if Event is not\r
458 NULL. All outstanding data was written\r
459 correctly to the device if the Event is NULL.\r
460 @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
461 to write data.\r
462 @retval EFI_WRITE_PROTECTED The device cannot be written to.\r
463 @retval EFI_NO_MEDIA There is no media in the device.\r
464 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
465 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
466 lack of resources.\r
467\r
468**/\r
469EFI_STATUS\r
470EFIAPI\r
471RamDiskBlkIo2FlushBlocksEx (\r
472 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
473 IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
474 )\r
475{\r
476 RAM_DISK_PRIVATE_DATA *PrivateData;\r
477\r
478 PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO2 (This);\r
479\r
480 if (TRUE == PrivateData->Media.ReadOnly) {\r
481 return EFI_WRITE_PROTECTED;\r
482 }\r
483\r
484 //\r
485 // If caller's event is given, signal it directly.\r
486 //\r
487 if ((Token != NULL) && (Token->Event != NULL)) {\r
488 Token->TransactionStatus = EFI_SUCCESS;\r
489 gBS->SignalEvent (Token->Event);\r
490 }\r
491\r
492 return EFI_SUCCESS;\r
493}\r