efi_loader: correct reading of directories
authorHeinrich Schuchardt <xypron.glpk@gmx.de>
Sat, 7 Sep 2019 20:34:07 +0000 (22:34 +0200)
committerHeinrich Schuchardt <xypron.glpk@gmx.de>
Mon, 9 Sep 2019 13:21:08 +0000 (15:21 +0200)
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

index 9f78b822419657298236beaa4c8e24e6918fc164..74ad878217afeba020650c8b665274508f2e19ec 100644 (file)
@@ -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);