efi_loader: EFI_FILE_PROTOCOL.Write() check args

Check the parameters passed to Write():

* cannot write to directories (UEFI SCT 2017, 5.7.3.5.15)
* cannot write to file opened read only (UEFI SCT 2017, 5.7.3.5.16)

Add missing comments.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
This commit is contained in:
Heinrich Schuchardt 2019-09-06 21:37:21 +02:00
parent 2f760735c1
commit b0f1c728c8

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0+ // SPDX-License-Identifier: GPL-2.0+
/* /*
* EFI utils * EFI_FILE_PROTOCOL
* *
* Copyright (c) 2017 Rob Clark * Copyright (c) 2017 Rob Clark
*/ */
#include <common.h> #include <common.h>
@ -28,6 +28,7 @@ struct file_handle {
struct file_system *fs; struct file_system *fs;
loff_t offset; /* current file position/cursor */ loff_t offset; /* current file position/cursor */
int isdir; int isdir;
u64 open_mode;
/* for reading a directory: */ /* for reading a directory: */
struct fs_dir_stream *dirs; struct fs_dir_stream *dirs;
@ -161,13 +162,13 @@ static int efi_create_file(struct file_handle *fh, u64 attributes)
* @file_name: path of the file to be opened. '\', '.', or '..' may * @file_name: path of the file to be opened. '\', '.', or '..' may
* be used as modifiers. A leading backslash indicates an * be used as modifiers. A leading backslash indicates an
* absolute path. * absolute path.
* @mode: bit mask indicating the access mode (read, write, * @open_mode: bit mask indicating the access mode (read, write,
* create) * create)
* @attributes: attributes for newly created file * @attributes: attributes for newly created file
* Returns: handle to the opened file or NULL * Returns: handle to the opened file or NULL
*/ */
static struct efi_file_handle *file_open(struct file_system *fs, static struct efi_file_handle *file_open(struct file_system *fs,
struct file_handle *parent, u16 *file_name, u64 mode, struct file_handle *parent, u16 *file_name, u64 open_mode,
u64 attributes) u64 attributes)
{ {
struct file_handle *fh; struct file_handle *fh;
@ -190,6 +191,7 @@ static struct efi_file_handle *file_open(struct file_system *fs,
/* +2 is for null and '/' */ /* +2 is for null and '/' */
fh = calloc(1, sizeof(*fh) + plen + (flen * MAX_UTF8_PER_UTF16) + 2); fh = calloc(1, sizeof(*fh) + plen + (flen * MAX_UTF8_PER_UTF16) + 2);
fh->open_mode = open_mode;
fh->base = efi_file_handle_protocol; fh->base = efi_file_handle_protocol;
fh->fs = fs; fh->fs = fs;
@ -218,9 +220,11 @@ static struct efi_file_handle *file_open(struct file_system *fs,
goto error; goto error;
if (!exists) { if (!exists) {
if (!(mode & EFI_FILE_MODE_CREATE) || if (!(open_mode & EFI_FILE_MODE_CREATE) ||
efi_create_file(fh, attributes)) efi_create_file(fh, attributes))
goto error; goto error;
if (set_blk_dev(fh))
goto error;
} }
/* figure out if file is a directory: */ /* figure out if file is a directory: */
@ -434,6 +438,19 @@ error:
return EFI_EXIT(ret); return EFI_EXIT(ret);
} }
/**
* efi_file_write() - write to file
*
* This function implements the Write() service of the EFI_FILE_PROTOCOL.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
*
* @file: file handle
* @buffer_size: number of bytes to write
* @buffer: buffer with the bytes to write
* Return: status code
*/
static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file, static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file,
efi_uintn_t *buffer_size, efi_uintn_t *buffer_size,
void *buffer) void *buffer)
@ -444,21 +461,35 @@ static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file,
EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer); EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer);
if (set_blk_dev(fh)) { if (!file || !buffer_size || !buffer) {
ret = EFI_DEVICE_ERROR; ret = EFI_INVALID_PARAMETER;
goto error; goto out;
}
if (fh->isdir) {
ret = EFI_UNSUPPORTED;
goto out;
}
if (!(fh->open_mode & EFI_FILE_MODE_WRITE)) {
ret = EFI_ACCESS_DENIED;
goto out;
} }
if (!*buffer_size)
goto out;
if (set_blk_dev(fh)) {
ret = EFI_DEVICE_ERROR;
goto out;
}
if (fs_write(fh->path, map_to_sysmem(buffer), fh->offset, *buffer_size, if (fs_write(fh->path, map_to_sysmem(buffer), fh->offset, *buffer_size,
&actwrite)) { &actwrite)) {
ret = EFI_DEVICE_ERROR; ret = EFI_DEVICE_ERROR;
goto error; goto out;
} }
*buffer_size = actwrite; *buffer_size = actwrite;
fh->offset += actwrite; fh->offset += actwrite;
error: out:
return EFI_EXIT(ret); return EFI_EXIT(ret);
} }