All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 0/4] fixes for EFI_FILE_PROTOCOL
@ 2019-09-07 23:59 Heinrich Schuchardt
  2019-09-07 23:59 ` [U-Boot] [PATCH 1/4] efi_loader: EFI_FILE_PROTOCOL.Write() check args Heinrich Schuchardt
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Heinrich Schuchardt @ 2019-09-07 23:59 UTC (permalink / raw)
  To: u-boot

This series fixes problems in the EFI_FILE_PROTOCOL:

* parameter checks for EFI_FILE_PROTOCOL.Write()
* correct handling of directories in EFI_FILE_PROTOCOL.READ()
* correct conversion of UTF-8 into UTF-16
* file position check in EFI_FILE_PROTOCOL.READ()

Heinrich Schuchardt (4):
  efi_loader: EFI_FILE_PROTOCOL.Write() check args
  efi_loader: eliminate inline function ascii2unicode()
  efi_loader: correct reading of directories
  efi_loader: file size checks

 include/efi_loader.h                     |  16 ---
 lib/efi_loader/efi_device_path_to_text.c |  10 +-
 lib/efi_loader/efi_file.c                | 166 ++++++++++++++---------
 3 files changed, 106 insertions(+), 86 deletions(-)

--
2.20.1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [U-Boot] [PATCH 1/4] efi_loader: EFI_FILE_PROTOCOL.Write() check args
  2019-09-07 23:59 [U-Boot] [PATCH 0/4] fixes for EFI_FILE_PROTOCOL Heinrich Schuchardt
@ 2019-09-07 23:59 ` Heinrich Schuchardt
  2019-09-07 23:59 ` [U-Boot] [PATCH 2/4] efi_loader: eliminate inline function ascii2unicode() Heinrich Schuchardt
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Heinrich Schuchardt @ 2019-09-07 23:59 UTC (permalink / raw)
  To: u-boot

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>
---
 lib/efi_loader/efi_file.c | 51 +++++++++++++++++++++++++++++++--------
 1 file changed, 41 insertions(+), 10 deletions(-)

diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c
index f4ca5694ee..a13754a558 100644
--- a/lib/efi_loader/efi_file.c
+++ b/lib/efi_loader/efi_file.c
@@ -1,8 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- *  EFI utils
+ * EFI_FILE_PROTOCOL
  *
- *  Copyright (c) 2017 Rob Clark
+ * Copyright (c) 2017 Rob Clark
  */

 #include <common.h>
@@ -28,6 +28,7 @@ struct file_handle {
 	struct file_system *fs;
 	loff_t offset;       /* current file position/cursor */
 	int isdir;
+	u64 open_mode;

 	/* for reading a directory: */
 	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
  *			be used as modifiers. A leading backslash indicates an
  *			absolute path.
- * @mode:		bit mask indicating the access mode (read, write,
+ * @open_mode:		bit mask indicating the access mode (read, write,
  *			create)
  * @attributes:		attributes for newly created file
  * Returns:		handle to the opened file or NULL
  */
 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)
 {
 	struct file_handle *fh;
@@ -190,6 +191,7 @@ static struct efi_file_handle *file_open(struct file_system *fs,
 	/* +2 is for null and '/' */
 	fh = calloc(1, sizeof(*fh) + plen + (flen * MAX_UTF8_PER_UTF16) + 2);

+	fh->open_mode = open_mode;
 	fh->base = efi_file_handle_protocol;
 	fh->fs = fs;

@@ -218,9 +220,11 @@ static struct efi_file_handle *file_open(struct file_system *fs,
 			goto error;

 		if (!exists) {
-			if (!(mode & EFI_FILE_MODE_CREATE) ||
+			if (!(open_mode & EFI_FILE_MODE_CREATE) ||
 			    efi_create_file(fh, attributes))
 				goto error;
+			if (set_blk_dev(fh))
+				goto error;
 		}

 		/* figure out if file is a directory: */
@@ -434,6 +438,19 @@ error:
 	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,
 					  efi_uintn_t *buffer_size,
 					  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);

+	if (!file || !buffer_size || !buffer) {
+		ret = EFI_INVALID_PARAMETER;
+		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 error;
+		goto out;
 	}
-
 	if (fs_write(fh->path, map_to_sysmem(buffer), fh->offset, *buffer_size,
 		     &actwrite)) {
 		ret = EFI_DEVICE_ERROR;
-		goto error;
+		goto out;
 	}
-
 	*buffer_size = actwrite;
 	fh->offset += actwrite;

-error:
+out:
 	return EFI_EXIT(ret);
 }

--
2.20.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [U-Boot] [PATCH 2/4] efi_loader: eliminate inline function ascii2unicode()
  2019-09-07 23:59 [U-Boot] [PATCH 0/4] fixes for EFI_FILE_PROTOCOL Heinrich Schuchardt
  2019-09-07 23:59 ` [U-Boot] [PATCH 1/4] efi_loader: EFI_FILE_PROTOCOL.Write() check args Heinrich Schuchardt
@ 2019-09-07 23:59 ` Heinrich Schuchardt
  2019-09-07 23:59 ` [U-Boot] [PATCH 3/4] efi_loader: correct reading of directories Heinrich Schuchardt
  2019-09-07 23:59 ` [U-Boot] [PATCH 4/4] efi_loader: file size checks Heinrich Schuchardt
  3 siblings, 0 replies; 5+ messages in thread
From: Heinrich Schuchardt @ 2019-09-07 23:59 UTC (permalink / raw)
  To: u-boot

ascii2unicode() can only convert characters 0x00-0x7f from UTF-8 to UTF-16.
Use utf8_utf16_strcpy() instead.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
 include/efi_loader.h                     | 16 ----------------
 lib/efi_loader/efi_device_path_to_text.c | 10 +++++-----
 lib/efi_loader/efi_file.c                | 23 +++++++++++++++--------
 3 files changed, 20 insertions(+), 29 deletions(-)

diff --git a/include/efi_loader.h b/include/efi_loader.h
index 00eba8afa4..dd24a2746c 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -555,22 +555,6 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
 	(((_dp)->type == DEVICE_PATH_TYPE_##_type) && \
 	 ((_dp)->sub_type == DEVICE_PATH_SUB_TYPE_##_subtype))

-/**
- * ascii2unicode() - convert ASCII string to UTF-16 string
- *
- * A zero terminated ASCII string is converted to a zero terminated UTF-16
- * string. The output buffer must be preassigned.
- *
- * @unicode:	preassigned output buffer for UTF-16 string
- * @ascii:	ASCII string to be converted
- */
-static inline void ascii2unicode(u16 *unicode, const char *ascii)
-{
-	while (*ascii)
-		*(unicode++) = *(ascii++);
-	*unicode = 0;
-}
-
 static inline int guidcmp(const void *g1, const void *g2)
 {
 	return memcmp(g1, g2, sizeof(efi_guid_t));
diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c
index b20b7c097c..0f3796b373 100644
--- a/lib/efi_loader/efi_device_path_to_text.c
+++ b/lib/efi_loader/efi_device_path_to_text.c
@@ -29,15 +29,15 @@ const efi_guid_t efi_guid_device_path_to_text_protocol =
 static u16 *efi_str_to_u16(char *str)
 {
 	efi_uintn_t len;
-	u16 *out;
+	u16 *out, *dst;
 	efi_status_t ret;

-	len = strlen(str) + 1;
-	ret = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, len * sizeof(u16),
-				(void **)&out);
+	len = sizeof(u16) * (utf8_utf16_strlen(str) + 1);
+	ret = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, len, (void **)&out);
 	if (ret != EFI_SUCCESS)
 		return NULL;
-	ascii2unicode(out, str);
+	dst = out;
+	utf8_utf16_strcpy(&dst, str);
 	return out;
 }

diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c
index a13754a558..9f78b82241 100644
--- a/lib/efi_loader/efi_file.c
+++ b/lib/efi_loader/efi_file.c
@@ -339,6 +339,7 @@ static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size,
 	struct efi_file_info *info = buffer;
 	struct fs_dirent *dent;
 	unsigned int required_size;
+	u16 *dst;

 	if (!fh->dirs) {
 		assert(fh->offset == 0);
@@ -381,7 +382,8 @@ static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size,
 	}

 	/* check buffer size: */
-	required_size = sizeof(*info) + 2 * (strlen(dent->name) + 1);
+	required_size = sizeof(*info) +
+			2 * (utf8_utf16_strlen(dent->name) + 1);
 	if (*buffer_size < required_size) {
 		*buffer_size = required_size;
 		fh->dent = dent;
@@ -398,7 +400,8 @@ static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size,
 	if (dent->type == FS_DT_DIR)
 		info->attribute |= EFI_FILE_DIRECTORY;

-	ascii2unicode(info->file_name, dent->name);
+	dst = info->file_name;
+	utf8_utf16_strcpy(&dst, dent->name);

 	fh->offset++;

@@ -577,6 +580,7 @@ static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file,
 {
 	struct file_handle *fh = to_fh(file);
 	efi_status_t ret = EFI_SUCCESS;
+	u16 *dst;

 	EFI_ENTRY("%p, %pUl, %p, %p", file, info_type, buffer_size, buffer);

@@ -587,7 +591,8 @@ static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file,
 		loff_t file_size;

 		/* check buffer size: */
-		required_size = sizeof(*info) + 2 * (strlen(filename) + 1);
+		required_size = sizeof(*info) +
+				2 * (utf8_utf16_strlen(filename) + 1);
 		if (*buffer_size < required_size) {
 			*buffer_size = required_size;
 			ret = EFI_BUFFER_TOO_SMALL;
@@ -613,7 +618,8 @@ static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file,
 		if (fh->isdir)
 			info->attribute |= EFI_FILE_DIRECTORY;

-		ascii2unicode(info->file_name, filename);
+		dst = info->file_name;
+		utf8_utf16_strcpy(&dst, filename);
 	} else if (!guidcmp(info_type, &efi_file_system_info_guid)) {
 		struct efi_file_system_info *info = buffer;
 		disk_partition_t part;
@@ -628,8 +634,9 @@ static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file,
 			ret = EFI_DEVICE_ERROR;
 			goto error;
 		}
-		required_size = sizeof(info) + 2 *
-				(strlen((const char *)part.name) + 1);
+		required_size = sizeof(*info) + 2 *
+				(utf8_utf16_strlen((const char *)part.name) +
+				 1);
 		if (*buffer_size < required_size) {
 			*buffer_size = required_size;
 			ret = EFI_BUFFER_TOO_SMALL;
@@ -647,8 +654,8 @@ static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file,
 		 * TODO: The volume label is not available in U-Boot.
 		 * Use the partition name as substitute.
 		 */
-		ascii2unicode((u16 *)info->volume_label,
-			      (const char *)part.name);
+		dst = info->volume_label;
+		utf8_utf16_strcpy(&dst, (const char *)part.name);
 	} else {
 		ret = EFI_UNSUPPORTED;
 	}
--
2.20.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [U-Boot] [PATCH 3/4] efi_loader: correct reading of directories
  2019-09-07 23:59 [U-Boot] [PATCH 0/4] fixes for EFI_FILE_PROTOCOL Heinrich Schuchardt
  2019-09-07 23:59 ` [U-Boot] [PATCH 1/4] efi_loader: EFI_FILE_PROTOCOL.Write() check args Heinrich Schuchardt
  2019-09-07 23:59 ` [U-Boot] [PATCH 2/4] efi_loader: eliminate inline function ascii2unicode() Heinrich Schuchardt
@ 2019-09-07 23:59 ` Heinrich Schuchardt
  2019-09-07 23:59 ` [U-Boot] [PATCH 4/4] efi_loader: file size checks Heinrich Schuchardt
  3 siblings, 0 replies; 5+ messages in thread
From: Heinrich Schuchardt @ 2019-09-07 23:59 UTC (permalink / raw)
  To: u-boot

EFI_FILE_PROTOCOL.Read() is used both to read files and directories.

When reaching the end of a directory we always have to return buffer size
zero irrespective of the incoming buffer size. (The described scenario for
a Shim quirk cannot arise because every directory has at least '.' and '..'
as entries.)

Even when the buffer_size is too small multiple times we have to keep a
reference to our last read directory entry.

When we return to the start of the directory via SetPosition() we must
remove the reference to a previously kept directory entry.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
 lib/efi_loader/efi_file.c | 23 +++++------------------
 1 file changed, 5 insertions(+), 18 deletions(-)

diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c
index 9f78b82241..74ad878217 100644
--- a/lib/efi_loader/efi_file.c
+++ b/lib/efi_loader/efi_file.c
@@ -338,7 +338,7 @@ static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size,
 {
 	struct efi_file_info *info = buffer;
 	struct fs_dirent *dent;
-	unsigned int required_size;
+	u64 required_size;
 	u16 *dst;

 	if (!fh->dirs) {
@@ -346,6 +346,7 @@ static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size,
 		fh->dirs = fs_opendir(fh->path);
 		if (!fh->dirs)
 			return EFI_DEVICE_ERROR;
+		fh->dent = NULL;
 	}

 	/*
@@ -356,28 +357,13 @@ static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size,
 	 */
 	if (fh->dent) {
 		dent = fh->dent;
-		fh->dent = NULL;
 	} else {
 		dent = fs_readdir(fh->dirs);
 	}

-
 	if (!dent) {
-		/* no more files in directory: */
-		/* workaround shim.efi bug/quirk.. as find_boot_csv()
-		 * loops through directory contents, it initially calls
-		 * read w/ zero length buffer to find out how much mem
-		 * to allocate for the EFI_FILE_INFO, then allocates,
-		 * and then calls a 2nd time.  If we return size of
-		 * zero the first time, it happily passes that to
-		 * AllocateZeroPool(), and when that returns NULL it
-		 * thinks it is EFI_OUT_OF_RESOURCES.  So on first
-		 * call return a non-zero size:
-		 */
-		if (*buffer_size == 0)
-			*buffer_size = sizeof(*info);
-		else
-			*buffer_size = 0;
+		/* no more files in directory */
+		*buffer_size = 0;
 		return EFI_SUCCESS;
 	}

@@ -389,6 +375,7 @@ static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size,
 		fh->dent = dent;
 		return EFI_BUFFER_TOO_SMALL;
 	}
+	fh->dent = NULL;

 	*buffer_size = required_size;
 	memset(info, 0, required_size);
--
2.20.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [U-Boot] [PATCH 4/4] efi_loader: file size checks
  2019-09-07 23:59 [U-Boot] [PATCH 0/4] fixes for EFI_FILE_PROTOCOL Heinrich Schuchardt
                   ` (2 preceding siblings ...)
  2019-09-07 23:59 ` [U-Boot] [PATCH 3/4] efi_loader: correct reading of directories Heinrich Schuchardt
@ 2019-09-07 23:59 ` Heinrich Schuchardt
  3 siblings, 0 replies; 5+ messages in thread
From: Heinrich Schuchardt @ 2019-09-07 23:59 UTC (permalink / raw)
  To: u-boot

The file size has to be determined in multiple places. Factor out a common
function.

If on entry into EFI_FILE_PROTOCOL.Read() the current position is beyond
the end of the file, return EFI_DEVICE_ERROR.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
 lib/efi_loader/efi_file.c | 69 +++++++++++++++++++++++----------------
 1 file changed, 40 insertions(+), 29 deletions(-)

diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c
index 74ad878217..504b1d1755 100644
--- a/lib/efi_loader/efi_file.c
+++ b/lib/efi_loader/efi_file.c
@@ -318,11 +318,42 @@ static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file)
 	return EFI_EXIT(ret);
 }

+/**
+ * efi_get_file_size() - determine the size of a file
+ *
+ * @fh:		file handle
+ * @file_size:	pointer to receive file size
+ * Return:	status code
+ */
+static efi_status_t efi_get_file_size(struct file_handle *fh,
+				      loff_t *file_size)
+{
+	if (set_blk_dev(fh))
+		return EFI_DEVICE_ERROR;
+
+	if (fs_size(fh->path, file_size))
+		return EFI_DEVICE_ERROR;
+
+	return EFI_SUCCESS;
+}
+
 static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size,
 		void *buffer)
 {
 	loff_t actread;
+	efi_status_t ret;
+	loff_t file_size;
+
+	ret = efi_get_file_size(fh, &file_size);
+	if (ret != EFI_SUCCESS)
+		return ret;
+	if (file_size < fh->offset) {
+		ret = EFI_DEVICE_ERROR;
+		return ret;
+	}

+	if (set_blk_dev(fh))
+		return EFI_DEVICE_ERROR;
 	if (fs_read(fh->path, map_to_sysmem(buffer), fh->offset,
 		    *buffer_size, &actread))
 		return EFI_DEVICE_ERROR;
@@ -341,6 +372,9 @@ static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size,
 	u64 required_size;
 	u16 *dst;

+	if (set_blk_dev(fh))
+		return EFI_DEVICE_ERROR;
+
 	if (!fh->dirs) {
 		assert(fh->offset == 0);
 		fh->dirs = fs_opendir(fh->path);
@@ -409,11 +443,6 @@ static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file,
 		goto error;
 	}

-	if (set_blk_dev(fh)) {
-		ret = EFI_DEVICE_ERROR;
-		goto error;
-	}
-
 	bs = *buffer_size;
 	if (fh->isdir)
 		ret = dir_read(fh, &bs, buffer);
@@ -541,16 +570,9 @@ static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file,
 	if (pos == ~0ULL) {
 		loff_t file_size;

-		if (set_blk_dev(fh)) {
-			ret = EFI_DEVICE_ERROR;
-			goto error;
-		}
-
-		if (fs_size(fh->path, &file_size)) {
-			ret = EFI_DEVICE_ERROR;
+		ret = efi_get_file_size(fh, &file_size);
+		if (ret != EFI_SUCCESS)
 			goto error;
-		}
-
 		pos = file_size;
 	}

@@ -586,15 +608,9 @@ static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file,
 			goto error;
 		}

-		if (set_blk_dev(fh)) {
-			ret = EFI_DEVICE_ERROR;
-			goto error;
-		}
-
-		if (fs_size(fh->path, &file_size)) {
-			ret = EFI_DEVICE_ERROR;
+		ret = efi_get_file_size(fh, &file_size);
+		if (ret != EFI_SUCCESS)
 			goto error;
-		}

 		memset(info, 0, required_size);

@@ -693,14 +709,9 @@ static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file,
 		}
 		free(new_file_name);
 		/* Check for truncation */
-		if (set_blk_dev(fh)) {
-			ret = EFI_DEVICE_ERROR;
-			goto out;
-		}
-		if (fs_size(fh->path, &file_size)) {
-			ret = EFI_DEVICE_ERROR;
+		ret = efi_get_file_size(fh, &file_size);
+		if (ret != EFI_SUCCESS)
 			goto out;
-		}
 		if (file_size != info->file_size) {
 			/* TODO: we do not support truncation */
 			EFI_PRINT("Truncation not supported\n");
--
2.20.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2019-09-07 23:59 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-09-07 23:59 [U-Boot] [PATCH 0/4] fixes for EFI_FILE_PROTOCOL Heinrich Schuchardt
2019-09-07 23:59 ` [U-Boot] [PATCH 1/4] efi_loader: EFI_FILE_PROTOCOL.Write() check args Heinrich Schuchardt
2019-09-07 23:59 ` [U-Boot] [PATCH 2/4] efi_loader: eliminate inline function ascii2unicode() Heinrich Schuchardt
2019-09-07 23:59 ` [U-Boot] [PATCH 3/4] efi_loader: correct reading of directories Heinrich Schuchardt
2019-09-07 23:59 ` [U-Boot] [PATCH 4/4] efi_loader: file size checks Heinrich Schuchardt

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.