RE: [PATCH 2/2] efi/x86: Add a quirk to support command line arguments on Dell EFI firmware

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




> -----Original Message-----
> From: Jacobo Pantoja <jacobopantoja@xxxxxxxxx>
> Sent: Wednesday, September 16, 2020 11:50
> To: Ard Biesheuvel
> Cc: Arvind Sankar; Limonciello, Mario; Peter Jones; linux-efi
> Subject: Re: [PATCH 2/2] efi/x86: Add a quirk to support command line
> arguments on Dell EFI firmware
> 
> 
> [EXTERNAL EMAIL]
> 
> Hi, I'd like to update my testing and share my thoughts.
> 
> Regarding the patches:
> 1) The patches in email 1/2 (the functions "efi_warn", etc.) are not working
> properly. I got some suggestions for testing from Ard in a separate email.
>   3a. If, in this 2nd patch, I switch the "efi_warn_once" with an
> "efi_printk", the
>   messages appear.
>   1a. I've set CONFIG_CONSOLE_LOGLEVEL_DEFAULT=5, same result
>   2a. I've switched from "efi_warn_once" to "efi_warn", same result.
> 2) Even if they would be working, since it is not logged anywhere, I
> don't really
> think these messages make sense. Idk if these can be made available to dmesg.
> 3) The function "efi_apply_loadoptions_quirk" is called twice, it seems to me
> that calling it from the "file.c" is redundant, but probably I'm
> missing something.
> 
> Regarding the quirk itself, in my opinion we should wait for Mario's
> news, since,
> again in my opinion, this is something that should be fixed in the
> firmware itself.
> Being Dell a serious company, I think it is feasible that, at least
> for their enterprise
> products, they might fix it.

I'm sorry to say this is going to be a slow response and I have nothing to share
yet.  My "expectation" however would be that if it's changed it will only be in
modern/current systems and there should still be a need to decide whether to carry
the quirk to support systems with this firmware aberration.

> 
> On Tue, 15 Sep 2020 at 17:09, Ard Biesheuvel <ardb@xxxxxxxxxx> wrote:
> >
> > On Tue, 15 Sep 2020 at 00:35, Arvind Sankar <nivedita@xxxxxxxxxxxx> wrote:
> > >
> > > At least some versions of Dell EFI firmware pass the entire
> > > EFI_LOAD_OPTION descriptor, rather than just the OptionalData part, to
> > > the loaded image. This was verified with firmware revision 2.15.0 on a
> > > Dell Precision T3620 by Jacobo Pontaja.
> 
> Please be so kind to correct my name, if it's being included in the commit
> msg.
> 
> > >
> > > To handle this, add a quirk to check if the options look like a valid
> > > EFI_LOAD_OPTION descriptor, and if so, use the OptionalData part as the
> > > command line.
> > >
> > > Signed-off-by: Arvind Sankar <nivedita@xxxxxxxxxxxx>
> > > Reported-by: Jacobo Pantoja <jacobopantoja@xxxxxxxxx>
> > > Link: https://lore.kernel.org/linux-
> efi/20200907170021.GA2284449@xxxxxxxxxxxxxxxxxx/
> >
> > I'll queue these up for v5.10
> >
> > Thanks all
> >
> > > ---
> > >  .../firmware/efi/libstub/efi-stub-helper.c    | 101 +++++++++++++++++-
> > >  drivers/firmware/efi/libstub/efistub.h        |  31 ++++++
> > >  drivers/firmware/efi/libstub/file.c           |   5 +-
> > >  3 files changed, 135 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c
> b/drivers/firmware/efi/libstub/efi-stub-helper.c
> > > index f735db55adc0..aa8da0a49829 100644
> > > --- a/drivers/firmware/efi/libstub/efi-stub-helper.c
> > > +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
> > > @@ -238,6 +238,102 @@ efi_status_t efi_parse_options(char const *cmdline)
> > >         return EFI_SUCCESS;
> > >  }
> > >
> > > +/*
> > > + * The EFI_LOAD_OPTION descriptor has the following layout:
> > > + *     u32 Attributes;
> > > + *     u16 FilePathListLength;
> > > + *     u16 Description[];
> > > + *     efi_device_path_protocol_t FilePathList[];
> > > + *     u8 OptionalData[];
> > > + *
> > > + * This function validates and unpacks the variable-size data fields.
> > > + */
> > > +static
> > > +bool efi_load_option_unpack(efi_load_option_unpacked_t *dest,
> > > +                           const efi_load_option_t *src, size_t size)
> > > +{
> > > +       const void *pos;
> > > +       u16 c;
> > > +       efi_device_path_protocol_t header;
> > > +       const efi_char16_t *description;
> > > +       const efi_device_path_protocol_t *file_path_list;
> > > +
> > > +       if (size < offsetof(efi_load_option_t, variable_data))
> > > +               return false;
> > > +       pos = src->variable_data;
> > > +       size -= offsetof(efi_load_option_t, variable_data);
> > > +
> > > +       if ((src->attributes & ~EFI_LOAD_OPTION_MASK) != 0)
> > > +               return false;
> > > +
> > > +       /* Scan description. */
> > > +       description = pos;
> > > +       do {
> > > +               if (size < sizeof(c))
> > > +                       return false;
> > > +               c = *(const u16 *)pos;
> > > +               pos += sizeof(c);
> > > +               size -= sizeof(c);
> > > +       } while (c != L'\0');
> > > +
> > > +       /* Scan file_path_list. */
> > > +       file_path_list = pos;
> > > +       do {
> > > +               if (size < sizeof(header))
> > > +                       return false;
> > > +               header = *(const efi_device_path_protocol_t *)pos;
> > > +               if (header.length < sizeof(header))
> > > +                       return false;
> > > +               if (size < header.length)
> > > +                       return false;
> > > +               pos += header.length;
> > > +               size -= header.length;
> > > +       } while ((header.type != EFI_DEV_END_PATH && header.type !=
> EFI_DEV_END_PATH2) ||
> > > +                (header.sub_type != EFI_DEV_END_ENTIRE));
> > > +       if (pos != (const void *)file_path_list + src-
> >file_path_list_length)
> > > +               return false;
> > > +
> > > +       dest->attributes = src->attributes;
> > > +       dest->file_path_list_length = src->file_path_list_length;
> > > +       dest->description = description;
> > > +       dest->file_path_list = file_path_list;
> > > +       dest->optional_data_size = size;
> > > +       dest->optional_data = size ? pos : NULL;
> > > +
> > > +       return true;
> > > +}
> > > +
> > > +/*
> > > + * At least some versions of Dell firmware pass the entire contents of
> the
> > > + * Boot#### variable, i.e. the EFI_LOAD_OPTION descriptor, rather than
> just the
> > > + * OptionalData field.
> > > + *
> > > + * Detect this case and extract OptionalData.
> > > + */
> > > +void efi_apply_loadoptions_quirk(const void **load_options, int
> *load_options_size)
> > > +{
> > > +       const efi_load_option_t *load_option = *load_options;
> > > +       efi_load_option_unpacked_t load_option_unpacked;
> > > +
> > > +       if (!IS_ENABLED(CONFIG_X86))
> > > +               return;
> > > +       if (!load_option)
> > > +               return;
> > > +       if (*load_options_size < sizeof(*load_option))
> > > +               return;
> > > +       if ((load_option->attributes & ~EFI_LOAD_OPTION_BOOT_MASK) != 0)
> > > +               return;
> > > +
> > > +       if (!efi_load_option_unpack(&load_option_unpacked, load_option,
> *load_options_size))
> > > +               return;
> > > +
> > > +       efi_warn_once(FW_BUG "LoadOptions is an EFI_LOAD_OPTION
> descriptor\n");
> > > +       efi_warn_once(FW_BUG "Using OptionalData as a workaround\n");
> > > +
> > > +       *load_options = load_option_unpacked.optional_data;
> > > +       *load_options_size = load_option_unpacked.optional_data_size;
> > > +}
> > > +
> > >  /*
> > >   * Convert the unicode UEFI command line to ASCII to pass to kernel.
> > >   * Size of memory allocated return in *cmd_line_len.
> > > @@ -247,12 +343,15 @@ char *efi_convert_cmdline(efi_loaded_image_t *image,
> int *cmd_line_len)
> > >  {
> > >         const u16 *s2;
> > >         unsigned long cmdline_addr = 0;
> > > -       int options_chars = efi_table_attr(image, load_options_size) / 2;
> > > +       int options_chars = efi_table_attr(image, load_options_size);
> > >         const u16 *options = efi_table_attr(image, load_options);
> > >         int options_bytes = 0, safe_options_bytes = 0;  /* UTF-8 bytes */
> > >         bool in_quote = false;
> > >         efi_status_t status;
> > >
> > > +       efi_apply_loadoptions_quirk((const void **)&options,
> &options_chars);
> > > +       options_chars /= sizeof(*options);
> > > +
> > >         if (options) {
> > >                 s2 = options;
> > >                 while (options_bytes < COMMAND_LINE_SIZE && options_chars-
> -) {
> > > diff --git a/drivers/firmware/efi/libstub/efistub.h
> b/drivers/firmware/efi/libstub/efistub.h
> > > index e33b9395bc23..7997890c756d 100644
> > > --- a/drivers/firmware/efi/libstub/efistub.h
> > > +++ b/drivers/firmware/efi/libstub/efistub.h
> > > @@ -711,6 +711,35 @@ union efi_load_file_protocol {
> > >         } mixed_mode;
> > >  };
> > >
> > > +typedef struct {
> > > +       u32 attributes;
> > > +       u16 file_path_list_length;
> > > +       u8 variable_data[];
> > > +       // efi_char16_t description[];
> > > +       // efi_device_path_protocol_t file_path_list[];
> > > +       // u8 optional_data[];
> > > +} __packed efi_load_option_t;
> > > +
> > > +#define EFI_LOAD_OPTION_ACTIVE         0x0001U
> > > +#define EFI_LOAD_OPTION_FORCE_RECONNECT        0x0002U
> > > +#define EFI_LOAD_OPTION_HIDDEN         0x0008U
> > > +#define EFI_LOAD_OPTION_CATEGORY       0x1f00U
> > > +#define   EFI_LOAD_OPTION_CATEGORY_BOOT        0x0000U
> > > +#define   EFI_LOAD_OPTION_CATEGORY_APP 0x0100U
> > > +
> > > +#define EFI_LOAD_OPTION_BOOT_MASK \
> > > +
> (EFI_LOAD_OPTION_ACTIVE|EFI_LOAD_OPTION_HIDDEN|EFI_LOAD_OPTION_CATEGORY)
> > > +#define EFI_LOAD_OPTION_MASK
> (EFI_LOAD_OPTION_FORCE_RECONNECT|EFI_LOAD_OPTION_BOOT_MASK)
> > > +
> > > +typedef struct {
> > > +       u32 attributes;
> > > +       u16 file_path_list_length;
> > > +       const efi_char16_t *description;
> > > +       const efi_device_path_protocol_t *file_path_list;
> > > +       size_t optional_data_size;
> > > +       const void *optional_data;
> > > +} efi_load_option_unpacked_t;
> > > +
> > >  void efi_pci_disable_bridge_busmaster(void);
> > >
> > >  typedef efi_status_t (*efi_exit_boot_map_processing)(
> > > @@ -753,6 +782,8 @@ __printf(1, 2) int efi_printk(char const *fmt, ...);
> > >
> > >  void efi_free(unsigned long size, unsigned long addr);
> > >
> > > +void efi_apply_loadoptions_quirk(const void **load_options, int
> *load_options_size);
> > > +
> > >  char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len);
> > >
> > >  efi_status_t efi_get_memory_map(struct efi_boot_memmap *map);
> > > diff --git a/drivers/firmware/efi/libstub/file.c
> b/drivers/firmware/efi/libstub/file.c
> > > index 630caa6b1f4c..4e81c6077188 100644
> > > --- a/drivers/firmware/efi/libstub/file.c
> > > +++ b/drivers/firmware/efi/libstub/file.c
> > > @@ -136,7 +136,7 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t
> *image,
> > >                                   unsigned long *load_size)
> > >  {
> > >         const efi_char16_t *cmdline = image->load_options;
> > > -       int cmdline_len = image->load_options_size / 2;
> > > +       int cmdline_len = image->load_options_size;
> > >         unsigned long efi_chunk_size = ULONG_MAX;
> > >         efi_file_protocol_t *volume = NULL;
> > >         efi_file_protocol_t *file;
> > > @@ -148,6 +148,9 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t
> *image,
> > >         if (!load_addr || !load_size)
> > >                 return EFI_INVALID_PARAMETER;
> > >
> > > +       efi_apply_loadoptions_quirk((const void **)&cmdline,
> &cmdline_len);
> > > +       cmdline_len /= sizeof(*cmdline);
> > > +
> > >         if (IS_ENABLED(CONFIG_X86) && !efi_nochunk)
> > >                 efi_chunk_size = EFI_READ_CHUNK_SIZE;
> > >
> > > --
> > > 2.26.2
> > >




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux