audk/OvmfPkg/VirtioFsDxe/SimpleFsSetInfo.c

246 lines
7.7 KiB
C
Raw Normal View History

OvmfPkg/VirtioFsDxe: implement EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume() With the help of the VirtioFsFuseOpenDir() and VirtioFsFuseReleaseFileOrDir() functions introduced previously, we can now open and close the root directory. So let's implement EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume(). OpenVolume() creates a new EFI_FILE_PROTOCOL object -- a reference to the root directory of the filesystem. Thus, we have to start tracking references to EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, lest we unbind the virtio-fs device while files are open. There are two methods that release an EFI_FILE_PROTOCOL object: the Close() and the Delete() member functions. In particular, they are not allowed to fail with regard to resource management -- they must release resources unconditionally. Thus, for rolling back the resource accounting that we do in EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume(), we have to implement the first versions of EFI_FILE_PROTOCOL.Close() and EFI_FILE_PROTOCOL.Delete() in this patch as well. With this patch applied, the UEFI shell can enter the root directory of the Virtio Filesystem (such as with the "FS3:" shell command), and the "DIR" shell command exercises FUSE_OPENDIR and FUSE_RELEASEDIR, according to the virtiofsd log. The "DIR" command reports the root directory as if it were empty; probably because at this time, we only allow the shell to open and to close the root directory, but not to read it. 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-12-lersek@redhat.com> Acked-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
2020-12-16 22:10:48 +01:00
/** @file
EFI_FILE_PROTOCOL.SetInfo() member function for the Virtio Filesystem driver.
Copyright (C) 2020, Red Hat, Inc.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Guid/FileSystemInfo.h> // gEfiFileSystemInfoGuid
#include <Guid/FileSystemVolumeLabelInfo.h> // gEfiFileSystemVolumeLabelInfo...
#include <Library/BaseLib.h> // StrCmp()
#include <Library/BaseMemoryLib.h> // CompareGuid()
OvmfPkg/VirtioFsDxe: implement EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume() With the help of the VirtioFsFuseOpenDir() and VirtioFsFuseReleaseFileOrDir() functions introduced previously, we can now open and close the root directory. So let's implement EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume(). OpenVolume() creates a new EFI_FILE_PROTOCOL object -- a reference to the root directory of the filesystem. Thus, we have to start tracking references to EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, lest we unbind the virtio-fs device while files are open. There are two methods that release an EFI_FILE_PROTOCOL object: the Close() and the Delete() member functions. In particular, they are not allowed to fail with regard to resource management -- they must release resources unconditionally. Thus, for rolling back the resource accounting that we do in EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume(), we have to implement the first versions of EFI_FILE_PROTOCOL.Close() and EFI_FILE_PROTOCOL.Delete() in this patch as well. With this patch applied, the UEFI shell can enter the root directory of the Virtio Filesystem (such as with the "FS3:" shell command), and the "DIR" shell command exercises FUSE_OPENDIR and FUSE_RELEASEDIR, according to the virtiofsd log. The "DIR" command reports the root directory as if it were empty; probably because at this time, we only allow the shell to open and to close the root directory, but not to read it. 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-12-lersek@redhat.com> Acked-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
2020-12-16 22:10:48 +01:00
#include "VirtioFsDxe.h"
/**
Validate a buffer that the EFI_FILE_PROTOCOL.SetInfo() caller passes in for a
particular InformationType GUID.
The structure to be validated is supposed to end with a variable-length,
NUL-terminated CHAR16 Name string.
@param[in] SizeByProtocolCaller The BufferSize parameter as provided by the
EFI_FILE_PROTOCOL.SetInfo() caller.
@param[in] MinimumStructSize The minimum structure size that is required
for the given InformationType GUID,
including a single CHAR16 element from the
trailing Name field.
@param[in] IsSizeByInfoPresent TRUE if and only if the expected structure
starts with a UINT64 Size field that reports
the actual structure size.
@param[in] Buffer The Buffer parameter as provided by the
EFI_FILE_PROTOCOL.SetInfo() caller.
@retval EFI_SUCCESS Validation successful, Buffer is well-formed.
@retval EFI_BAD_BUFFER_SIZE The EFI_FILE_PROTOCOL.SetInfo()
caller provided a BufferSize that is smaller
than the minimum structure size required for
the given InformationType GUID.
@retval EFI_INVALID_PARAMETER IsSizeByInfoPresent is TRUE, and the leading
UINT64 Size field does not match the
EFI_FILE_PROTOCOL.SetInfo() caller-provided
BufferSize.
@retval EFI_INVALID_PARAMETER The trailing Name field does not consist of a
whole multiple of CHAR16 elements.
@retval EFI_INVALID_PARAMETER The trailing Name field is not NUL-terminated.
**/
STATIC
EFI_STATUS
ValidateInfoStructure (
IN UINTN SizeByProtocolCaller,
IN UINTN MinimumStructSize,
IN BOOLEAN IsSizeByInfoPresent,
IN VOID *Buffer
)
{
UINTN NameFieldByteOffset;
UINTN NameFieldBytes;
UINTN NameFieldChar16s;
CHAR16 *NameField;
//
// Make sure the internal function asking for validation passes in sane
// values.
//
ASSERT (MinimumStructSize >= sizeof (CHAR16));
NameFieldByteOffset = MinimumStructSize - sizeof (CHAR16);
if (IsSizeByInfoPresent) {
ASSERT (MinimumStructSize >= sizeof (UINT64) + sizeof (CHAR16));
ASSERT (NameFieldByteOffset >= sizeof (UINT64));
}
//
// Check whether the protocol caller provided enough bytes for the minimum
// size of this info structure.
//
if (SizeByProtocolCaller < MinimumStructSize) {
return EFI_BAD_BUFFER_SIZE;
}
//
// If the info structure starts with a UINT64 Size field, check if that
// agrees with the protocol caller-provided size.
//
if (IsSizeByInfoPresent) {
UINT64 *SizeByInfo;
SizeByInfo = Buffer;
if (*SizeByInfo != SizeByProtocolCaller) {
return EFI_INVALID_PARAMETER;
}
}
//
// The CHAR16 Name field at the end of the structure must have an even number
// of bytes.
//
// The subtraction below cannot underflow, and yields at least
// sizeof(CHAR16).
//
ASSERT (SizeByProtocolCaller >= NameFieldByteOffset);
NameFieldBytes = SizeByProtocolCaller - NameFieldByteOffset;
ASSERT (NameFieldBytes >= sizeof (CHAR16));
if (NameFieldBytes % sizeof (CHAR16) != 0) {
return EFI_INVALID_PARAMETER;
}
//
// The CHAR16 Name field at the end of the structure must be NUL-terminated.
//
NameFieldChar16s = NameFieldBytes / sizeof (CHAR16);
ASSERT (NameFieldChar16s >= 1);
NameField = (CHAR16 *)((UINT8 *)Buffer + NameFieldByteOffset);
if (NameField[NameFieldChar16s - 1] != L'\0') {
return EFI_INVALID_PARAMETER;
}
return EFI_SUCCESS;
}
/**
Process an EFI_FILE_SYSTEM_INFO setting request.
**/
STATIC
EFI_STATUS
SetFileSystemInfo (
IN EFI_FILE_PROTOCOL *This,
IN UINTN BufferSize,
IN VOID *Buffer
)
{
VIRTIO_FS_FILE *VirtioFsFile;
VIRTIO_FS *VirtioFs;
EFI_STATUS Status;
EFI_FILE_SYSTEM_INFO *FileSystemInfo;
VirtioFsFile = VIRTIO_FS_FILE_FROM_SIMPLE_FILE (This);
VirtioFs = VirtioFsFile->OwnerFs;
//
// Validate if Buffer passes as EFI_FILE_SYSTEM_INFO.
//
Status = ValidateInfoStructure (
BufferSize, // SizeByProtocolCaller
OFFSET_OF (EFI_FILE_SYSTEM_INFO,
VolumeLabel) + sizeof (CHAR16), // MinimumStructSize
TRUE, // IsSizeByInfoPresent
Buffer
);
if (EFI_ERROR (Status)) {
return Status;
}
FileSystemInfo = Buffer;
//
// EFI_FILE_SYSTEM_INFO fields other than VolumeLabel cannot be changed, per
// spec.
//
// If the label is being changed to its current value, report success;
// otherwise, reject the request, as the Virtio Filesystem device does not
// support changing the label.
//
if (StrCmp (FileSystemInfo->VolumeLabel, VirtioFs->Label) == 0) {
return EFI_SUCCESS;
}
return EFI_WRITE_PROTECTED;
}
/**
Process an EFI_FILE_SYSTEM_VOLUME_LABEL setting request.
**/
STATIC
EFI_STATUS
SetFileSystemVolumeLabelInfo (
IN EFI_FILE_PROTOCOL *This,
IN UINTN BufferSize,
IN VOID *Buffer
)
{
VIRTIO_FS_FILE *VirtioFsFile;
VIRTIO_FS *VirtioFs;
EFI_STATUS Status;
EFI_FILE_SYSTEM_VOLUME_LABEL *FileSystemVolumeLabel;
VirtioFsFile = VIRTIO_FS_FILE_FROM_SIMPLE_FILE (This);
VirtioFs = VirtioFsFile->OwnerFs;
//
// Validate if Buffer passes as EFI_FILE_SYSTEM_VOLUME_LABEL.
//
Status = ValidateInfoStructure (
BufferSize, // SizeByProtocolCaller
OFFSET_OF (EFI_FILE_SYSTEM_VOLUME_LABEL,
VolumeLabel) + sizeof (CHAR16), // MinimumStructSize
FALSE, // IsSizeByInfoPresent
Buffer
);
if (EFI_ERROR (Status)) {
return Status;
}
FileSystemVolumeLabel = Buffer;
//
// If the label is being changed to its current value, report success;
// otherwise, reject the request, as the Virtio Filesystem device does not
// support changing the label.
//
if (StrCmp (FileSystemVolumeLabel->VolumeLabel, VirtioFs->Label) == 0) {
return EFI_SUCCESS;
}
return EFI_WRITE_PROTECTED;
}
OvmfPkg/VirtioFsDxe: implement EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume() With the help of the VirtioFsFuseOpenDir() and VirtioFsFuseReleaseFileOrDir() functions introduced previously, we can now open and close the root directory. So let's implement EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume(). OpenVolume() creates a new EFI_FILE_PROTOCOL object -- a reference to the root directory of the filesystem. Thus, we have to start tracking references to EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, lest we unbind the virtio-fs device while files are open. There are two methods that release an EFI_FILE_PROTOCOL object: the Close() and the Delete() member functions. In particular, they are not allowed to fail with regard to resource management -- they must release resources unconditionally. Thus, for rolling back the resource accounting that we do in EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume(), we have to implement the first versions of EFI_FILE_PROTOCOL.Close() and EFI_FILE_PROTOCOL.Delete() in this patch as well. With this patch applied, the UEFI shell can enter the root directory of the Virtio Filesystem (such as with the "FS3:" shell command), and the "DIR" shell command exercises FUSE_OPENDIR and FUSE_RELEASEDIR, according to the virtiofsd log. The "DIR" command reports the root directory as if it were empty; probably because at this time, we only allow the shell to open and to close the root directory, but not to read it. 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-12-lersek@redhat.com> Acked-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
2020-12-16 22:10:48 +01:00
EFI_STATUS
EFIAPI
VirtioFsSimpleFileSetInfo (
IN EFI_FILE_PROTOCOL *This,
IN EFI_GUID *InformationType,
IN UINTN BufferSize,
IN VOID *Buffer
)
{
if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
return EFI_UNSUPPORTED;
}
if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
return SetFileSystemInfo (This, BufferSize, Buffer);
}
if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
return SetFileSystemVolumeLabelInfo (This, BufferSize, Buffer);
}
return EFI_UNSUPPORTED;
OvmfPkg/VirtioFsDxe: implement EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume() With the help of the VirtioFsFuseOpenDir() and VirtioFsFuseReleaseFileOrDir() functions introduced previously, we can now open and close the root directory. So let's implement EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume(). OpenVolume() creates a new EFI_FILE_PROTOCOL object -- a reference to the root directory of the filesystem. Thus, we have to start tracking references to EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, lest we unbind the virtio-fs device while files are open. There are two methods that release an EFI_FILE_PROTOCOL object: the Close() and the Delete() member functions. In particular, they are not allowed to fail with regard to resource management -- they must release resources unconditionally. Thus, for rolling back the resource accounting that we do in EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume(), we have to implement the first versions of EFI_FILE_PROTOCOL.Close() and EFI_FILE_PROTOCOL.Delete() in this patch as well. With this patch applied, the UEFI shell can enter the root directory of the Virtio Filesystem (such as with the "FS3:" shell command), and the "DIR" shell command exercises FUSE_OPENDIR and FUSE_RELEASEDIR, according to the virtiofsd log. The "DIR" command reports the root directory as if it were empty; probably because at this time, we only allow the shell to open and to close the root directory, but not to read it. 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-12-lersek@redhat.com> Acked-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
2020-12-16 22:10:48 +01:00
}