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