efi_loader: support file rename in SetInfo()
authorGabriel Dalimonte <gabriel.dalimonte@gmail.com>
Mon, 17 Feb 2025 18:26:47 +0000 (13:26 -0500)
committerTom Rini <trini@konsulko.com>
Fri, 7 Mar 2025 17:50:22 +0000 (11:50 -0600)
Following the UEFI specification. The specification did not seem to
delineate if file_name was explicitly a file name only, or could
include paths to move the file to a different directory. The more
generous interpretation of supporting paths was selected.

Signed-off-by: Gabriel Dalimonte <gabriel.dalimonte@gmail.com>
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
lib/efi_loader/efi_file.c

index 6b15c1f..7d81da8 100644 (file)
@@ -954,6 +954,7 @@ static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file,
 {
        struct file_handle *fh = to_fh(file);
        efi_status_t ret = EFI_UNSUPPORTED;
+       char *new_file_name = NULL, *new_path = NULL;
 
        EFI_ENTRY("%p, %pUs, %zu, %p", file, info_type, buffer_size, buffer);
 
@@ -983,13 +984,43 @@ static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file,
                pos = new_file_name;
                utf16_utf8_strcpy(&pos, info->file_name);
                if (strcmp(new_file_name, filename)) {
-                       /* TODO: we do not support renaming */
-                       EFI_PRINT("Renaming not supported\n");
-                       free(new_file_name);
-                       ret = EFI_ACCESS_DENIED;
-                       goto out;
+                       int dlen;
+                       int rv;
+
+                       if (set_blk_dev(fh)) {
+                               ret = EFI_DEVICE_ERROR;
+                               goto out;
+                       }
+                       dlen = filename - fh->path;
+                       new_path = calloc(1, dlen + strlen(new_file_name) + 1);
+                       if (!new_path) {
+                               ret = EFI_OUT_OF_RESOURCES;
+                               goto out;
+                       }
+                       memcpy(new_path, fh->path, dlen);
+                       strcpy(new_path + dlen, new_file_name);
+                       sanitize_path(new_path);
+                       rv = fs_exists(new_path);
+                       if (rv) {
+                               ret = EFI_ACCESS_DENIED;
+                               goto out;
+                       }
+                       /* fs_exists() calls fs_close(), so open file system again */
+                       if (set_blk_dev(fh)) {
+                               ret = EFI_DEVICE_ERROR;
+                               goto out;
+                       }
+                       rv = fs_rename(fh->path, new_path);
+                       if (rv) {
+                               ret = EFI_ACCESS_DENIED;
+                               goto out;
+                       }
+                       free(fh->path);
+                       fh->path = new_path;
+                       /* Prevent new_path from being freed on out */
+                       new_path = NULL;
+                       ret = EFI_SUCCESS;
                }
-               free(new_file_name);
                /* Check for truncation */
                if (!fh->isdir) {
                        ret = efi_get_file_size(fh, &file_size);
@@ -1012,6 +1043,8 @@ static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file,
                ret = EFI_UNSUPPORTED;
        }
 out:
+       free(new_path);
+       free(new_file_name);
        return EFI_EXIT(ret);
 }