efi_loader: file size checks
authorHeinrich Schuchardt <xypron.glpk@gmx.de>
Sat, 7 Sep 2019 21:28:04 +0000 (23:28 +0200)
committerHeinrich Schuchardt <xypron.glpk@gmx.de>
Mon, 9 Sep 2019 13:21:08 +0000 (15:21 +0200)
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

index 74ad878217afeba020650c8b665274508f2e19ec..504b1d175511c2e3319cec200644b5c380acfff3 100644 (file)
@@ -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");