Re: [PATCH 10/10] uuid: Constify UUID compound literals

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

 



On Wed, Jan 04, 2017 at 05:54:08PM +0000, Ard Biesheuvel wrote:
> On 2 January 2017 at 10:24, Lukas Wunner <lukas@xxxxxxxxx> wrote:
> > The UUID_BE() and UUID_LE() macros (as well as the derived EFI_GUID())
> > generate a compound literal for a 128-bit ID.  By default, these are not
> > stored in the rodata section but generated on the stack at runtime in a
> > very time- and space-inefficient manner.
> 
> This is not true if you declare those variables static const (in
> function scope).
> 
> In general, I think we should avoid touching uapi headers for this, so
> I would like to explore if we can reach the same result without this
> patch. Another objection I have to this patch is that it is context
> dependent whether the UUID_[LE_BE]() macros in fact generate compound
> literals: this is true for an assignment to a pointer variable, but
> when they are used in initializers this is not the case, and so adding
> 'const' to their definitions is not always appropriate imo.
> 
> Are there any instances where simply turning those automatic variables
> into static const doesn't work?

The number of GUIDs used in the kernel is vast, it's many more than this
patch set makes it appear.  In a lot of cases, they're used as literals.
I would have to declare a temporary "static const" variable for each of
them and this patch set would become much larger and more intrusive.
Additionally the necessity to use a static const variable instead of a
literal seems clumsy and ugly.

As an example, consider arch/ia64/kernel/mca_drv.c:mca_make_slidx() which
contains an if-else-if ladder with 9 entries, each using a GUID literal.
I would have expected objections on grounds of severe ugliness if I had
changed all of these to temporary "static const" variables.

By contrast, just changing the UUID_LE() and UUID_BE() macros causes these
literals to be placed in rodata automatically.

It seems that the only reason for uuid.h to be in uapi is its usage by
two other uapi headers, hyperv.h and mei.h.  The two don't even use the
UUID_LE() and UUID_BE() macros.

The impact of adding const to these macros is limited:  If the macros are
used as an initializer in a user space application and the variable they're
assigned to isn't declared const, gcc will silently make them non-const.

Worst thing that can happen is that compiling the user space application
results in a compiler warning.  This only occurs if the UUID is passed by
reference into a function.  E.g. if this patch wasn't at the end of the
series, these 3 warnings would occur:

arch/x86/platform/efi/quirks.c: In function 'efi_delete_dummy_variable':
arch/x86/platform/efi/quirks.c:52:35: warning: passing argument 2 of 'efi.set_variable' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
  efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
                                   ^
arch/x86/platform/efi/quirks.c:52:35: note: expected 'efi_guid_t * {aka struct <anonymous> *}' but argument is of type 'const uuid_le * {aka const struct <anonymous> *}'

arch/x86/platform/efi/quirks.c: In function 'efi_query_variable_store':
arch/x86/platform/efi/quirks.c:129:45: warning: passing argument 2 of 'efi.set_variable' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
   status = efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
                                             ^
arch/x86/platform/efi/quirks.c:129:45: note: expected 'efi_guid_t * {aka struct <anonymous> *}' but argument is of type 'const uuid_le * {aka const struct <anonymous> *}'

drivers/scsi/isci/probe_roms.c: In function 'isci_get_efi_var':
drivers/scsi/isci/probe_roms.c:190:8: warning: passing argument 2 of 'get_efi()->get_variable' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
        &ISCI_EFI_VENDOR_GUID,
        ^
drivers/scsi/isci/probe_roms.c:190:8: note: expected 'efi_guid_t * {aka struct <anonymous> *}' but argument is of type 'const uuid_le * {aka const struct <anonymous> *}'

This can easily be fixed in the user space application by adding "const"
to function declarations.

To reiterate what I wrote in the commit message, I don't see why anyone
would want to modify the distinct bytes making up the UUID after declaring
it, so marking UUIDs const seems natural.

Thanks,

Lukas

> 
> > E.g. EFI_FILE_SYSTEM_GUID (964E5B22-6459-11D2-8E39-00A0C969723B) results
> > in x86_64 code which requires 80 bytes text instead of 16 bytes rodata:
> >
> >     c6 44 24 20 22                   movb   $0x22,0x20(%rsp)
> >     c6 44 24 21 5b                   movb   $0x5b,0x21(%rsp)
> >     c6 44 24 22 4e                   movb   $0x4e,0x22(%rsp)
> >     c6 44 24 23 96                   movb   $0x96,0x23(%rsp)
> >     c6 44 24 24 59                   movb   $0x59,0x24(%rsp)
> >     c6 44 24 25 64                   movb   $0x64,0x25(%rsp)
> >     c6 44 24 26 d2                   movb   $0xd2,0x26(%rsp)
> >     c6 44 24 27 11                   movb   $0x11,0x27(%rsp)
> >     c6 44 24 28 8e                   movb   $0x8e,0x28(%rsp)
> >     c6 44 24 29 39                   movb   $0x39,0x29(%rsp)
> >     c6 44 24 2a 00                   movb   $0x0,0x2a(%rsp)
> >     c6 44 24 2b a0                   movb   $0xa0,0x2b(%rsp)
> >     c6 44 24 2c c9                   movb   $0xc9,0x2c(%rsp)
> >     c6 44 24 2d 69                   movb   $0x69,0x2d(%rsp)
> >     c6 44 24 2e 72                   movb   $0x72,0x2e(%rsp)
> >     c6 44 24 2f 3b                   movb   $0x3b,0x2f(%rsp)
> >
> > gcc 7 improves on this by using 2x movabs + 2x mov instructions,
> > amounting to 30 bytes text instead of 16 bytes rodata.  That's more
> > space-efficient than 80 bytes but still undesirable from a performance
> > and security perspective:
> >
> >     48 b8 22 5b 4e 96 59 64 d2 11    movabs $0x11d26459964e5b,%rax
> >     48 89 44 24 20                   mov    %rax,0x20(%rsp)
> >     48 b8 8e 39 00 a0 c9 69 72 3b    movabs $0x3b7269c9a00039,%rax
> >     48 89 44 24 28                   mov    %rax,0x28(%rsp)
> >
> > The reason for generating compound literals on the stack is that they're
> > allowed to be modified.  E.g. a pointer to a UUID might be used to
> > change some of its 16 bytes.  In the context of UUIDs this seems silly
> > though:  The uuid_be, uuid_le and efi_guid_t data types hide the
> > distinct bytes making up the ID, the bytes are not meant to be modified.
> > Moreover, the UUIDs are usually pre-defined in a spec such as UEFI and
> > there's no reason at all to modify them.
> >
> > Thus, change the UUID_BE and UUID_LE macros to declare the generated
> > compound literal const, allowing the compiler to put it in rodata.
> >
> > When using the compound literal as an initializer for a variable, that
> > variable has to be declared const as well for the UUID to become rodata.
> >
> > Is that all?  Unfortunately not.  Under certain conditions gcc refuses
> > to store compound literals in rodata despite them being declared const.
> > Rasmus Villemoes opened a bugzilla entry for this in December 2015:
> > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68725
> >
> > The upshot is that if a UUID is passed by value to a function (either
> > directly or as a variable), it is stored in rodata.  This is the case
> > for efi_guidcmp().  But if the UUID is passed by reference, it is
> > generated on the stack, in spite of it being declared const and the
> > function parameter being declared const.  This is the case for the
> > various EFI boot and runtime services calls such as GetVariable.
> > A workaround is to declare a *static* const variable, assign the UUID to
> > it and pass the variable by reference to the function.
> >
> > This issue also affects efi_char16_t strings which are only declared
> > const (and not static const).  They're likewise generated on the stack
> > at runtime.
> >
> > clang 3.9 is not better than gcc:  It does the exact opposite by putting
> > UUIDs in rodata if they're passed by reference, and generating them on
> > the stack if they're passed by value.
> >
> > Cc: Huang Ying <ying.huang@xxxxxxxxx>
> > Cc: Rasmus Villemoes <linux@xxxxxxxxxxxxxxxxxx>
> > Cc: Matt Fleming <matt@xxxxxxxxxxxxxxxxxxx>
> > Cc: Ard Biesheuvel <ard.biesheuvel@xxxxxxxxxx>
> > Signed-off-by: Lukas Wunner <lukas@xxxxxxxxx>
> > ---
> >  include/uapi/linux/uuid.h | 4 ++--
> >  1 file changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/include/uapi/linux/uuid.h b/include/uapi/linux/uuid.h
> > index 3738e5f..9184f01 100644
> > --- a/include/uapi/linux/uuid.h
> > +++ b/include/uapi/linux/uuid.h
> > @@ -29,14 +29,14 @@
> >  } uuid_be;
> >
> >  #define UUID_LE(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7)               \
> > -((uuid_le)                                                             \
> > +((const uuid_le)                                                       \
> >  {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
> >     (b) & 0xff, ((b) >> 8) & 0xff,                                      \
> >     (c) & 0xff, ((c) >> 8) & 0xff,                                      \
> >     (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
> >
> >  #define UUID_BE(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7)               \
> > -((uuid_be)                                                             \
> > +((const uuid_be)                                                       \
> >  {{ ((a) >> 24) & 0xff, ((a) >> 16) & 0xff, ((a) >> 8) & 0xff, (a) & 0xff, \
> >     ((b) >> 8) & 0xff, (b) & 0xff,                                      \
> >     ((c) >> 8) & 0xff, (c) & 0xff,                                      \
> > --
> > 2.11.0
> >
--
To unsubscribe from this list: send the line "unsubscribe linux-efi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[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