]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg/VirtioFsDxe: handle the volume label in EFI_FILE_PROTOCOL.SetInfo
authorLaszlo Ersek <lersek@redhat.com>
Wed, 16 Dec 2020 21:11:17 +0000 (22:11 +0100)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Mon, 21 Dec 2020 17:16:23 +0000 (17:16 +0000)
The least complicated third of EFI_FILE_PROTOCOL.SetInfo() is to handle
the EFI_FILE_SYSTEM_INFO and EFI_FILE_SYSTEM_VOLUME_LABEL setting
requests. Both of those can only change the volume label -- which the
Virtio Filesystem device does not support.

Verify the input for well-formedness, and report success only if the
volume label is being set to its current value.

Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3097
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Message-Id: <20201216211125.19496-41-lersek@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
OvmfPkg/VirtioFsDxe/SimpleFsSetInfo.c

index 200b7a1bcd20a38856830db601ede8138c355a16..895b5c029a9e057dd0dbe6cbc78a880b9730c254 100644 (file)
@@ -6,8 +6,220 @@
   SPDX-License-Identifier: BSD-2-Clause-Patent\r
 **/\r
 \r
+#include <Guid/FileSystemInfo.h>            // gEfiFileSystemInfoGuid\r
+#include <Guid/FileSystemVolumeLabelInfo.h> // gEfiFileSystemVolumeLabelInfo...\r
+#include <Library/BaseLib.h>                // StrCmp()\r
+#include <Library/BaseMemoryLib.h>          // CompareGuid()\r
+\r
 #include "VirtioFsDxe.h"\r
 \r
+/**\r
+  Validate a buffer that the EFI_FILE_PROTOCOL.SetInfo() caller passes in for a\r
+  particular InformationType GUID.\r
+\r
+  The structure to be validated is supposed to end with a variable-length,\r
+  NUL-terminated CHAR16 Name string.\r
+\r
+  @param[in] SizeByProtocolCaller  The BufferSize parameter as provided by the\r
+                                   EFI_FILE_PROTOCOL.SetInfo() caller.\r
+\r
+  @param[in] MinimumStructSize     The minimum structure size that is required\r
+                                   for the given InformationType GUID,\r
+                                   including a single CHAR16 element from the\r
+                                   trailing Name field.\r
+\r
+  @param[in] IsSizeByInfoPresent   TRUE if and only if the expected structure\r
+                                   starts with a UINT64 Size field that reports\r
+                                   the actual structure size.\r
+\r
+  @param[in] Buffer                The Buffer parameter as provided by the\r
+                                   EFI_FILE_PROTOCOL.SetInfo() caller.\r
+\r
+  @retval EFI_SUCCESS            Validation successful, Buffer is well-formed.\r
+\r
+  @retval EFI_BAD_BUFFER_SIZE    The EFI_FILE_PROTOCOL.SetInfo()\r
+                                 caller provided a BufferSize that is smaller\r
+                                 than the minimum structure size required for\r
+                                 the given InformationType GUID.\r
+\r
+  @retval EFI_INVALID_PARAMETER  IsSizeByInfoPresent is TRUE, and the leading\r
+                                 UINT64 Size field does not match the\r
+                                 EFI_FILE_PROTOCOL.SetInfo() caller-provided\r
+                                 BufferSize.\r
+\r
+  @retval EFI_INVALID_PARAMETER  The trailing Name field does not consist of a\r
+                                 whole multiple of CHAR16 elements.\r
+\r
+  @retval EFI_INVALID_PARAMETER  The trailing Name field is not NUL-terminated.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+ValidateInfoStructure (\r
+  IN UINTN   SizeByProtocolCaller,\r
+  IN UINTN   MinimumStructSize,\r
+  IN BOOLEAN IsSizeByInfoPresent,\r
+  IN VOID    *Buffer\r
+  )\r
+{\r
+  UINTN  NameFieldByteOffset;\r
+  UINTN  NameFieldBytes;\r
+  UINTN  NameFieldChar16s;\r
+  CHAR16 *NameField;\r
+\r
+  //\r
+  // Make sure the internal function asking for validation passes in sane\r
+  // values.\r
+  //\r
+  ASSERT (MinimumStructSize >= sizeof (CHAR16));\r
+  NameFieldByteOffset = MinimumStructSize - sizeof (CHAR16);\r
+\r
+  if (IsSizeByInfoPresent) {\r
+    ASSERT (MinimumStructSize >= sizeof (UINT64) + sizeof (CHAR16));\r
+    ASSERT (NameFieldByteOffset >= sizeof (UINT64));\r
+  }\r
+\r
+  //\r
+  // Check whether the protocol caller provided enough bytes for the minimum\r
+  // size of this info structure.\r
+  //\r
+  if (SizeByProtocolCaller < MinimumStructSize) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  //\r
+  // If the info structure starts with a UINT64 Size field, check if that\r
+  // agrees with the protocol caller-provided size.\r
+  //\r
+  if (IsSizeByInfoPresent) {\r
+    UINT64 *SizeByInfo;\r
+\r
+    SizeByInfo = Buffer;\r
+    if (*SizeByInfo != SizeByProtocolCaller) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
+  //\r
+  // The CHAR16 Name field at the end of the structure must have an even number\r
+  // of bytes.\r
+  //\r
+  // The subtraction below cannot underflow, and yields at least\r
+  // sizeof(CHAR16).\r
+  //\r
+  ASSERT (SizeByProtocolCaller >= NameFieldByteOffset);\r
+  NameFieldBytes = SizeByProtocolCaller - NameFieldByteOffset;\r
+  ASSERT (NameFieldBytes >= sizeof (CHAR16));\r
+  if (NameFieldBytes % sizeof (CHAR16) != 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // The CHAR16 Name field at the end of the structure must be NUL-terminated.\r
+  //\r
+  NameFieldChar16s = NameFieldBytes / sizeof (CHAR16);\r
+  ASSERT (NameFieldChar16s >= 1);\r
+\r
+  NameField = (CHAR16 *)((UINT8 *)Buffer + NameFieldByteOffset);\r
+  if (NameField[NameFieldChar16s - 1] != L'\0') {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Process an EFI_FILE_SYSTEM_INFO setting request.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+SetFileSystemInfo (\r
+  IN EFI_FILE_PROTOCOL *This,\r
+  IN UINTN             BufferSize,\r
+  IN VOID              *Buffer\r
+  )\r
+{\r
+  VIRTIO_FS_FILE       *VirtioFsFile;\r
+  VIRTIO_FS            *VirtioFs;\r
+  EFI_STATUS           Status;\r
+  EFI_FILE_SYSTEM_INFO *FileSystemInfo;\r
+\r
+  VirtioFsFile = VIRTIO_FS_FILE_FROM_SIMPLE_FILE (This);\r
+  VirtioFs     = VirtioFsFile->OwnerFs;\r
+\r
+  //\r
+  // Validate if Buffer passes as EFI_FILE_SYSTEM_INFO.\r
+  //\r
+  Status = ValidateInfoStructure (\r
+             BufferSize,                       // SizeByProtocolCaller\r
+             OFFSET_OF (EFI_FILE_SYSTEM_INFO,\r
+               VolumeLabel) + sizeof (CHAR16), // MinimumStructSize\r
+             TRUE,                             // IsSizeByInfoPresent\r
+             Buffer\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  FileSystemInfo = Buffer;\r
+\r
+  //\r
+  // EFI_FILE_SYSTEM_INFO fields other than VolumeLabel cannot be changed, per\r
+  // spec.\r
+  //\r
+  // If the label is being changed to its current value, report success;\r
+  // otherwise, reject the request, as the Virtio Filesystem device does not\r
+  // support changing the label.\r
+  //\r
+  if (StrCmp (FileSystemInfo->VolumeLabel, VirtioFs->Label) == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  return EFI_WRITE_PROTECTED;\r
+}\r
+\r
+/**\r
+  Process an EFI_FILE_SYSTEM_VOLUME_LABEL setting request.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+SetFileSystemVolumeLabelInfo (\r
+  IN EFI_FILE_PROTOCOL *This,\r
+  IN UINTN             BufferSize,\r
+  IN VOID              *Buffer\r
+  )\r
+{\r
+  VIRTIO_FS_FILE               *VirtioFsFile;\r
+  VIRTIO_FS                    *VirtioFs;\r
+  EFI_STATUS                   Status;\r
+  EFI_FILE_SYSTEM_VOLUME_LABEL *FileSystemVolumeLabel;\r
+\r
+  VirtioFsFile = VIRTIO_FS_FILE_FROM_SIMPLE_FILE (This);\r
+  VirtioFs     = VirtioFsFile->OwnerFs;\r
+\r
+  //\r
+  // Validate if Buffer passes as EFI_FILE_SYSTEM_VOLUME_LABEL.\r
+  //\r
+  Status = ValidateInfoStructure (\r
+             BufferSize,                              // SizeByProtocolCaller\r
+             OFFSET_OF (EFI_FILE_SYSTEM_VOLUME_LABEL,\r
+               VolumeLabel) + sizeof (CHAR16),        // MinimumStructSize\r
+             FALSE,                                   // IsSizeByInfoPresent\r
+             Buffer\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  FileSystemVolumeLabel = Buffer;\r
+\r
+  //\r
+  // If the label is being changed to its current value, report success;\r
+  // otherwise, reject the request, as the Virtio Filesystem device does not\r
+  // support changing the label.\r
+  //\r
+  if (StrCmp (FileSystemVolumeLabel->VolumeLabel, VirtioFs->Label) == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  return EFI_WRITE_PROTECTED;\r
+}\r
+\r
 EFI_STATUS\r
 EFIAPI\r
 VirtioFsSimpleFileSetInfo (\r
@@ -17,5 +229,17 @@ VirtioFsSimpleFileSetInfo (
   IN VOID              *Buffer\r
   )\r
 {\r
-  return EFI_NO_MEDIA;\r
+  if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {\r
+    return SetFileSystemInfo (This, BufferSize, Buffer);\r
+  }\r
+\r
+  if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {\r
+    return SetFileSystemVolumeLabelInfo (This, BufferSize, Buffer);\r
+  }\r
+\r
+  return EFI_UNSUPPORTED;\r
 }\r