Re: [RFC PATCH] x86: Config options to assign versions in the PE-COFF header

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

 



On Tue, Apr 11, 2017 at 06:37:54PM +0100, Ard Biesheuvel wrote:
> On 11 April 2017 at 11:20, Gary Lin <glin@xxxxxxxx> wrote:
> > This commit adds the new config options to allow the user to modify the
> > following fields in the PE-COFF header.
> >
> > UINT16 MajorOperatingSystemVersion
> > UINT16 MinorOperatingSystemVersion
> > UINT16 MajorImageVersion
> > UINT16 MinorImageVersion
> >
> > Those fields are mainly for the executables or libraries in Windows NT
> > or higher to specify the minimum supported Windows version and the
> > version of the image itself.
> >
> > Given the fact that those fields are ignored in UEFI, we can safely reuse
> > those fields for other purposes, e.g. Security Version(*).
> >
> > (*) https://github.com/lcp/shim/wiki/Security-Version
> >
> > Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
> > Cc: Ingo Molnar <mingo@xxxxxxxxxx>
> > Cc: "H. Peter Anvin" <hpa@xxxxxxxxx>
> > Cc: Masahiro Yamada <yamada.masahiro@xxxxxxxxxxxxx>
> > Cc: Michal Marek <mmarek@xxxxxxxx>
> > Cc: Matt Fleming <matt@xxxxxxxxxxxxxxxxxxx>
> > Cc: Ard Biesheuvel <ard.biesheuvel@xxxxxxxxxx>
> > Cc: Joey Lee <jlee@xxxxxxxx>
> > Cc: Vojtech Pavlik <vojtech@xxxxxxx>
> > Signed-off-by: Gary Lin <glin@xxxxxxxx>
> > Tested-by: Joey Lee <jlee@xxxxxxxx>
> > ---
> >  arch/x86/Kconfig       |  24 +++++++
> >  arch/x86/boot/Makefile |  10 +++
> >  scripts/efiversion.pl  | 192 +++++++++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 226 insertions(+)
> >  create mode 100755 scripts/efiversion.pl
> >
> > diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> > index 5bbdef151805..f281c0ff3ff6 100644
> > --- a/arch/x86/Kconfig
> > +++ b/arch/x86/Kconfig
> > @@ -1803,6 +1803,30 @@ config EFI_STUB
> >
> >           See Documentation/efi-stub.txt for more information.
> >
> > +config EFI_MAJOR_OS_VERSION
> > +       hex "EFI Major OS Version"
> > +       range 0x0 0xFFFF
> > +       default "0x0"
> > +       depends on EFI_STUB
> > +
> > +config EFI_MINOR_OS_VERSION
> > +       hex "EFI Minor OS Version"
> > +       range 0x0 0xFFFF
> > +       default "0x0"
> > +       depends on EFI_STUB
> > +
> > +config EFI_MAJOR_IMAGE_VERSION
> > +       hex "EFI Major Image Version"
> > +       range 0x0 0xFFFF
> > +       default "0x0"
> > +       depends on EFI_STUB
> > +
> > +config EFI_MINOR_IMAGE_VERSION
> > +       hex "EFI Minor Image Version"
> > +       range 0x0 0xFFFF
> > +       default "0x0"
> > +       depends on EFI_STUB
> > +
> 
> Why is this x86 only?
> 
> >  config EFI_MIXED
> >         bool "EFI mixed-mode support"
> >         depends on EFI_STUB && X86_64
> > diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
> > index 0d810fb15eac..b9de8b50f32a 100644
> > --- a/arch/x86/boot/Makefile
> > +++ b/arch/x86/boot/Makefile
> > @@ -76,8 +76,18 @@ quiet_cmd_image = BUILD   $@
> >  cmd_image = $(obj)/tools/build $(obj)/setup.bin $(obj)/vmlinux.bin \
> >                                $(obj)/zoffset.h $@
> >
> > +cmd_efiversion = scripts/efiversion.pl \
> > +                       --major-os=$(CONFIG_EFI_MAJOR_OS_VERSION) \
> > +                       --minor-os=$(CONFIG_EFI_MINOR_OS_VERSION) \
> > +                       --major-image=$(CONFIG_EFI_MAJOR_IMAGE_VERSION) \
> > +                       --minor-image=$(CONFIG_EFI_MINOR_IMAGE_VERSION) \
> > +                       $@
> > +
> >  $(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCE
> >         $(call if_changed,image)
> > +ifeq ($(CONFIG_EFI_STUB),y)
> > +       $(call if_changed,efiversion,$@)
> > +endif
> >         @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
> >
> 
> Do we need a script? Can't we just use those defines in the PE/COFF
> header directly? I.e., something like
> 
> diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
> index 3dd5be33aaa7..da21b48a2d68 100644
> --- a/arch/x86/boot/header.S
> +++ b/arch/x86/boot/header.S
> @@ -156,10 +156,10 @@ extra_header_fields:
>  #endif
>         .long   0x20                            # SectionAlignment
>         .long   0x20                            # FileAlignment
> -       .word   0                               # MajorOperatingSystemVersion
> -       .word   0                               # MinorOperatingSystemVersion
> -       .word   0                               # MajorImageVersion
> -       .word   0                               # MinorImageVersion
> +       .word   CONFIG_EFI_MAJOR_OS_VERSION     # MajorOperatingSystemVersion
> +       .word   CONFIG_EFI_MINOR_OS_VERSION     # MinorOperatingSystemVersion
> +       .word   CONFIG_EFI_MAJOR_IMAGE_VERSION  # MajorImageVersion
> +       .word   CONFIG_EFI_MINOR_IMAGE_VERSION  # MinorImageVersion
>         .word   0                               # MajorSubsystemVersion
>         .word   0                               # MinorSubsystemVersion
>         .long   0                               # Win32VersionValue
> 
This looks much saner! I was using the script to modify and check EFI
images and thought it's objcopy to generate the header. I'm happy to
know that I was wrong.

> (and again, why is this x86 only?)
> 
The reason is that I only tested on x86_64. I will add the patches for
ARM and ARM64 later.

Thanks,

Gary Lin

> 
> 
> 
> >  OBJCOPYFLAGS_vmlinux.bin := -O binary -R .note -R .comment -S
> > diff --git a/scripts/efiversion.pl b/scripts/efiversion.pl
> > new file mode 100755
> > index 000000000000..fe730d10638a
> > --- /dev/null
> > +++ b/scripts/efiversion.pl
> > @@ -0,0 +1,192 @@
> > +#!/usr/bin/perl
> > +
> > +=head1 efiversion.pl
> > +
> > +efiversion.pl - show or modify the version fields in the EFI image
> > +
> > +=head1 SYNOPSIS
> > +
> > +efiversion.pl [OPTIONS] FILE
> > +
> > +=head1 OPTIONS
> > +
> > +=over 4
> > +
> > +=item B<--major-os=NUMBER>
> > +
> > +assign the major OS version
> > +
> > +=item B<--minor-os=NUMBER>
> > +
> > +assign the minor OS version
> > +
> > +=item B<--major-image=NUMBER>
> > +
> > +assign the major image version
> > +
> > +=item B<--minor-image=NUMBER>
> > +
> > +assign the minor image version
> > +
> > +=item B<--help, -h>
> > +
> > +print help
> > +
> > +=back
> > +
> > +=head1 DESCRIPTION
> > +
> > +A script to modify the version fields in the header of the EFI image
> > +
> > +Show the versions:
> > +$ efiversion.pl sample.efi
> > +
> > +Modify the versions:
> > +$ efiversion.pl --major-os=1 --minor-os=2 sample.efi
> > +
> > +=cut
> > +
> > +use strict;
> > +use warnings;
> > +use FileHandle;
> > +use Getopt::Long;
> > +Getopt::Long::Configure("no_ignore_case");
> > +
> > +my %options;
> > +
> > +sub usage($) {
> > +       my $r = shift;
> > +       eval "use Pod::Usage; pod2usage($r);";
> > +       if ($@) {
> > +               die "cannot display help, install perl(Pod::Usage)\n";
> > +       }
> > +}
> > +
> > +my $options;
> > +my $major_os = '';
> > +my $minor_os = '';
> > +my $major_image = '';
> > +my $minor_image = '';
> > +my $help = '';
> > +my $overwrite = '';
> > +
> > +GetOptions(
> > +       "major-os=o" => \$major_os,
> > +       "minor-os=o" => \$minor_os,
> > +       "major-image=o" => \$major_image,
> > +       "minor-image=o" => \$minor_image,
> > +       "help|h" => \$help,
> > +) or usage(1);
> > +
> > +usage(1) unless @ARGV;
> > +usage(0) if ($help);
> > +
> > +sub not_ushort($)
> > +{
> > +       my ($number) = @_;
> > +
> > +       return 0 unless $number;
> > +       return 1 if ($number < 0 or $number > 0xFFFF);
> > +
> > +       $overwrite = "y";
> > +
> > +       return 0;
> > +}
> > +
> > +sub check_args
> > +{
> > +       return 0 if not_ushort($major_os);
> > +       return 0 if not_ushort($minor_os);
> > +       return 0 if not_ushort($major_image);
> > +       return 0 if not_ushort($minor_image);
> > +       return 1;
> > +}
> > +
> > +sub read_file($)
> > +{
> > +       my ($file) = @_;
> > +       my $contents;
> > +       my $len;
> > +
> > +       open(FD, "<$file") || die $file;
> > +       binmode FD;
> > +       my @st = stat(FD);
> > +       die $file if (!@st);
> > +       $len = read(FD, $contents, $st[7]) || die $file;
> > +       close(FD) || die $file;
> > +       die "$file: Wanted length ", $st[7], ", got ", $len, "\n"
> > +               if ($len != $st[7]);
> > +       return $contents;
> > +}
> > +
> > +sub get_signature_offset($)
> > +{
> > +       my ($image) = @_;
> > +
> > +       # e_magic must be 'M''Z'
> > +       my ($e_magic) = unpack("n", substr($image, 0, 2));
> > +       die "not a EFI Image\n" unless ($e_magic == 0x4D5A);
> > +
> > +       # Get the offset to the PE signature
> > +       my ($e_lfanew) = unpack("V", substr($image, 0x3C, 4));
> > +
> > +       # Match Signature 'P''E''\0''\0'
> > +       my ($Signature) = unpack("N", substr($image, $e_lfanew, 4));
> > +       die "not a PE Image\n" unless ($Signature == 0x50450000);
> > +
> > +       return $e_lfanew;
> > +}
> > +
> > +sub write_file($)
> > +{
> > +       my ($file, $contents) = @_;
> > +
> > +       open(FD, ">$file") || die $file;
> > +       binmode FD;
> > +       print FD $contents;
> > +       close(FD) || die $file;
> > +}
> > +
> > +sub set_version($)
> > +{
> > +       my ($image_ptr, $offset, $value) = @_;
> > +       my $packed = pack("v", $value);
> > +       substr($$image_ptr, $offset, 2, $packed);
> > +}
> > +
> > +die "invalid arguments\n" unless check_args;
> > +
> > +my ($file) = @ARGV;
> > +my $pe_image = read_file($file) if ($file);
> > +my $e_lfanew = get_signature_offset($pe_image);
> > +
> > +# [PE Signature][COFF File Header][Optional Header]
> > +#     4 bytes        20 bytes
> > +#
> > +# The offset of MajorOperatingSystemVersion in the Optional Header: 40
> > +#
> > +# The file offset of MajorOperatingSystemVersion: $e_lfanew + 24 + 40
> > +#
> > +# Our targets:
> > +#   UINT16  MajorOperatingSystemVersion;
> > +#   UINT16  MinorOperatingSystemVersion;
> > +#   UINT16  MajorImageVersion;
> > +#   UINT16  MinorImageVersion;
> > +my $os_offset = $e_lfanew + 64;
> > +
> > +if ($overwrite) {
> > +       # Write the file
> > +       &set_version(\$pe_image, $os_offset,     $major_os)     if ($major_os);
> > +       &set_version(\$pe_image, $os_offset + 2, $minor_os)     if ($minor_os);
> > +       &set_version(\$pe_image, $os_offset + 4, $major_image)  if ($major_image);
> > +       &set_version(\$pe_image, $os_offset + 6, $minor_image)  if ($minor_image);
> > +       &write_file($file, $pe_image);
> > +} else {
> > +       # Get the versions
> > +       (my @versions) = unpack("v6", substr($pe_image, $os_offset, 12));
> > +
> > +       printf "MajorOperatingSystemVersion\t0x%X\n", $versions[0];
> > +       printf "MinorOperatingSystemVersion\t0x%X\n", $versions[1];
> > +       printf "MajorImageVersion\t\t0x%X\n",         $versions[2];
> > +       printf "MinorImageVersion\t\t0x%X\n",         $versions[3];
> > +}
> > --
> > 2.12.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