meta-secure-core: initial commit

Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
This commit is contained in:
Lans Zhang
2017-06-22 15:22:01 +08:00
commit 1b3e594449
204 changed files with 14086 additions and 0 deletions

17
COPYING.MIT Normal file
View File

@@ -0,0 +1,17 @@
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

1
MAINTAINERS Normal file
View File

@@ -0,0 +1 @@
Jia Zhang <lans.zhang2008@gmail.com>

60
README Normal file
View File

@@ -0,0 +1,60 @@
This README file contains information on the contents of the
meta-secure-core layer.
Please see the corresponding sections below for details.
Dependencies
============
This layer depends on:
URI: git://git.openembedded.org/bitbake
branch: master
URI: git://git.openembedded.org/openembedded-core
layers: meta
branch: master
Patches
=======
Please submit any patches against the meta-secure-core layer to the
maintainer:
Maintainer: Jia Zhang <lans.zhang2008@gmail.com>
Table of Contents
=================
I. Adding the meta-secure-core layer to your build
II. Misc
I. Adding the meta-secure-core layer to your build
=================================================
--- replace with specific instructions for the meta-secure-core layer ---
In order to use this layer, you need to make the build system aware of
it.
Assuming the meta-secure-core layer exists at the top-level of your
yocto build tree, you can add it to the build system by adding the
location of the meta-secure-core layer to bblayers.conf, along with any
other layers needed. e.g.:
BBLAYERS ?= " \
/path/to/yocto/meta \
/path/to/yocto/meta-poky \
/path/to/yocto/meta-yocto-bsp \
/path/to/yocto/meta-meta-secure-core \
"
II. Misc
========
--- replace with specific information about the meta-secure-core layer ---

95
README.md Normal file
View File

@@ -0,0 +1,95 @@
### meta-secure-env
This layer provides the following common and platform-specific security
features:
#### UEFI Secure Boot
For x86 platform, UEFI secure boot is the industry standard defined in the
UEFI spec, allowing images loaded by UEFI BIOS to be verified with the trusted
key. Whenever this feature is enabled, the bootloader and kernel will be
signed automatically during the build, implying the signed binaries are
contained by the resulting RPM and rootfs image.
Refer to [meta-efi-secure-boot](https://github.com/jiazhang0/meta-efi-secure-boot/blob/master/README.md) for more details.
#### MOK Secure Boot
For x86 platform, MOK secure boot is based on the UEFI secure boot, adding
the shim loader to chainloader the second-stage bootloader. Meanwhile,
the shim will also install a protocol which permits the second-stage bootloader
to perform similar binary validation, e.g, for linux kernel.
Refer to [meta-efi-secure-boot](https://github.com/jiazhang0/meta-efi-secure-boot/blob/master/README.md) for more details.
#### User key store
By default, the signing key used by UEFI/MOK secure boot is the sample key for
the purposes of development and demonstration. It is not recommended that
this sample key be used for a production device and should be replaced by
a secret key owned by the user.
Refer to [meta-signing-key](https://github.com/jiazhang0/meta-signing-key/blob/master/README.md)
for more details about how to construct an user key store.
#### TPM 1.x
This feature enables Trusted Platform Module 1.x support, including
kernel option changes to enable tpm drivers, and picking up TPM 1.x packages.
Refer to [meta-tpm](https://github.com/jiazhang0/meta-tpm/blob/master/README.md)
for more details.
#### TPM 2.0
This feature enables Trusted Platform Module 2.0 support, including
kernel option changes to enable tpm drivers, and picking up TPM 2.0 packages.
Trusted Platform Module (TPM 2.0) is a microcontroller that stores keys,
passwords, and digital certificates. A discrete TPM 2.0 offers the
capabilities as part of the overall platform security requirements.
Refer to [meta-tpm2](https://github.com/jiazhang0/meta-tpm2/blob/master/README.md)
for more details.
#### Encrypted storage
This feature gives 2 types of granularity for storage encryption. Data volume
encryption allows the user to create encryption partition with a passphrase
typed by the end user. Root filesystem encryption enables the data encryption on
the entire rootfs except the boot partition.
Both types of storage encryption are based on device-mapper crypt target,
which provides transparent encryption of block devices using the kernel crypto
API. Additionally, the utility cryptsetup is used to conveniently setup disk
encryption based on device-mapper crypt target.
Refer to [meta-encrypted-storage](https://github.com/jiazhang0/meta-encrypted-storage/blob/master/README.md) for more details.
#### Integrity
The Linux IMA subsystem introduces hooks within the Linux kernel to support
measuring the integrity of files that are loaded (including application code)
before it is executed or mmap()ed to memory. The measured value (hash) is then
registered in a log that can be consulted by administrators.
To support proven integrity of the files, the IMA subsystem can interact with
the TPM chip within the system to protect the registered hashes from tampering
by a rogue administrator or application. The IMA subsystem, as already
supported by the Linux kernel, supports reporting on the hashes of files and
commands ran by privileged accounts (and more if you create your own
measurement policies).
In addition, IMA appraisal can even register the measured value as an extended
attribute, and after subsequent measurement(s) validate this extended attribute
against the measured value and refuse to load the file (or execute the
application) if the hash does not match. In that case, the IMA subsystem allows
files and applications to be loaded if the hashes match (and will save the
updated hash if the file is modified) but refuse to load it if it doesn't. This
provides some protection against offline tampering of the files.
Refer to [meta-integrity](https://github.com/jiazhang0/meta-efi-secure-boot/blob/master/README.md)
for more details.
#### RPM signing
This feature provides the integrity verification for the RPM5 package.
Refer to [meta-rpm-signing](https://github.com/jiazhang0/meta-rpm-signing/blob/master/README.md)
for more details.
### Building the meta-secure-env layer
This layer should be added to the bblayers.conf file. To enable certain
feature provided by this layer, add the feature to the local.conf file.

View File

@@ -0,0 +1,463 @@
### EFI secure boot feature
This feature consists of two widely used secure boot technologies: UEFI Secure
Boot and MOK Secure Boot.
- UEFI Secure Boot is the industry standard defined in the UEFI spec, allowing the
images loaded by UEFI BIOS to be verified with the certificates corresponding to
the trusted keys.
- MOK (Machine Owner Key) Secure Boot is based on UEFI Secure Boot, adding
the shim bootloader to chainloader the next stage bootloader with the integrity
check using the shim-managed certificates corresponding to another set of
trusted keys which may be different than the trusted keys used by UEFI Secure
Boot.
In addition, this feature introduces the SELoader as the second-stage bootloader
and eventually chainliader to the third-stage bootloader "grub". With the
extension provided by SELoader, grub configuration files, kernel (even without
EFI stub support) and initrd can be authenticated. This capability is not
available in the shim bootloader.
Grub bootloader is enhanced to support lockdown mode. In this mode, the
edit, rescue and command line are protected in order to prevent from
tampering the kernel commandline or loading an unsigned boot component. Hence,
this lockdown protection can effectively defeat the attempts to disable the
kernel security mechanisms. The flexibility is also provided if the user
authentication is enabled. The user authenticated by a password check can enter
into edit and command line.
Therefore, using UEFI Secure Boot, SELoader, and grub lockdown together, the
boot process is completely trustworthy.
A complete boot flow with this feature is:
- UEFI BIOS boot manager (UEFI Secure Boot enabled) ->
- shim (verified by a DB certificate) ->
- SELoader (verified by a shim-managed certificate) ->
- grub (verified by a shim-managed certificate) ->
- grub.cfg (verified by a shim-managed certificate)
- kernel (verified by a shim-managed certificate)
- initramfs (verified by a shim-managed certificate)
### Quick start for the first boot
- Deploy the rootfs
- Boot up the target board
- Enter to BIOS setup and remove the enrolled certificates
* It is recommended to still turn on UEFI Secure Boot option if allowed.
- Exit BIOS setup and automatically reboot
- Manually launch a reboot via ctrl + alt + del again
* Otherwise, a misleading error message about the verification failure
will be displayed.
- Automatically boot to the boot option "Automatic Certificate Provision" in
grub boot menu.
- (Optional) Enter into BIOS setup to turn on UEFI Secure Boot option
- Boot to the system with the protection provided by UEFI and MOK Secure Boot
### Key Management
Refer to meta-signing-key/README.md for the initial cognition about key
management for UEFI Secure Boot.
Note that the sample key and user key are the concepts in the key signing
model according to the ownership and secrecy. In UEFI Secure Boot, a policy
object such as PK, KEK, DB and DBX is mapped to a key managed by the key
signing model.
#### Sample Keys
This feature, by default, use **the sample keys** to sign and verify images for
the purpose of development and demonstration. **Please ensure you know what your
risk is to use the sample keys in your product, because they are completely
public.**
The sample keys used for UEFI Secure Boot are centrally placed under
meta-signing-key/files/uefi_sb_keys/.
- PK.pem
The X509 certificate enrolled to UEFI BIOS, used to update/delete PK/KEK.
- PK.key
The private key corresponding to PK.pem, used to sign the EFI signature
list for PK/KEK enrollment.
- KEK.pem
The X509 certificate enrolled to UEFI BIOS, used to update/delete
DB/DBX.
- KEK.key
The private key corresponding to KEK.pem, used to sign the EFI signature
list for DB/DBX enrollment.
- DB.pem
The X509 certificate enrolled to UEFI BIOS, used to verify the images
directly loaded by UEFI BIOS.
- DB.key
The private key corresponding to DB.pem, used to sign the images directly
loaded by UEFI BIOS.
- DBX
This directory contains any number of X509 certificate enrolled to UEFI
BIOS, used to blacklist the revoked certificates. The revoked certificates
must be PEM-formatted.
The sample keys used for MOK Secure Boot are centrally placed under
`meta-signing-key/files/mok_sb_keys/`.
- shim_cert.pem
The X509 certificate embedded in shim, used to verify the images either
directly or indirectly loaded by shim.
- shim_cert.key
The private key corresponding to shim_cert.pem, used to sign the images
either directly or indirectly loaded by shim.
- vendor_cert.pem
Used in the same way as shim_cert.pem. In addition, vendor certificate
is the switch to enable shim verification protocol, which facilitates
the verification for the SELoader.
- vendor_cert.key
The private key corresponding to vendor_cert.pem, Same fuction as
shim_cert.key.
- vendor_dbx
This directory contains any number of X509 certificate embedded in shim,
used to blacklist the revoked certificates.
#### User Keys
Refer to meta-signing-key/README.md for the details about how to generate/use
the keys owned by the end user.
#### Automatic Certificate Provision
The certificate provision is required to enable UEFI Secure Boot. By default,
the target may be provisioned with the default certificates enrolled during the
manufacture.
In order to use the bootloader and kernel signed by the sample or self-owned
key to boot up the system, this feature provides a process of autmatic
certificate provison for the convenience. Refer to the instructions listed in
the section "Work Flow For The First Boot". The detailed descriptions are
given below.
##### Remove the enrolled certificates in BIOS setup
The LockDown.efi application is used to run the provision. However,
LockDown.efi cannot be launched if UEFI Secure Boot is already enabled. In
addition, the enrolled certificates may be not the ones the user hopes to use.
The provisioned certificates can be removed in BIOS setup. The detailed steps
may vary between the boards. Refer to BIOS manual for the details.
##### Launch the automatic provision
Lockdown.efi will automatically provision UEFI Secure Boot after removing the
the provisioned certificates in BIOS setup. More specifically, the PK, KEK,
DB and DBX (if any) will be enrolled and begin to take affect after a reboot.
##### Turn on UEFI Secure Boot option
If UEFI Secure Boot option is turned off, the user has to enter into BIOS setup
after provision to manually turn on the option.
If the option is already enabled when removing the enrolled certificates in
BIOS setup, this step can be ignored.
##### Re-trigger automatic provision
By default, the "Automatic Certificate Provision" option is hidden in boot
menu for the first boot. If the user would like to clear the certificates
provisioned by the "Automatic Certificate Provision" option in BIOS setup, this
hidden boot option will be shown in boot menu, allowing to re-trigger it when
necessary.
### Signing
By default, the build system uses DB.key to sign shim, and uses vendor_cert.key
to sign SELoader, grub, grub configuration file, kernel and initramfs image
during the build.
### Verficiation
#### UEFI Secure Boot Verification
UEFI BIOS will validate the integrity of shim bootloader with a certificate in
DB before running it.
#### Bootloader Verification
When the shim loads SELoader and SELoader loads grub, if both UEFI Secure Boot
and MOK Secure Boot are already enabled, the upper bootloader uses a list of
certificate to check the integrity of lower bootloader.
- Blacklist check
If the lower bootloader is signed with a key corresponding to a certificate
within any of a policy object below, the boot failure will occur.
* Vendor DBX
* DBX
* MokListX (MOK certificate blacklist)
- Whitelist check
If the lower bootloader is signed with a key corresponding to a certificate
within any of a policy object below, the boot success will occur.
* DB
* MokList (MOK certificate whitelist)
* Shim certificate (only for PE image)
* Vendor certificate
If the lower bootloader is not signed or signed by a key not corresponding to
any policy objects mentioned above, the boot failure will occur.
The benefit of these behaviors allow the end user to regulate the secure boot
even without the ownership of DB on Microsoft certificated hardware.
##### SELoader Verification
The SELoader is designed to authenticate the non-PE files, such as grub.cfg,
kernel (without EFI stub support) and initrd, which cannot be verified by
the verification protocol registered by the shim loader.
In order to conveniently authenticate the PE file with gBS->LoadImage()
and gBS->StartImage(), the SELoader hooks EFI Security2 Architectural
Protocol and employs verification protocol provided by the shim loader to
verify the PE file. If only UEFI Secure Boot is enabled, the SELoader just
simplily calls gBS->LoadImage() and gBS->StartImage() to allow UEFI BIOS
to verify the PE file.
The SELoader publishes MOK2 verification protocol which provides a flexible
interface to allow the bootloader to verify the file, file buffer or
memory buffer without knowing the file format.
In order to establish the chain of trust, the SELoader is required to be
signed by a private key corresponding to a DB certificate, the shim
certificate, the vendor certificate or a MOK certificate. The specific
key is determined by the secure boot scheme you will use.
See more details about the SELoader in its README file.
#### Grub Configuration File Verification
Grub can call the MOK2 verification protocol registered by the SELoader
to validate the integrity of grub configuration file before parsing it.
This protection prevents from tampering the grub configuration file from
disabling certains kernel security mechanism such as selinux, IMA and so on.
#### Kernel Verification
When SELoader loads the kernel image with the linux command, if both UEFI
Secure Boot and MOK Secure Boot are already enabled, grub will call the
verification protocol installed by SELoader to validate the kernel image.
Alternately, if grub loads the kernel image with the chainloader command,
if both UEFI Secure Boot and MOK Secure Boot are already enabled, grub will
call the verification protocol installed by shim to validate the kernel image.
By default, the kernel image is signed by vendor certificate and then signed
again to generate the .p7b signature file.
#### Initramfs Verification
When SELoader loads the kernel image with the initrd command, if both UEFI
Secure Boot and MOK Secure Boot are already enabled, grub will call the
verification protocol installed by SELoader to validate the initramfs image.
#### Verification Failure
Either situation will cause a failure of verification.
- A boot component is not signed.
- A boot component is signed by a key which doesn't correspond to any
certificate in whitelists such as DB and shim-managed certificates.
- A boot component is signed by a key which corresponds to a certificate in
blacklist such as DBX and shim-managed certificates in MOKX.
Each boot component may have different verification failure phenomenon.
- If SELoader fails signature check, UEFI BIOS boot manager will print an error
message about the image authentication failure.
- If grub fails signature check, an image authentication failure message is
printed and the system hangs.
- If a grub configuration file fails the signature check, an authentication
failure message is printed and grub hangs.
- If kernel image fails signature check, grub returns back to the boot menu.
- If initrd fails signature check, grub returns back to the boot menu.
### MOK Secure Boot and the shim bootloader
MOK (Machine Owner Key) Secure Boot is based on UEFI Secure Boot, adding
the shim bootloader to chainloader the second-stage bootloader
"SELoader" and eventually chainliader to the third-stage bootloader "grub".
[ Quoting: https://github.com/rhinstaller/shim ]
shim is a trivial EFI application that, when run, attempts to open and
execute another application. It will initially attempt to do this via the
standard EFI LoadImage() and StartImage() calls. If these fail (because secure
boot is enabled and the binary is not signed with an appropriate key, for
instance) it will then validate the binary against a built-in certificate. If
this succeeds and if the binary or signing key are not blacklisted then shim
will relocate and execute the binary.
shim will also install a protocol which permits the second-stage bootloader
to perform similar binary validation. This protocol has a GUID as described
in the shim.h header file and provides a single entry point. On 64-bit systems
this entry point expects to be called with SysV ABI rather than MSABI, and
so calls to it should not be wrapped.
[ End of Quote ]
In most cases, the hardware coming out of the factory is already provisioned
with a default certificate used to verify the bootloader and issued by
Microsoft Corporation UEFI CA 2011. This kind of hardware is so-called
Microsoft certificated hardware.
Obviously, this requirement needs a bootloader loaded by BIOS must be signed
by Microsoft. Microsoft provides the signing service (not free), but only
accept shim bootloader for Linux world. Refer to [Microsoft's signing policy](http://blogs.msdn.com/b/windows_hardware_certification/archive/2013/12/03/microsoft-uefi-ca-signing-policy-updates.aspx).
It is allowed to remove all default certificates and use the self-owned keys to
provision UEFI Secure Boot, but this is not practical for ODM/OEM devices
during the manufacture phrase. See the section "Out-of-box Experience".
For a good user experience, shim + SELoader + grub is an excellent combination
to handle Microsoft certificated hardware. With this model, SELoader and grub
are signed by a shim-managed certificate without being subject to the limit from
Microsoft's signing policy, and the manual provision is thus unnecessary.
#### mokutil and MOK Manager
mokutil is a tool to import or delete the machines owner keys stored in the
database of shim. mokutil creates the requests and MOK manager will be
automatically launched by shim as long as it detects the pending requests.
The physical present user will be prompted to run the operations corresponding
to the requests. Note the operation is required to be authenticated by MOK
management password set by mokutil.
Refer to mokutil man page for the detailed usages.
##### MOK Management Password
MOK management password is the authentication information to allow MOK manager
to grant the request regarding of MOK management. To set the password, run
mokutil with the option --password. In addition, there are 4 input methods to
provide the password. By default, mokutil prompts the user to input the
password and then wraps the password to sha256 password hash. For other 3
methods, refer to the uses of option --hash-file, --root-pw and --simple-hash.
##### Enroll the MOK certificate
Here is an example showing how to enroll a DER formatted X509 certificate to
the database of shim.
```
# mokutil --import <cert.cer>
```
where `<cert.cer>` is the MOK certificate corresponding to the private key used
to sign either grub or kernel.
To convert a PEM, for exmaple, the shim_cert.pem, to a DER formatted X509
certificate, type the command:
```
$ openssl x509 -in shim_cert.pem -inform PEM -out shim_cert.cer -outform DER
```
##### List the enrollment requests
The several enrollment requests can be submitted before system reboot. Run the
following command to check all enrollment requests.
```
# mokutil --list-new
```
##### Revoke the enrollment requests
Note the revocation operation will remove all enrollment requests.
```
# mokutil --revoke-import
```
##### Test the MOK certificate
If you cannot confirm whether a certificate has been enrolled or not, type the
following command for a check:
```
# mokutil --test-key <cert.cer>
```
##### Delete the MOK certificate
Removing an useless MOK certificate is also supported.
```
# mokutil --delete <cert.cer>
```
Refer to the options --list-delete and --revoke-delete to list and revoke the
MOKs.
##### Reset MOK certificates
This request will clear all enrolled MOK certificates.
```
# mokutil --reset
```
##### Disable/Enable MOK Secure Boot
MOK Secure Boot can be enabled or disabled regardless of the setting of UEFI
Secure Boot.
```
# mokutil --disable-validation // disable MOK Secure Boot
# mokutil --enable-validation // enable MOK Secure Boot
```
Note that MOK Secure Boot is based on UEFI Secure Boot. If UEFI Secure Boot
is disabled, MOK Secure Boot will be automatically inactive. Type the
following command to check the status of UEFI Secure Boot.
```
# mokutil --sb-state
```
##### Other options
Refer to the options --import-hash and --delete-hash to manage hash-based
signature. The options --pk, --kek, --db and --dbx are useful to check
the content of the policy objects used in UEFI Secure Boot.
##### Manage blacklist
All above mentioned are talking MOK which is acting as whitelist to
authenticate the verified image to launch. Actually, there is a contrary
policy object called MOKX, acting as blacklist to deny the untrusted
image to launch. Also, MOKX as blacklist is handled by shim prior to MOK
as whitelist.
For the management of blacklist, add the option --mokx with the following
options to change the operation target from MOK to the following options.
--list-enrolled
--test-key
--list-new
--list-delete
--import
--delete
--import-hash
--delete-hash
--reset
--revoke-import
--revoke-delete
##### Handle MOK Secure Boot Failure with MOK Manager
If either grub or SELoader is not signed or signed with an unauthorized
certificate, the shim will prompt the end user a UI called MOK manager to
guide the user to enroll the certificate or hash of the image.
The policy of the selection between digest and certificate for next step is
decided by whether the unauthorized grub or SELoader is signed or not.
If the grub or SELoader is not signed at all, you have to always select
the calculation of the digest based on the file. Note that once grub or SELoader
is updated and its digest is changed, you have to relaunch the MOK manager
to enroll the new digests.
If the grub or SELoader is signed by an unauthorized certificate, enrolling the
signing certificate is the preferred way. Copy the certificate to the boot
drive and then select the certificate in MOK manager. Note that the
certificate for the selection must be **DER formatted**.
If doing so, the unauthorized grub or SELoader will be verified successfully
after exiting MOK Manager.
### Grub Lockdown
In order to prevent from tampering the kernel command line or loading an
unsigned boot component, grub is locked if UEFI Secure Boot is enabled. In this
situation, the end user cannot enter into command or edit line via pressing 'c'
and 'e'.
If the user authentication is enabled, the access to command or edit line is
protected by a password. In this situation, grub is unlockable.
Rescue mode is always disabled as long as UEFI Secure Boot is enabled.
### Known Issues
- The 32-bit MOK Secure Boot is not validated. In other words, loading 32-bit
shim, MOK manager, grub and kernel is not supported.
### Reference
[OpenEmbedded layer for EFI secure boot features](https://github.com/jiazhang0/meta-efi-secure-boot)

View File

@@ -0,0 +1,16 @@
# We have a conf and classes directory, add to BBPATH
BBPATH .= ":${LAYERDIR}"
# We have recipes-* directories, add to BBFILES
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
${LAYERDIR}/recipes-*/*/*.bbappend"
BBFILE_COLLECTIONS += "efi-secure-boot"
BBFILE_PATTERN_efi-secure-boot = "^${LAYERDIR}/"
BBFILE_PRIORITY_efi-secure-boot = "10"
LAYERDEPENDS_efi-secure-boot = "\
core \
openembedded-layer \
signing-key \
"

View File

@@ -0,0 +1,28 @@
DESCRIPTION = "EFI Secure Boot packages for secure-environment."
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COREBASE}/LICENSE;md5=4d92cd373abda3937c2bc47fbc49d690 \
file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420"
S = "${WORKDIR}"
ALLOW_EMPTY_${PN} = "1"
pkgs = " \
grub-efi \
efitools \
efibootmgr \
mokutil \
seloader \
shim \
"
RDEPENDS_${PN}_x86 = "${pkgs}"
RDEPENDS_${PN}_x86-64 = "${pkgs}"
kmods = " \
kernel-module-efivarfs \
kernel-module-efivars \
"
RRECOMMENDS_${PN}_x86 += "${kmods}"
RRECOMMENDS_${PN}_x86-64 += "${kmods}"

View File

@@ -0,0 +1,11 @@
require efitools.inc
inherit native
DEPENDS_append = " gnu-efi-native"
EXTRA_OEMAKE_append = " \
INCDIR_PREFIX='${STAGING_DIR_NATIVE}' \
CRTPATH_PREFIX='${STAGING_DIR_NATIVE}' \
EXTRA_LDFLAGS='-Wl,-rpath,${libdir}' \
"

View File

@@ -0,0 +1,63 @@
SUMMARY = "Tools to support reading and manipulating the UEFI signature database"
DESCRIPTION = "\
From the EFI Tools package in the Linux user-space, it's now possible \
to read and manipulate the UEFI signatures database via the new \
efi-readvar and efi-updatevar commands. Aside from needing efitools \
1.4, the EFIVARFS file-system is also needed, which was only introduced \
in the Linux 3.8 kernel. \
"
LICENSE = "GPLv2"
LIC_FILES_CHKSUM = "file://COPYING;md5=e28f66b16cb46be47b20a4cdfe6e99a1"
SRC_URI = " \
git://git.kernel.org/pub/scm/linux/kernel/git/jejb/efitools.git \
file://Fix-for-the-cross-compilation.patch \
file://Kill-all-the-build-warning-caused-by-implicit-declar.patch \
file://Fix-the-wrong-dependency-for-blacklist.esl.patch \
file://LockDown-run-system-warm-reset-after-the-key-provisi.patch \
file://Allow-to-override-tools-for-target-build.patch \
file://Fix-help2man-failure.patch \
file://Don-t-build-PreLoader.efi.patch \
file://Reuse-xxdi.pl.patch \
file://Add-static-keyword-for-IsValidVariableHeader.patch \
"
SRCREV = "0649468475d20d8ca5634433c4912467cef3ce93"
PV = "1.7.0+git${SRCPV}"
PARALLEL_MAKE = ""
inherit perlnative
DEPENDS_append += "\
help2man-native openssl-native sbsigntool-native \
libfile-slurp-perl-native \
"
S = "${WORKDIR}/git"
EXTRA_OEMAKE = " \
HELP2MAN='${STAGING_BINDIR_NATIVE}/help2man' \
OPENSSL='${STAGING_BINDIR_NATIVE}/openssl' \
SBSIGN='${STAGING_BINDIR_NATIVE}/sbsign' \
OPENSSL_LIB='${STAGING_LIBDIR}' \
NM='${NM}' AR='${AR}' \
"
EXTRA_OEMAKE_append_x86 += " ARCH=ia32"
EXTRA_OEMAKE_append_x86-64 += " ARCH=x86_64"
# LDFLAGS is used by LD not CC, so remove '-Wl,'
LDFLAGS := "${@oe_filter_out('-Wl,', '${LDFLAGS}', d)}"
BUILD_LDFLAGS := "${@oe_filter_out('-Wl,', '${BUILD_LDFLAGS}', d)}"
do_compile_prepend() {
sed -i -e "1s:#!.*:#!/usr/bin/env nativeperl:" xxdi.pl
}
EFI_BOOT_PATH = "/boot/efi/EFI/BOOT"
FILES_${PN} += "${EFI_BOOT_PATH}"
do_install() {
oe_runmake install DESTDIR='${D}${base_prefix}'
}

View File

@@ -0,0 +1,38 @@
From 960a5fc7c58c875827797b6f4afed2684acc2cde Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Sun, 12 Jun 2016 13:45:54 +0800
Subject: [PATCH] Add static keyword for IsValidVariableHeader()
Upstream-Status: Pending
GCC does not inline any functions when not optimizing (-O0 specified) unless
you specify "always_inline" attribute for the function.
By default, GCC complies with C89 standard for c code, which means
"inline" equals to "extern inline" and thus the definition is used only for
inlining with the assembly code actually generated.
Therefore, "static inline" is used for both purposes. If -O0 is specified,
GCC will generate the assembly code as long as the function is referred.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
include/variableformat.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/include/variableformat.h b/include/variableformat.h
index 32cde05..45d0ebb 100644
--- a/include/variableformat.h
+++ b/include/variableformat.h
@@ -109,7 +109,7 @@ typedef struct {
#pragma pack()
-inline BOOLEAN
+static inline BOOLEAN
IsValidVariableHeader (VARIABLE_HEADER *vh) {
if (vh == NULL || vh->StartId != VARIABLE_DATA)
return FALSE;
--
1.7.1

View File

@@ -0,0 +1,94 @@
From 1613bae3a9760b3cdcbf8f43e750c475d69ad8bb Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Wed, 23 Mar 2016 19:05:29 +0800
Subject: [PATCH] Allow to override tools for target build
Upstream-Status: Pending
These tools should use the ones from native build.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
Make.rules | 22 +++++++++++++---------
Makefile | 4 ++--
2 files changed, 15 insertions(+), 11 deletions(-)
diff --git a/Make.rules b/Make.rules
index 5e8cb82..4aa7650 100644
--- a/Make.rules
+++ b/Make.rules
@@ -34,6 +34,10 @@ AR = ar
OPENSSL = openssl
SBSIGN = sbsign
XXD = xxd
+SIGN_EFI_SIG_LIST ?= ./sign-efi-sig-list
+CERT_TO_EFI_SIG_LIST ?= ./cert-to-efi-sig-list
+CERT_TO_EFI_HASH_LIST ?= ./cert-to-efi-hash-list
+HASH_TO_EFI_SIG_LIST ?= ./hash-to-efi-sig-list
MYGUID = 11111111-2222-3333-4444-123456789abc
INSTALL = install
BINDIR = $(DESTDIR)/usr/bin
@@ -75,34 +79,34 @@ endif
$(XXD) -i $< > $@
%.hash: %.efi hash-to-efi-sig-list
- ./hash-to-efi-sig-list $< $@
+ $(HASH_TO_EFI_SIG_LIST) $< $@
%-blacklist.esl: %.crt cert-to-efi-sig-list
- ./cert-to-efi-sig-list $< $@
+ $(CERT_TO_EFI_SIG_LIST) $< $@
%-hash-blacklist.esl: %.crt cert-to-efi-hash-list
- ./cert-to-efi-hash-list $< $@
+ $(CERT_TO_EFI_HASH_LIST) $< $@
%.esl: %.crt cert-to-efi-sig-list
- ./cert-to-efi-sig-list -g $(MYGUID) $< $@
+ $(CERT_TO_EFI_SIG_LIST) -g $(MYGUID) $< $@
getcert = $(shell if [ "$(1)" = "PK" -o "$(1)" = "KEK" ]; then echo "-c PK.crt -k PK.key"; else echo "-c KEK.crt -k KEK.key"; fi)
getvar = $(shell if [ "$(1)" = "PK" -o "$(1)" = "KEK" ]; then echo $(1); else echo db; fi)
%.auth: %.esl PK.crt KEK.crt sign-efi-sig-list
- ./sign-efi-sig-list $(call getcert,$*) $(call getvar,$*) $< $@
+ $(SIGN_EFI_SIG_LIST) $(call getcert,$*) $(call getvar,$*) $< $@
%-update.auth: %.esl PK.crt KEK.crt sign-efi-sig-list
- ./sign-efi-sig-list -a $(call getcert,$*) $(call getvar,$*) $< $@
+ $(SIGN_EFI_SIG_LIST) -a $(call getcert,$*) $(call getvar,$*) $< $@
%-pkupdate.auth: %.esl PK.crt sign-efi-sig-list
- ./sign-efi-sig-list -a -c PK.crt -k PK.key $(call getvar,$*) $< $@
+ $(SIGN_EFI_SIG_LIST) -a -c PK.crt -k PK.key $(call getvar,$*) $< $@
%-blacklist.auth: %-blacklist.esl KEK.crt sign-efi-sig-list
- ./sign-efi-sig-list -a -c KEK.crt -k KEK.key dbx $< $@
+ $(SIGN_EFI_SIG_LIST) -a -c KEK.crt -k KEK.key dbx $< $@
%-pkblacklist.auth: %-blacklist.esl PK.crt sign-efi-sig-list
- ./sign-efi-sig-list -a -c PK.crt -k PK.key dbx $< $@
+ $(SIGN_EFI_SIG_LIST) -a -c PK.crt -k PK.key dbx $< $@
%.o: %.c
$(CC) $(INCDIR) $(cflags) $(cppflags) -c $< -o $@
diff --git a/Makefile b/Makefile
index 15fc944..c4e0081 100644
--- a/Makefile
+++ b/Makefile
@@ -66,10 +66,10 @@ noPK.esl:
> noPK.esl
noPK.auth: noPK.esl PK.crt sign-efi-sig-list
- ./sign-efi-sig-list -t "$(shell date --date='1 second' +'%Y-%m-%d %H:%M:%S')" -c PK.crt -k PK.key PK $< $@
+ $(SIGN_EFI_SIG_LIST) -t "$(shell date --date='1 second' +'%Y-%m-%d %H:%M:%S')" -c PK.crt -k PK.key PK $< $@
ms-%.esl: ms-%.crt cert-to-efi-sig-list
- ./cert-to-efi-sig-list -g $(MSGUID) $< $@
+ $(CERT_TO_EFI_SIG_LIST) -g $(MSGUID) $< $@
hashlist.h: HashTool.hash
cat $^ > /tmp/tmp.hash
--
1.9.1

View File

@@ -0,0 +1,44 @@
From e909a2d4777a6fd2644ff89361539db141c0a67f Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Sat, 28 Jan 2017 13:42:28 +0800
Subject: [PATCH] Build DBX by default
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
Makefile | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile
index a1fc538..7f767c8 100644
--- a/Makefile
+++ b/Makefile
@@ -26,7 +26,7 @@ include Make.rules
EFISIGNED = $(patsubst %.efi,%-signed.efi,$(EFIFILES))
-all: $(EFIFILES) $(BINARIES) $(MANPAGES) noPK.auth $(KEYAUTH) \
+all: $(EFIFILES) $(BINARIES) $(MANPAGES) noPK.auth $(KEYAUTH) DBX.auth \
$(KEYUPDATEAUTH) $(KEYBLACKLISTAUTH) $(KEYHASHBLACKLISTAUTH)
@@ -49,7 +49,7 @@ lib/asn1/libasn1.a lib/asn1/libasn1-efi.a: FORCE
.SUFFIXES: .crt
-.KEEP: PK.crt KEK.crt DB.crt PK.key KEK.key DB.key PK.esl DB.esl KEK.esl \
+.KEEP: PK.crt KEK.crt DB.crt DBX.crt PK.key KEK.key DB.key PK.esl DB.esl KEK.esl DBX.esl \
$(EFIFILES)
LockDown.o: PK.h KEK.h DB.h DBX.h
@@ -116,7 +116,7 @@ flash-var: flash-var.o lib/lib.a
$(CC) $(ARCH3264) -o $@ $< lib/lib.a
clean:
- rm -f PK.* KEK.* DB.* $(EFIFILES) $(EFISIGNED) $(BINARIES) *.o *.so
+ rm -f PK.* KEK.* DB.* DBX.* $(EFIFILES) $(EFISIGNED) $(BINARIES) *.o *.so
rm -f noPK.*
rm -f doc/*.1
$(MAKE) -C lib clean
--
2.7.4

View File

@@ -0,0 +1,40 @@
From 95e167f432f1a6d8c96aeca73871122806007c9f Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Thu, 28 Apr 2016 11:21:33 +0800
Subject: [PATCH] Don't build PreLoader.efi
Upstream-Status: Pending
The upstream has an obvious build failure:
| PreLoader.c:45:2: error: too few arguments to function 'security_policy_install'
| status = security_policy_install();
| ^
| In file included from PreLoader.c:14:0:
| /buildarea3/jzhang0/projects/wrl8/intel-x86-64-gwp-scp/bitbake_build/tmp/work/x86_64-linux/efitools-native/1.7.0+gitAUTOINC+20a8fdc4ec-r0/git/include/security_policy.h:4:1: note: declared here
| security_policy_install(BOOLEAN (*override)(void), POLICY_FUNCTION allow, POLICY_FUNCTION deny);
| ^
We are waiting for the upstream fix and remove this workaround in next
refresh.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index b3bb73a..da363a6 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ BINARIES = cert-to-efi-sig-list sig-list-to-certs sign-efi-sig-list \
flash-var
ifeq ($(ARCH),x86_64)
-EFIFILES += PreLoader.efi
+#EFIFILES += PreLoader.efi
endif
MSGUID = 77FA9ABD-0359-4D32-BD60-28F4E78F784B
--
1.9.1

View File

@@ -0,0 +1,193 @@
From ab2eb06c1271e46e07add5a0b0a444353d45e055 Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Tue, 15 Mar 2016 21:28:33 +0800
Subject: [PATCH] Fix for the cross compilation
Upstream-Status: Pending
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
Make.rules | 52 +++++++++++++++++++++++++++++-----------------------
Makefile | 14 +++++++-------
2 files changed, 36 insertions(+), 30 deletions(-)
diff --git a/Make.rules b/Make.rules
index 88d5481..7e89332 100644
--- a/Make.rules
+++ b/Make.rules
@@ -13,21 +13,27 @@ ARCH3264 =
else
$(error unknown architecture $(ARCH))
endif
-INCDIR = -I$(TOPDIR)include/ -I/usr/include/efi -I/usr/include/efi/$(ARCH) -I/usr/include/efi/protocol
-CPPFLAGS = -DCONFIG_$(ARCH)
-CFLAGS = -O2 $(ARCH3264) -fpic -Wall -fshort-wchar -fno-strict-aliasing -fno-merge-constants -fno-stack-protector -ffreestanding -fno-stack-check
-LDFLAGS = -nostdlib
+INCDIR = -I$(TOPDIR)include/ -I$(INCDIR_PREFIX)/usr/include/efi -I$(INCDIR_PREFIX)/usr/include/efi/$(ARCH) -I$(INCDIR_PREFIX)/usr/include/efi/protocol
+cppflags = -DCONFIG_$(ARCH)
+cflags = -O2 $(ARCH3264) -fpic -Wall -fshort-wchar -fno-strict-aliasing -fno-merge-constants -fno-stack-protector -ffreestanding -fno-stack-check $(CFLAGS)
+ldflags = -nostdlib $(LDFLAGS)
CRTOBJ = crt0-efi-$(ARCH).o
CRTPATHS = /lib /lib64 /lib/efi /lib64/efi /usr/lib /usr/lib64 /usr/lib/efi /usr/lib64/efi
-CRTPATH = $(shell for f in $(CRTPATHS); do if [ -e $$f/$(CRTOBJ) ]; then echo $$f; break; fi; done)
+CRTPATH = $(shell for f in $(CRTPATHS); do if [ -e $(CRTPATH_PREFIX)/$$f/$(CRTOBJ) ]; then echo $(CRTPATH_PREFIX)/$$f; break; fi; done)
CRTOBJS = $(CRTPATH)/$(CRTOBJ)
# there's a bug in the gnu tools ... the .reloc section has to be
# aligned otherwise the file alignment gets screwed up
LDSCRIPT = elf_$(ARCH)_efi.lds
-LDFLAGS += -shared -Bsymbolic $(CRTOBJS) -L $(CRTPATH) -T $(LDSCRIPT)
+ldflags += -shared -Bsymbolic $(CRTOBJS) -L $(CRTPATH) -T $(LDSCRIPT)
+ldflags_openssl = $(addprefix -L$(CRTPATH_PREFIX),$(CRTPATHS))
LOADLIBES = -lefi -lgnuefi $(shell $(CC) $(ARCH3264) -print-libgcc-file-name)
FORMAT = --target=efi-app-$(ARCH)
OBJCOPY = objcopy
+NM = nm
+AR = ar
+OPENSSL = openssl
+SBSIGN = sbsign
+XXD = xxd
MYGUID = 11111111-2222-3333-4444-123456789abc
INSTALL = install
BINDIR = $(DESTDIR)/usr/bin
@@ -36,23 +42,23 @@ EFIDIR = $(DESTDIR)/usr/share/efitools/efi
DOCDIR = $(DESTDIR)/usr/share/efitools
# globally use EFI calling conventions (requires gcc >= 4.7)
-CFLAGS += -DGNU_EFI_USE_MS_ABI
+cflags += -DGNU_EFI_USE_MS_ABI
ifeq ($(ARCH),x86_64)
- CFLAGS += -DEFI_FUNCTION_WRAPPER -mno-red-zone
+ cflags += -DEFI_FUNCTION_WRAPPER -mno-red-zone
endif
ifeq ($(ARCH),ia32)
- CFLAGS += -mno-red-zone
+ cflags += -mno-red-zone
endif
ifeq ($(ARCH),arm)
- LDFLAGS += --defsym=EFI_SUBSYSTEM=0x0a
+ ldflags += --defsym=EFI_SUBSYSTEM=0x0a
FORMAT = -O binary
endif
ifeq ($(ARCH),aarch64)
- LDFLAGS += --defsym=EFI_SUBSYSTEM=0x0a
+ ldflags += --defsym=EFI_SUBSYSTEM=0x0a
FORMAT = -O binary
endif
@@ -61,12 +67,12 @@ endif
-j .rel -j .rela -j .rel.* -j .rela.* -j .rel* -j .rela* \
-j .reloc $(FORMAT) $*.so $@
%.so: %.o
- $(LD) $(LDFLAGS) $^ -o $@ $(LOADLIBES)
+ $(LD) $(ldflags) $^ -o $@ $(LOADLIBES)
# check we have no undefined symbols
- nm -D $@ | grep ' U ' && exit 1 || exit 0
+ ${NM} -D $@ | grep ' U ' && exit 1 || exit 0
%.h: %.auth
- ./xxdi.pl $< > $@
+ $(XXD) -i $< > $@
%.hash: %.efi hash-to-efi-sig-list
./hash-to-efi-sig-list $< $@
@@ -99,28 +105,28 @@ getvar = $(shell if [ "$(1)" = "PK" -o "$(1)" = "KEK" ]; then echo $(1); else ec
./sign-efi-sig-list -a -c PK.crt -k PK.key dbx $< $@
%.o: %.c
- $(CC) $(INCDIR) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
+ $(CC) $(INCDIR) $(cflags) $(cppflags) -c $< -o $@
%.efi.o: %.c
- $(CC) $(INCDIR) $(CFLAGS) $(CPPFLAGS) -fno-toplevel-reorder -DBUILD_EFI -c $< -o $@
+ $(CC) $(INCDIR) $(cflags) $(cppflags) -fno-toplevel-reorder -DBUILD_EFI -c $< -o $@
%.efi.s: %.c
- $(CC) -S $(INCDIR) $(CFLAGS) $(CPPFLAGS) -fno-toplevel-reorder -DBUILD_EFI -c $< -o $@
+ $(CC) -S $(INCDIR) $(cflags) $(cppflags) -fno-toplevel-reorder -DBUILD_EFI -c $< -o $@
%.crt:
- openssl req -new -x509 -newkey rsa:2048 -subj "/CN=$*/" -keyout $*.key -out $@ -days 3650 -nodes -sha256
+ $(OPENSSL) req -new -x509 -newkey rsa:2048 -subj "/CN=$*/" -keyout $*.key -out $@ -days 3650 -nodes -sha256
%.cer: %.crt
- openssl x509 -in $< -out $@ -outform DER
+ $(OPENSSL) x509 -in $< -out $@ -outform DER
%-subkey.csr:
- openssl req -new -newkey rsa:2048 -keyout $*-subkey.key -subj "/CN=Subkey $* of KEK/" -out $@ -nodes
+ $(OPENSSL) req -new -newkey rsa:2048 -keyout $*-subkey.key -subj "/CN=Subkey $* of KEK/" -out $@ -nodes
%-subkey.crt: %-subkey.csr KEK.crt
- openssl x509 -req -in $< -CA DB.crt -CAkey DB.key -set_serial 1 -out $@ -days 365
+ $(OPENSSL) x509 -req -in $< -CA DB.crt -CAkey DB.key -set_serial 1 -out $@ -days 365
%-signed.efi: %.efi DB.crt
- sbsign --key DB.key --cert DB.crt --output $@ $<
+ $(SBSIGN) --key DB.key --cert DB.crt --output $@ $<
##
# No need for KEK signing
@@ -129,7 +135,7 @@ getvar = $(shell if [ "$(1)" = "PK" -o "$(1)" = "KEK" ]; then echo $(1); else ec
# sbsign --key KEK.key --cert KEK.crt --output $@ $<
%.a:
- ar rcv $@ $^
+ $(AR) rcv $@ $^
doc/%.1: doc/%.1.in %
$(HELP2MAN) --no-info -i $< -o $@ ./$*
diff --git a/Makefile b/Makefile
index 774ee0a..46e4620 100644
--- a/Makefile
+++ b/Makefile
@@ -73,7 +73,7 @@ ms-%.esl: ms-%.crt cert-to-efi-sig-list
hashlist.h: HashTool.hash
cat $^ > /tmp/tmp.hash
- ./xxdi.pl /tmp/tmp.hash > $@
+ $(XXD) -i /tmp/tmp.hash > $@
rm -f /tmp/tmp.hash
@@ -88,28 +88,28 @@ HelloWorld.so: lib/lib-efi.a
ShimReplace.so: lib/lib-efi.a
cert-to-efi-sig-list: cert-to-efi-sig-list.o lib/lib.a
- $(CC) $(ARCH3264) -o $@ $< -lcrypto lib/lib.a
+ $(CC) $(ARCH3264) -o $@ $< $(ldflags_openssl) $(EXTRA_LDFLAGS) -lcrypto lib/lib.a
sig-list-to-certs: sig-list-to-certs.o lib/lib.a
- $(CC) $(ARCH3264) -o $@ $< -lcrypto lib/lib.a
+ $(CC) $(ARCH3264) -o $@ $< $(ldflags_openssl) $(EXTRA_LDFLAGS) -lcrypto lib/lib.a
sign-efi-sig-list: sign-efi-sig-list.o lib/lib.a
- $(CC) $(ARCH3264) -o $@ $< -lcrypto lib/lib.a
+ $(CC) $(ARCH3264) -o $@ $< $(ldflags_openssl) $(EXTRA_LDFLAGS) -lcrypto lib/lib.a
hash-to-efi-sig-list: hash-to-efi-sig-list.o lib/lib.a
$(CC) $(ARCH3264) -o $@ $< lib/lib.a
cert-to-efi-hash-list: cert-to-efi-hash-list.o lib/lib.a
- $(CC) $(ARCH3264) -o $@ $< -lcrypto lib/lib.a
+ $(CC) $(ARCH3264) -o $@ $< $(ldflags_openssl) $(EXTRA_LDFLAGS) -lcrypto lib/lib.a
efi-keytool: efi-keytool.o lib/lib.a
$(CC) $(ARCH3264) -o $@ $< lib/lib.a
efi-readvar: efi-readvar.o lib/lib.a
- $(CC) $(ARCH3264) -o $@ $< -lcrypto lib/lib.a
+ $(CC) $(ARCH3264) -o $@ $< $(ldflags_openssl) $(EXTRA_LDFLAGS) -lcrypto lib/lib.a
efi-updatevar: efi-updatevar.o lib/lib.a
- $(CC) $(ARCH3264) -o $@ $< -lcrypto lib/lib.a
+ $(CC) $(ARCH3264) -o $@ $< $(ldflags_openssl) $(EXTRA_LDFLAGS) -lcrypto lib/lib.a
flash-var: flash-var.o lib/lib.a
$(CC) $(ARCH3264) -o $@ $< lib/lib.a
--
1.9.1

View File

@@ -0,0 +1,28 @@
From f2e4ff4e63f4a5f8a4452c970ca271091eeaec7d Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Sun, 18 Jun 2017 23:35:09 +0800
Subject: [PATCH] Fix help2man error
This issue may be caused by the poky compiler.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
Make.rules | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/Make.rules b/Make.rules
index 38c7a22..bda5518 100644
--- a/Make.rules
+++ b/Make.rules
@@ -140,5 +140,7 @@ getvar = $(shell if [ "$(1)" = "PK" -o "$(1)" = "KEK" ]; then echo $(1); else ec
%.a:
$(AR) rcv $@ $^
+HELP2MAN_PROG_PREFIX ?= .
+
doc/%.1: doc/%.1.in %
- $(HELP2MAN) --no-discard-stderr --no-info -i $< -o $@ ./$*
+ $(HELP2MAN) --no-discard-stderr --no-info -i $< -o $@ $(HELP2MAN_PROG_PREFIX)/$*
--
2.7.5

View File

@@ -0,0 +1,25 @@
From 546b8c36301bdcf540b3b027fd25baa9cff2abdc Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Wed, 23 Mar 2016 19:44:51 +0800
Subject: [PATCH] Fix help2man failure
Add --no-discard-stderr to work around the error.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
Make.rules | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Make.rules b/Make.rules
index 4aa7650..21926b0 100644
--- a/Make.rules
+++ b/Make.rules
@@ -142,4 +142,4 @@ getvar = $(shell if [ "$(1)" = "PK" -o "$(1)" = "KEK" ]; then echo $(1); else ec
$(AR) rcv $@ $^
doc/%.1: doc/%.1.in %
- $(HELP2MAN) --no-info -i $< -o $@ ./$*
+ $(HELP2MAN) --no-discard-stderr --no-info -i $< -o $@ ./$*
--
1.9.1

View File

@@ -0,0 +1,28 @@
From 52228c24af681463d73d5bd8454872b3e811855b Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Tue, 15 Mar 2016 21:07:31 +0800
Subject: [PATCH] Fix the wrong dependency for %-blacklist.esl
Upstream-Status: Pending
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
Make.rules | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Make.rules b/Make.rules
index 48b02e4..08a2489 100644
--- a/Make.rules
+++ b/Make.rules
@@ -77,7 +77,7 @@ endif
%.hash: %.efi hash-to-efi-sig-list
./hash-to-efi-sig-list $< $@
-%-blacklist.esl: %.crt cert-to-efi-hash-list
+%-blacklist.esl: %.crt cert-to-efi-sig-list
./cert-to-efi-sig-list $< $@
%-hash-blacklist.esl: %.crt cert-to-efi-hash-list
--
1.9.1

View File

@@ -0,0 +1,80 @@
From 872a9d96386b819d2c5fd7581d2bdaf7ea61a5f8 Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Tue, 15 Mar 2016 17:12:24 +0800
Subject: [PATCH] Kill all the build warning caused by implicit declaration of
function
Upstream-Status: Pending
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
Loader.c | 1 +
cert-to-efi-hash-list.c | 2 +-
flash-var.c | 2 ++
lib/pecoff.c | 1 +
sign-efi-sig-list.c | 2 ++
5 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/Loader.c b/Loader.c
index 1f9201a..044469a 100644
--- a/Loader.c
+++ b/Loader.c
@@ -9,6 +9,7 @@
#include <efi.h>
#include <efilib.h>
+#include <execute.h>
#include <simple_file.h>
#include <pecoff.h>
#include <sha256.h>
diff --git a/cert-to-efi-hash-list.c b/cert-to-efi-hash-list.c
index d4484f9..3792553 100644
--- a/cert-to-efi-hash-list.c
+++ b/cert-to-efi-hash-list.c
@@ -3,7 +3,7 @@
*
* see COPYING file
*/
-
+#define _GNU_SOURCE
#include <stdint.h>
#define __STDC_VERSION__ 199901L
diff --git a/flash-var.c b/flash-var.c
index aa10ae6..10429bc 100644
--- a/flash-var.c
+++ b/flash-var.c
@@ -1,3 +1,5 @@
+#define _GNU_SOURCE
+
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
diff --git a/lib/pecoff.c b/lib/pecoff.c
index 26d9dcf..10b898a 100644
--- a/lib/pecoff.c
+++ b/lib/pecoff.c
@@ -59,6 +59,7 @@
#endif
#endif
+#include <execute.h>
#include <pecoff.h>
#include <guid.h>
#include <simple_file.h>
diff --git a/sign-efi-sig-list.c b/sign-efi-sig-list.c
index e19ef97..5abcf27 100644
--- a/sign-efi-sig-list.c
+++ b/sign-efi-sig-list.c
@@ -3,6 +3,8 @@
*
* see COPYING file
*/
+#define _GNU_SOURCE
+
#include <stdint.h>
#define __STDC_VERSION__ 199901L
#include <efi.h>
--
1.9.1

View File

@@ -0,0 +1,47 @@
From e259aecc645c6dd4c194a64d607124cd5a714f9a Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Wed, 15 Feb 2017 14:52:07 +0800
Subject: [PATCH] LockDown: disable the entrance into BIOS setup to re-enable
secure boot
In most cases, this step is not necessary.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
LockDown.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/LockDown.c b/LockDown.c
index 13c626f..fbde3f2 100644
--- a/LockDown.c
+++ b/LockDown.c
@@ -20,6 +20,11 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
EFI_STATUS efi_status;
UINT8 SecureBoot, SetupMode;
UINTN DataSize = sizeof(SetupMode);
+ /* This controls whether it is required to enter into BIOS setup in
+ * order to re-enable UEFI secure boot. This operation is unnecessary
+ * in most cases.
+ */
+ UINTN NeedSetAttempt = 0;
InitializeLib(image, systab);
@@ -110,12 +115,12 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
* UEFI secure boot in BIOS setup.
*/
Print(L"Prepare to execute system warm reset after 3 seconds ...\n");
- if (!SecureBoot)
+ if (NeedSetAttempt && !SecureBoot)
Print(L"After warm reset, enter to BIOS setup to enable UEFI Secure Boot.\n");
BS->Stall(3000000);
- if (!SecureBoot)
+ if (NeedSetAttempt && !SecureBoot)
SETOSIndicationsAndReboot(EFI_OS_INDICATIONS_BOOT_TO_FW_UI);
else
RT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
--
2.7.4

View File

@@ -0,0 +1,85 @@
From 49b6a0bf2b9c69d1fd682fbc9d2ad7a7f6abee77 Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Fri, 22 Apr 2016 16:28:05 +0800
Subject: [PATCH] LockDown: enable the enrollment for DBX
Upstream-Status: Pending
DBX acting as blacklist now is able to be enrolled.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
LockDown.c | 16 +++++++++++-----
Makefile | 4 +++-
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/LockDown.c b/LockDown.c
index 821985c..fec2e79 100644
--- a/LockDown.c
+++ b/LockDown.c
@@ -12,6 +12,7 @@
#include "PK.h"
#include "KEK.h"
#include "DB.h"
+#include "DBX.h"
EFI_STATUS
efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
@@ -47,6 +48,7 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
return efi_status;
}
Print(L"Created KEK Cert\n");
+
efi_status = RT->SetVariable(L"db", &SIG_DB,
EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
@@ -58,15 +60,19 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
return efi_status;
}
Print(L"Created db Cert\n");
-#if 0
- /* testing revocation ... this will revoke the certificate
- * we just enrolled in db */
- efi_status = SetSecureVariable(L"dbx", DB_cer, DB_cer_len, SIG_DB, 0);
+
+ efi_status = RT->SetVariable(L"dbx", &SIG_DB,
+ EFI_VARIABLE_NON_VOLATILE
+ | EFI_VARIABLE_RUNTIME_ACCESS
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,
+ DBX_auth_len, DBX_auth);
if (efi_status != EFI_SUCCESS) {
Print(L"Failed to enroll dbx: %d\n", efi_status);
return efi_status;
}
-#endif
+ Print(L"Created dbx Cert\n");
+
/* PK must be updated with a signed copy of itself */
efi_status = RT->SetVariable(L"PK", &GV_GUID,
EFI_VARIABLE_NON_VOLATILE
diff --git a/Makefile b/Makefile
index b3bb73a..e189866 100644
--- a/Makefile
+++ b/Makefile
@@ -53,7 +53,7 @@ lib/asn1/libasn1.a lib/asn1/libasn1-efi.a: FORCE
.KEEP: PK.crt KEK.crt DB.crt PK.key KEK.key DB.key PK.esl DB.esl KEK.esl \
$(EFIFILES)
-LockDown.o: PK.h KEK.h DB.h
+LockDown.o: PK.h KEK.h DB.h DBX.h
PreLoader.o: hashlist.h
PK.h: PK.auth
@@ -62,6 +62,8 @@ KEK.h: KEK.auth
DB.h: DB.auth
+DBX.h: DBX.auth
+
noPK.esl:
> noPK.esl
--
1.9.1

View File

@@ -0,0 +1,44 @@
From b2897e78c7910f0e55f4861542155d2817c15bf4 Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Fri, 25 Mar 2016 10:52:34 +0800
Subject: [PATCH] LockDown: run system warm reset after the key provision
success
Upstream-Status: Pending
In addition, BIOS would stop at its setup screen. The end user can thus
enable UEFI secure boot immediately.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
LockDown.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/LockDown.c b/LockDown.c
index 29df9de..821985c 100644
--- a/LockDown.c
+++ b/LockDown.c
@@ -99,5 +99,20 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
}
Print(L"Platform %s set to boot securely\n", SecureBoot ? L"is" : L"is not");
+ /* Reset system to go back the real UEFI secure boot flow.
+ * If SecureBoot is still false, the user needs to turn on
+ * UEFI secure boot in BIOS setup.
+ */
+ Print(L"Prepare to execute system warm reset after 3 seconds ...\n");
+ if (!SecureBoot)
+ Print(L"After warm reset, enter to BIOS setup to enable UEFI Secure Boot.\n");
+
+ BS->Stall(3000000);
+
+ if (!SecureBoot)
+ SETOSIndicationsAndReboot(EFI_OS_INDICATIONS_BOOT_TO_FW_UI);
+ else
+ RT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
+
return EFI_SUCCESS;
}
--
1.9.1

View File

@@ -0,0 +1,94 @@
From 28eb6a3118c3c843b41732ec3cf5167fe027daba Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Tue, 17 Jan 2017 12:48:27 +0800
Subject: [PATCH] LockDown: show the error message with 3-sec timeout
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
LockDown.c | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/LockDown.c b/LockDown.c
index fec2e79..13c626f 100644
--- a/LockDown.c
+++ b/LockDown.c
@@ -27,12 +27,12 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
if (efi_status != EFI_SUCCESS) {
Print(L"No SetupMode variable ... is platform secure boot enabled?\n");
- return EFI_SUCCESS;
+ goto out;
}
if (!SetupMode) {
Print(L"Platform is not in Setup Mode, cannot install Keys\n");
- return EFI_SUCCESS;
+ goto out;
}
Print(L"Platform is in Setup Mode\n");
@@ -45,7 +45,7 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
KEK_auth_len, KEK_auth);
if (efi_status != EFI_SUCCESS) {
Print(L"Failed to enroll KEK: %d\n", efi_status);
- return efi_status;
+ goto out;
}
Print(L"Created KEK Cert\n");
@@ -57,7 +57,7 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
DB_auth_len, DB_auth);
if (efi_status != EFI_SUCCESS) {
Print(L"Failed to enroll db: %d\n", efi_status);
- return efi_status;
+ goto out;
}
Print(L"Created db Cert\n");
@@ -69,7 +69,7 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
DBX_auth_len, DBX_auth);
if (efi_status != EFI_SUCCESS) {
Print(L"Failed to enroll dbx: %d\n", efi_status);
- return efi_status;
+ goto out;
}
Print(L"Created dbx Cert\n");
@@ -84,14 +84,14 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
if (efi_status != EFI_SUCCESS) {
Print(L"Failed to enroll PK: %d\n", efi_status);
- return efi_status;
+ goto out;
}
Print(L"Created PK Cert\n");
/* enrolling the PK should put us in SetupMode; check this */
efi_status = RT->GetVariable(L"SetupMode", &GV_GUID, NULL, &DataSize, &SetupMode);
if (efi_status != EFI_SUCCESS) {
Print(L"Failed to get SetupMode variable: %d\n", efi_status);
- return efi_status;
+ goto out;
}
Print(L"Platform is in %s Mode\n", SetupMode ? L"Setup" : L"User");
@@ -101,7 +101,7 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
if (efi_status != EFI_SUCCESS) {
Print(L"Failed to get SecureBoot variable: %d\n", efi_status);
- return efi_status;
+ goto out;
}
Print(L"Platform %s set to boot securely\n", SecureBoot ? L"is" : L"is not");
@@ -121,4 +121,8 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
RT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
return EFI_SUCCESS;
+
+out:
+ BS->Stall(3000000);
+ return efi_status;
}
--
2.7.4

View File

@@ -0,0 +1,33 @@
From 923b9cb2bfe81ff29a29d46bfc4e3fe172e0e5ae Mon Sep 17 00:00:00 2001
From: Yunguo Wei <yunguo.wei@windriver.com>
Date: Tue, 17 Jan 2017 17:24:51 +0800
Subject: [PATCH] Makefile: do not build signed efi image
Signed-off-by: Yunguo Wei <yunguo.wei@windriver.com>
---
Makefile | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile
index addb593..a1fc538 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,4 @@
-EFIFILES = HelloWorld.efi LockDown.efi Loader.efi ReadVars.efi UpdateVars.efi \
- KeyTool.efi HashTool.efi SetNull.efi ShimReplace.efi
+EFIFILES = LockDown.efi
BINARIES = cert-to-efi-sig-list sig-list-to-certs sign-efi-sig-list \
hash-to-efi-sig-list efi-readvar efi-updatevar cert-to-efi-hash-list \
flash-var
@@ -27,7 +26,7 @@ include Make.rules
EFISIGNED = $(patsubst %.efi,%-signed.efi,$(EFIFILES))
-all: $(EFISIGNED) $(BINARIES) $(MANPAGES) noPK.auth $(KEYAUTH) \
+all: $(EFIFILES) $(BINARIES) $(MANPAGES) noPK.auth $(KEYAUTH) \
$(KEYUPDATEAUTH) $(KEYBLACKLISTAUTH) $(KEYHASHBLACKLISTAUTH)
--
2.7.4

View File

@@ -0,0 +1,51 @@
From 959e4395b5524babb27c2bf95fa37b990d79b663 Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Thu, 28 Apr 2016 12:52:22 +0800
Subject: [PATCH] Reuse xxdi.pl
The missing File::Slurp required by xxdi.pl is added. To avoid introducing
an extra xxd package, remove the support of using xxd.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
Make.rules | 3 +--
Makefile | 2 +-
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/Make.rules b/Make.rules
index 21926b0..38c7a22 100644
--- a/Make.rules
+++ b/Make.rules
@@ -33,7 +33,6 @@ NM = nm
AR = ar
OPENSSL = openssl
SBSIGN = sbsign
-XXD = xxd
SIGN_EFI_SIG_LIST ?= ./sign-efi-sig-list
CERT_TO_EFI_SIG_LIST ?= ./cert-to-efi-sig-list
CERT_TO_EFI_HASH_LIST ?= ./cert-to-efi-hash-list
@@ -76,7 +75,7 @@ endif
${NM} -D $@ | grep ' U ' && exit 1 || exit 0
%.h: %.auth
- $(XXD) -i $< > $@
+ ./xxdi.pl $< > $@
%.hash: %.efi hash-to-efi-sig-list
$(HASH_TO_EFI_SIG_LIST) $< $@
diff --git a/Makefile b/Makefile
index da363a6..2534b47 100644
--- a/Makefile
+++ b/Makefile
@@ -73,7 +73,7 @@ ms-%.esl: ms-%.crt cert-to-efi-sig-list
hashlist.h: HashTool.hash
cat $^ > /tmp/tmp.hash
- $(XXD) -i /tmp/tmp.hash > $@
+ ./xxdi.pl /tmp/tmp.hash > $@
rm -f /tmp/tmp.hash
--
1.9.1

View File

@@ -0,0 +1,83 @@
require efitools.inc
SRC_URI_append += " \
file://LockDown-enable-the-enrollment-for-DBX.patch \
file://LockDown-show-the-error-message-with-3-sec-timeout.patch \
file://Makefile-do-not-build-signed-efi-image.patch \
file://Build-DBX-by-default.patch \
file://LockDown-disable-the-entrance-into-BIOS-setup-to-re-.patch \
file://Fix-help2man-error.patch \
"
COMPATIBLE_HOST = '(i.86|x86_64).*-linux'
inherit user-key-store deploy
# The generated native binaries are used during native and target build
DEPENDS += "${BPN}-native gnu-efi openssl"
RDEPENDS_${PN}_append += " \
parted mtools coreutils util-linux openssl libcrypto \
"
EXTRA_OEMAKE_append += " \
INCDIR_PREFIX='${STAGING_DIR_TARGET}' \
CRTPATH_PREFIX='${STAGING_DIR_TARGET}' \
SIGN_EFI_SIG_LIST='${STAGING_BINDIR_NATIVE}/sign-efi-sig-list' \
CERT_TO_EFI_SIG_LIST='${STAGING_BINDIR_NATIVE}/cert-to-efi-sig-list' \
CERT_TO_EFI_HASH_LIST='${STAGING_BINDIR_NATIVE}/cert-to-efi-hash-list' \
HASH_TO_EFI_SIG_LIST='${STAGING_BINDIR_NATIVE}/hash-to-efi-sig-list' \
MYGUID='${UEFI_SIG_OWNER_GUID}' \
HELP2MAN_PROG_PREFIX='${STAGING_BINDIR_NATIVE}' \
"
python do_prepare_signing_keys() {
if d.expand('${UEFI_SB}') != '1':
return
# Prepare PK, KEK and DB for LockDown.efi.
if uks_signing_model(d) in ('sample', 'user'):
dir = uefi_sb_keys_dir(d)
else:
dir = d.expand('${SAMPLE_UEFI_SB_KEYS_DIR}/')
import shutil
for _ in ('PK', 'KEK', 'DB'):
shutil.copyfile(dir + _ + '.pem', d.expand('${S}/') + _ + '.crt')
shutil.copyfile(dir + _ + '.key', d.expand('${S}/') + _ + '.key')
# Make sure LockDown.efi contains the DB and KEK from Microsoft.
if "${@bb.utils.contains('DISTRO_FEATURES', 'msft', '1', '0', d)}" == '1':
shutil.copyfile(d.expand('${MSFT_DB_CERT}'), d.expand('${S}/DB.crt'))
shutil.copyfile(d.expand('${MSFT_KEK_CERT}'), d.expand('${S}/KEK.crt'))
path = create_uefi_dbx(d)
if path:
with open(d.expand('${S}/DBX.crt'), 'w') as f:
pass
shutil.copyfile(path, d.expand('${S}/DBX.esl'))
# Cheat the Makefile to avoid running this rule:
# %.esl: %.crt cert-to-efi-sig-list
# $(CERT_TO_EFI_SIG_LIST) -g $(MYGUID) $< $@
import time, os
tm = time.strptime('2038-01-01 00:00:00', \
'%Y-%m-%d %H:%M:%S')
time_stamp = time.mktime(tm)
os.utime(d.expand('${S}/DBX.esl'), (time_stamp, time_stamp))
}
addtask prepare_signing_keys after do_configure before do_compile
do_install_append() {
install -d ${D}${EFI_BOOT_PATH}
install -m 0755 ${D}${datadir}/efitools/efi/LockDown.efi ${D}${EFI_BOOT_PATH}
}
do_deploy() {
install -d ${DEPLOYDIR}
install -m 0600 ${D}${EFI_BOOT_PATH}/LockDown.efi "${DEPLOYDIR}"
}
addtask deploy after do_install before do_build

View File

@@ -0,0 +1,67 @@
From aecadf65c4d3dea68e55605ff5f0c3eb90206488 Mon Sep 17 00:00:00 2001
From: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
Date: Fri, 27 Mar 2015 08:01:41 -0700
Subject: [PATCH 1/7] pe32.h: add header structures for TE and DOS executables
Upstream-Status: Inappropriate [embedded specific]
Add header structures to describe the Terse Executable format and
the DOS header format for executable images.
These definitions are needed in subsequent commits to parse and
verify the identity of the executable image when utilizing a shim
to boot LUV.
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
include/grub/efi/pe32.h | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
index c3efa9b..c1c3483 100644
--- a/include/grub/efi/pe32.h
+++ b/include/grub/efi/pe32.h
@@ -313,4 +313,40 @@ struct grub_pe32_reloc
#define GRUB_PE32_REL_I386_DIR32 0x6
#define GRUB_PE32_REL_I386_REL32 0x14
+struct grub_te_header
+{
+ grub_uint16_t signature;
+ grub_uint16_t machine;
+ grub_uint8_t num_sections;
+ grub_uint8_t subsystem;
+ grub_uint16_t stripped_size;
+ grub_uint32_t entry_point;
+ grub_uint32_t code_base;
+ grub_uint64_t image_base;
+ struct grub_pe32_data_directory data_directory[2];
+};
+
+struct grub_dos_header
+{
+ grub_uint16_t magic;
+ grub_uint16_t cblp;
+ grub_uint16_t cp;
+ grub_uint16_t crlc;
+ grub_uint16_t cparhdr;
+ grub_uint16_t minalloc;
+ grub_uint16_t maxalloc;
+ grub_uint16_t ss;
+ grub_uint16_t sp;
+ grub_uint16_t csum;
+ grub_uint16_t ip;
+ grub_uint16_t cs;
+ grub_uint16_t lfarlc;
+ grub_uint16_t ovno;
+ grub_uint16_t res[4];
+ grub_uint16_t oemid;
+ grub_uint16_t oeminfo;
+ grub_uint16_t res2[10];
+ grub_uint32_t lfanew;
+};
+
#endif /* ! GRUB_EFI_PE32_HEADER */
--
1.9.1

View File

@@ -0,0 +1,161 @@
From 2341c2d2cf2ee67b036d21aa9b12b71bea84495f Mon Sep 17 00:00:00 2001
From: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
Date: Fri, 27 Mar 2015 08:09:58 -0700
Subject: [PATCH 2/7] shim: add needed data structures
Upstream-Status: Inappropriate [embedded specific]
Add the needed data structures for shim to load, parse, relocate and
execute a binary. This includes file-parsing structures, an identifier for
the UEFI protocol for image verification under secure boot provided by shim.
Shim is thin loader developed by Matthew Garret
(https://github.com/rhinstaller/shim). This code was ported from such project.
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
include/grub/efi/shim.h | 132 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 132 insertions(+)
create mode 100644 include/grub/efi/shim.h
diff --git a/include/grub/efi/shim.h b/include/grub/efi/shim.h
new file mode 100644
index 0000000..4b92a00
--- /dev/null
+++ b/include/grub/efi/shim.h
@@ -0,0 +1,132 @@
+/*
+ * shim.h - interface to shim: UEFI first-stage bootloader
+ *
+ * Copyright 2015 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Significant portions of this code are derived from Red Hat shim: UEFI
+ * first-stage bootloader.
+ * (https://github.com/rhinstaller/shim) and are Copyright 2012 Red Hat, Inc
+ */
+
+#ifndef GRUB_SHIM_HEADER
+#define GRUB_SHIM_HEADER 1
+
+#include <grub/efi/pe32.h>
+
+struct grub_nt_headers32
+{
+ grub_efi_uint32_t signature;
+ struct grub_pe32_coff_header file_hdr;
+ struct grub_pe32_optional_header opt_hdr;
+};
+
+struct grub_nt_headers64
+{
+ grub_efi_uint32_t signature;
+ struct grub_pe32_coff_header file_hdr;
+ struct grub_pe64_optional_header opt_hdr;
+};
+
+struct grub_image_base_relocation
+{
+ grub_efi_uint32_t virtual_address;
+ grub_efi_uint32_t block_size;
+};
+
+struct grub_shim_pe_coff_loader_image_context {
+ grub_efi_uint64_t image_address;
+ grub_efi_uint64_t image_size;
+ grub_efi_uint64_t entry_point;
+ grub_efi_uintn_t header_size;
+ grub_efi_uint16_t image_type;
+ grub_efi_uint16_t num_sections;
+ struct grub_pe32_section_table *first_section;
+ struct grub_pe32_data_directory *reloc_dir;
+ struct grub_pe32_data_directory *sec_dir;
+ grub_efi_uint64_t number_of_rva_and_sizes;
+ union grub_shim_optional_header_union *pe_hdr;
+};
+
+struct grub_shim_lock
+{
+ grub_efi_status_t
+ (*verify) (void *buffer,
+ grub_uint32_t size);
+
+ grub_efi_status_t
+ (*hash) (grub_int8_t *data,
+ grub_int32_t datasize,
+ struct grub_shim_pe_coff_loader_image_context *context,
+ grub_uint8_t sha256hash,
+ grub_uint8_t sha1hash);
+
+ grub_efi_status_t
+ (*context) (void *data,
+ grub_uint32_t datasize,
+ struct grub_shim_pe_coff_loader_image_context *context);
+};
+
+union grub_shim_optional_header_union
+{
+ struct grub_nt_headers32 pe32;
+ struct grub_nt_headers64 pe32plus;
+ struct grub_te_header te;
+};
+
+#define GRUB_EFI_SHIM_PROTOCOL_GUID \
+ { 0x605dab50, 0xe046, 0x4300, \
+ { 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } \
+ }
+
+#define SIGNATURE_16(A, B) ((A) | (B << 8))
+#define SIGNATURE_32(A, B, C, D) (SIGNATURE_16 (A, B) | (SIGNATURE_16 (C, D) << 16))
+
+#define EFI_IMAGE_DOS_SIGNATURE SIGNATURE_16('M', 'Z')
+#define EFI_IMAGE_NT_SIGNATURE SIGNATURE_32('P', 'E', '\0', '\0')
+
+#define EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC 5
+
+#define ALIGN_VALUE(Value, Alignment) ((Value) + (((Alignment) - (Value)) & ((Alignment) - 1)))
+#define ALIGN_POINTER(Pointer, Alignment) ((void *) (ALIGN_VALUE ((grub_efi_uintn_t)(Pointer), (Alignment))))
+
+/* Based relocation types. */
+
+#define EFI_IMAGE_REL_BASED_ABSOLUTE 0
+#define EFI_IMAGE_REL_BASED_HIGH 1
+#define EFI_IMAGE_REL_BASED_LOW 2
+#define EFI_IMAGE_REL_BASED_HIGHLOW 3
+#define EFI_IMAGE_REL_BASED_HIGHADJ 4
+#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR 5
+#define EFI_IMAGE_REL_BASED_ARM_MOV32A 5
+#define EFI_IMAGE_REL_BASED_ARM_MOV32T 7
+#define EFI_IMAGE_REL_BASED_IA64_IMM64 9
+#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR16 9
+#define EFI_IMAGE_REL_BASED_DIR64 10
+
+
+#endif /* ! GRUB_SHIM_HEADER */
--
1.9.1

View File

@@ -0,0 +1,81 @@
From 3b75fa5071e4b1a40510669119791928859b46e7 Mon Sep 17 00:00:00 2001
From: Matt Fleming <matt.fleming@intel.com>
Date: Fri, 27 Mar 2015 08:11:19 -0700
Subject: [PATCH 3/7] efi: chainloader: implement an UEFI Exit service for shim
in grub
Upstream-Status: Inappropriate [embedded specific]
When exiting, grub will call the UEFI boot-time service Exit. The
effect of this is that UEFI will jump to the entry point of the
UEFI started image. If we execute an image using shim within grub,
shim takes care of loading/parsing/relocating/executing the image.
Under this scenario, we also need to take care of the Exit call. Thus,
we need to reimplement the function to make sure we perform a jump
to the instruction after which shim executed the image.
Once we have taken care of the exit of the shim-executed image
the system Exit call is restored.
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
grub-core/kern/x86_64/efi/callwrap.S | 23 +++++++++++++++++++++++
include/grub/efi/api.h | 4 ++++
2 files changed, 27 insertions(+)
diff --git a/grub-core/kern/x86_64/efi/callwrap.S b/grub-core/kern/x86_64/efi/callwrap.S
index 2df95dd..f0f1dd8 100644
--- a/grub-core/kern/x86_64/efi/callwrap.S
+++ b/grub-core/kern/x86_64/efi/callwrap.S
@@ -48,6 +48,26 @@ FUNCTION(efi_wrap_1)
addq $48, %rsp
ret
+FUNCTION(efi_call_foo)
+ pushq %rbp
+ pushq %r12
+ pushq %r13
+ pushq %r14
+ pushq %r15
+ movq %rsp, saved_sp(%rip)
+ subq $48, %rsp
+ mov %rsi, %rcx
+ call *%rdi
+
+FUNCTION(efi_shim_exit)
+ movq saved_sp(%rip), %rsp
+ popq %r15
+ popq %r14
+ popq %r13
+ popq %r12
+ popq %rbp
+ ret
+
FUNCTION(efi_wrap_2)
subq $48, %rsp
mov %rsi, %rcx
@@ -127,3 +147,6 @@ FUNCTION(efi_wrap_10)
call *%rdi
addq $96, %rsp
ret
+
+ .data
+saved_sp: .quad 0
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index 26127de..374d88b 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -1437,6 +1437,10 @@ typedef struct grub_efi_block_io grub_efi_block_io_t;
grub_uint64_t EXPORT_FUNC(efi_wrap_0) (void *func);
grub_uint64_t EXPORT_FUNC(efi_wrap_1) (void *func, grub_uint64_t arg1);
+grub_efi_status_t EXPORT_FUNC(efi_shim_exit) (grub_efi_handle_t handle, grub_efi_status_t exit_status,
+ grub_efi_uintn_t exit_data_size, grub_efi_char16_t *exit_data) __attribute__((noreturn));
+grub_uint64_t EXPORT_FUNC(efi_call_foo) (void *func, grub_uint64_t arg1,
+ grub_uint64_t arg2);
grub_uint64_t EXPORT_FUNC(efi_wrap_2) (void *func, grub_uint64_t arg1,
grub_uint64_t arg2);
grub_uint64_t EXPORT_FUNC(efi_wrap_3) (void *func, grub_uint64_t arg1,
--
1.9.1

View File

@@ -0,0 +1,582 @@
From e097b4e25469aabdceac79c45cca27029824c1b5 Mon Sep 17 00:00:00 2001
From: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
Date: Fri, 27 Mar 2015 08:19:21 -0700
Subject: [PATCH 4/7] efi: chainloader: port shim to grub
Upstream-Status: Inappropriate [embedded specific]
Shim is a thin loader to execute signed binaries under the
chain of trust of UEFI secure boot. Before executing the image,
shim verifies that such image is signed with any of the Machine
Owner Keys (MOKs). If the verification is successful, shim will
load, parse, relocate and execute the image.
Shim is useful in case the user does not want to modify the UEFI
database of valid certificates (DB).
This commit ports Matthew Garret's code from shim to grub in order
to provide to grub the capability of load and execute trusted
binaries. This is useful in case we need to chainload two bootloaders.
Shim can be found here: https://github.com/rhinstaller/shim
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
grub-core/loader/efi/chainloader.c | 534 +++++++++++++++++++++++++++++++++++++
1 file changed, 534 insertions(+)
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index 3f3e6e3..bd83859 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -32,6 +32,7 @@
#include <grub/efi/api.h>
#include <grub/efi/efi.h>
#include <grub/efi/disk.h>
+#include <grub/efi/shim.h>
#include <grub/command.h>
#include <grub/i18n.h>
#include <grub/net.h>
@@ -45,6 +46,539 @@ static grub_efi_uintn_t pages;
static grub_efi_device_path_t *file_path;
static grub_efi_handle_t image_handle;
static grub_efi_char16_t *cmdline;
+static grub_int32_t shim_used;
+static grub_efi_physical_address_t shim_buffer;
+static grub_efi_uintn_t shim_pages;
+static grub_efi_loaded_image_t shim_li_bak;
+static grub_efi_status_t (*shim_entry_point) (grub_efi_handle_t image_handle,
+ grub_efi_system_table_t *systab);
+
+static const grub_uint16_t
+grub_shim_machine_type =
+#if defined(__x86_64__)
+ GRUB_PE32_MACHINE_X86_64;
+#elif defined(__aarch64__)
+ IMAGE_FILE_MACHINE_ARM64;
+#elif defined(__arm__)
+ IMAGE_FILE_MACHINE_ARMTHUMB_MIXED;
+#elif defined(__i386__) || defined(__i486__) || defined(__i686__)
+ GRUB_PE32_MACHINE_I386;
+#elif defined(__ia64__)
+ GRUB_PE32_MACHINE_IA64;
+#else
+#error this architecture is not supported by shim chainloader
+#endif
+
+static grub_efi_guid_t grub_shim_protocol_guid = GRUB_EFI_SHIM_PROTOCOL_GUID;
+
+static grub_int32_t
+grub_shim_allow_64_bit (void)
+{
+/* TODO: what is the definition for aarch64? */
+#if defined(__x86_64__)
+ return 1;
+#elif defined(__i386__) || defined(__i686__)
+/* TODO: find out what to do with in_protocol */
+ return 0;
+#else /* assuming everything else is 32-bit... */
+ return 0;
+#endif
+}
+
+static grub_int32_t
+grub_shim_allow_32_bit (void)
+{
+/* TODO: what is the definition for aarch64? */
+#if defined(__x86_64__)
+/* TODO: find out what to do with in_protocol */
+ return 0;
+#elif defined(__i386__) || defined(__i686__)
+ return 1;
+#else /* assuming everything else is 32-bit... */
+ return 1;
+#endif
+}
+
+static grub_int32_t
+grub_shim_image_is_64_bit (union grub_shim_optional_header_union *pe_hdr)
+{
+ /* .Magic is the same offset in all cases */
+ if (pe_hdr->pe32plus.opt_hdr.magic == GRUB_PE32_PE64_MAGIC)
+ return 1;
+ return 0;
+}
+
+static grub_int32_t
+grub_shim_image_is_loadable (union grub_shim_optional_header_union *pe_hdr)
+{
+ /* If the machine type doesn't match the binary, bail, unless
+ * we're in an allowed 64-on-32 scenario
+ */
+ if (pe_hdr->pe32.file_hdr.machine != grub_shim_machine_type)
+ {
+ if (!(grub_shim_machine_type == GRUB_PE32_MACHINE_I386
+ && pe_hdr->pe32.file_hdr.machine == GRUB_PE32_MACHINE_X86_64
+ && grub_shim_allow_64_bit ()))
+ return 0;
+ }
+
+ /* If it's not a header type we recognize at all, bail */
+ switch (pe_hdr->pe32plus.opt_hdr.magic)
+ {
+ case GRUB_PE32_PE64_MAGIC:
+ case GRUB_PE32_PE32_MAGIC:
+ break;
+ default:
+ return 0;
+ }
+
+ /* and now just check for general 64-vs-32 compatibility */
+ if (grub_shim_image_is_64_bit(pe_hdr))
+ {
+ if (grub_shim_allow_64_bit ())
+ return 1;
+ }
+ else
+ {
+ if (grub_shim_allow_32_bit ())
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Perform basic bounds checking of the intra-image pointers
+ */
+static grub_efi_uint64_t
+grub_shim_image_address (grub_addr_t image, grub_uint32_t size, grub_uint32_t addr)
+{
+ if (addr > size)
+ return 0;
+ return image + addr;
+}
+
+/*
+ * Perform the actual relocation
+ */
+static grub_err_t
+grub_shim_relocate_coff (struct grub_shim_pe_coff_loader_image_context *context,
+ void *orig, void *data)
+{
+ struct grub_image_base_relocation *reloc_base, *reloc_base_end;
+ grub_efi_uint64_t adjust;
+ grub_efi_uint16_t *reloc, *reloc_end;
+ grub_uint8_t *fixup, *fixup_base, *fixup_data = NULL;
+ grub_efi_uint16_t *fixup16;
+ grub_efi_uint32_t *fixup32;
+ grub_efi_uint64_t *fixup64;
+ grub_int32_t size = context->image_size;
+ void *image_end = (char *)orig + size;
+
+ if (grub_shim_image_is_64_bit(context->pe_hdr))
+ context->pe_hdr->pe32plus.opt_hdr.image_base = (grub_efi_uint64_t)(unsigned long)data;
+ else
+ context->pe_hdr->pe32.opt_hdr.image_base = (grub_efi_uint32_t)(unsigned long)data;
+
+ reloc_base = (struct grub_image_base_relocation *)
+ grub_shim_image_address ((grub_efi_uint64_t)orig, size,
+ context->reloc_dir->rva);
+ reloc_base_end = (struct grub_image_base_relocation *)
+ grub_shim_image_address ((grub_efi_uint64_t)orig, size,
+ context->reloc_dir->rva
+ + context->reloc_dir->size - 1);
+
+ if (!reloc_base || !reloc_base_end)
+ {
+ grub_printf("Reloc table overflows binary\n");
+ return GRUB_ERR_BAD_FILE_TYPE;
+ }
+
+ adjust = (grub_efi_uintn_t)data - context->image_address;
+
+ if (adjust == 0)
+ return GRUB_EFI_SUCCESS;
+
+ while (reloc_base < reloc_base_end)
+ {
+ reloc = (grub_efi_uint16_t *) ((grub_int8_t *) reloc_base
+ + sizeof (struct grub_image_base_relocation));
+
+ if ((reloc_base->block_size == 0)
+ || (reloc_base->block_size > context->reloc_dir->size))
+ {
+ grub_printf("Reloc block size %d is invalid\n", reloc_base->block_size);
+ return GRUB_ERR_FILE_READ_ERROR;
+ }
+
+ reloc_end = (grub_efi_uint16_t *)
+ ((grub_uint8_t *) reloc_base + reloc_base->block_size);
+ if ((void *)reloc_end < orig || (void *)reloc_end > image_end)
+ {
+ grub_printf("Reloc entry overflows binary\n");
+ return GRUB_ERR_FILE_READ_ERROR;
+ }
+
+ fixup_base = (grub_uint8_t *)
+ grub_shim_image_address ((grub_efi_uint64_t)data,
+ size,
+ reloc_base->virtual_address);
+ if (!fixup_base)
+ {
+ grub_printf("Invalid fixup_base\n");
+ return GRUB_ERR_FILE_READ_ERROR;
+ }
+
+ while (reloc < reloc_end)
+ {
+ fixup = fixup_base + (*reloc & 0xFFF);
+ switch ((*reloc) >> 12)
+ {
+ case EFI_IMAGE_REL_BASED_ABSOLUTE:
+ break;
+
+ case EFI_IMAGE_REL_BASED_HIGH:
+ fixup16 = (grub_efi_uint16_t *) fixup;
+ *fixup16 = (grub_efi_uint16_t)
+ (*fixup16
+ + ((grub_efi_uint16_t) ((grub_efi_uint32_t) adjust >> 16)));
+ if (fixup_data != NULL)
+ {
+ *(grub_efi_uint16_t *) fixup_data = *fixup16;
+ fixup_data = fixup_data + sizeof (grub_efi_uint16_t);
+ }
+ break;
+
+ case EFI_IMAGE_REL_BASED_LOW:
+ fixup16 = (grub_efi_uint16_t *) fixup;
+ *fixup16 = (grub_efi_uint16_t)
+ (*fixup16 + (grub_efi_uint16_t) adjust);
+ if (fixup_data != NULL)
+ {
+ *(grub_efi_uint16_t *) fixup_data = *fixup16;
+ fixup_data = fixup_data + sizeof (grub_efi_uint16_t);
+ }
+ break;
+
+ case EFI_IMAGE_REL_BASED_HIGHLOW:
+ fixup32 = (grub_efi_uint32_t *) fixup;
+ *fixup32 = *fixup32 + (grub_efi_uint32_t) adjust;
+ if (fixup_data != NULL)
+ {
+ fixup_data = ALIGN_POINTER (fixup_data, sizeof (grub_efi_uint32_t));
+ *(grub_efi_uint32_t *)fixup_data = *fixup32;
+ fixup_data = fixup_data + sizeof (grub_efi_uint32_t);
+ }
+ break;
+
+ case EFI_IMAGE_REL_BASED_DIR64:
+ fixup64 = (grub_efi_uint64_t *) fixup;
+ *fixup64 = *fixup64 + (grub_efi_uint64_t) adjust;
+ if (fixup_data != NULL)
+ {
+ fixup_data = ALIGN_POINTER (fixup_data, sizeof(grub_efi_uint64_t));
+ *(grub_efi_uint64_t *)(fixup_data) = *fixup64;
+ fixup_data = fixup_data + sizeof(grub_efi_uint64_t);
+ }
+ break;
+
+ default:
+ grub_printf("Unknown relocation\n");
+ return GRUB_ERR_FILE_READ_ERROR;
+ }
+ reloc += 1;
+ }
+ reloc_base = (struct grub_image_base_relocation *) reloc_end;
+ }
+
+ return GRUB_EFI_SUCCESS;
+}
+
+/*
+ * Read the binary header and grab appropriate information from it
+ */
+static grub_err_t
+grub_shim_read_header(grub_efi_physical_address_t data, grub_uint32_t datasize,
+ struct grub_shim_pe_coff_loader_image_context *context)
+{
+ struct grub_dos_header *dos_hdr = (struct grub_dos_header *)data;
+ union grub_shim_optional_header_union *pe_hdr = (union grub_shim_optional_header_union *)data;
+ grub_uint64_t header_without_data_dir, section_header_offset, opt_hdr_size;
+
+ if (datasize < sizeof (pe_hdr->pe32))
+ {
+ grub_printf("Invalid image\n");
+ return GRUB_ERR_BAD_FILE_TYPE;
+ }
+
+ if (dos_hdr->magic == EFI_IMAGE_DOS_SIGNATURE)
+ pe_hdr = (union grub_shim_optional_header_union *)((grub_uint8_t *)data
+ + dos_hdr->lfanew);
+
+ if (!grub_shim_image_is_loadable(pe_hdr))
+ {
+ grub_printf("Platform does not support this image\n");
+ return GRUB_ERR_BAD_FILE_TYPE;
+ }
+
+ if (grub_shim_image_is_64_bit(pe_hdr))
+ {
+ context->number_of_rva_and_sizes = pe_hdr->pe32plus.opt_hdr.num_data_directories;
+ context->header_size = pe_hdr->pe32plus.opt_hdr.header_size;
+ context->image_size = pe_hdr->pe32plus.opt_hdr.image_size;
+ opt_hdr_size = sizeof(struct grub_pe64_optional_header);
+ } else
+ {
+ context->number_of_rva_and_sizes = pe_hdr->pe32.opt_hdr.num_data_directories;
+ context->header_size = pe_hdr->pe32.opt_hdr.header_size;
+ context->image_size = (grub_efi_uint64_t)pe_hdr->pe32.opt_hdr.header_size;
+ opt_hdr_size = sizeof(struct grub_pe32_optional_header);
+ }
+
+ context->num_sections = pe_hdr->pe32.file_hdr.num_sections;
+
+ if (GRUB_PE32_NUM_DATA_DIRECTORIES < context->number_of_rva_and_sizes)
+ {
+ grub_printf("Image header too small\n");
+ return GRUB_ERR_FILE_READ_ERROR;
+ }
+
+ header_without_data_dir = opt_hdr_size
+ - sizeof (struct grub_pe32_data_directory)
+ * GRUB_PE32_NUM_DATA_DIRECTORIES;
+ if (((grub_efi_uint32_t)pe_hdr->pe32.file_hdr.optional_header_size
+ - header_without_data_dir) !=
+ context->number_of_rva_and_sizes * sizeof (struct grub_pe32_data_directory))
+ {
+ grub_printf("Image header overflows data directory\n");
+ return GRUB_ERR_FILE_READ_ERROR;
+ }
+
+ section_header_offset = dos_hdr->lfanew
+ + sizeof (grub_efi_uint32_t)
+ + sizeof (struct grub_pe32_coff_header)
+ + pe_hdr->pe32.file_hdr.optional_header_size;
+ if (((grub_efi_uint32_t)context->image_size - section_header_offset)
+ / sizeof (struct grub_pe32_section_table)
+ <= context->num_sections)
+ {
+ grub_printf("Image sections overflow image size\n");
+ return GRUB_ERR_FILE_READ_ERROR;
+ }
+
+ if ((context->header_size - section_header_offset)
+ / sizeof (struct grub_pe32_section_table)
+ < (grub_efi_uint32_t)context->num_sections)
+ {
+ grub_printf("Image sections overflow section headers\n");
+ return GRUB_ERR_FILE_READ_ERROR;
+ }
+
+ if ((((grub_efi_uint8_t *)pe_hdr
+ - (grub_efi_uint8_t *)data)
+ + sizeof(union grub_shim_optional_header_union )) > datasize)
+ {
+ grub_printf("Invalid image\n");
+ return GRUB_ERR_BAD_FILE_TYPE;
+ }
+
+ if (pe_hdr->te.signature != EFI_IMAGE_NT_SIGNATURE)
+ {
+ grub_printf("Unsupported image type\n");
+ return GRUB_ERR_BAD_FILE_TYPE;
+ }
+
+ if (pe_hdr->pe32.file_hdr.characteristics & GRUB_PE32_RELOCS_STRIPPED)
+ {
+ grub_printf("Unsupported image - Relocations have been stripped\n");
+ return GRUB_ERR_BAD_FILE_TYPE;
+ }
+
+ context->pe_hdr = pe_hdr;
+
+ if (grub_shim_image_is_64_bit(pe_hdr))
+ {
+ context->image_address = pe_hdr->pe32plus.opt_hdr.image_base;
+ context->entry_point = pe_hdr->pe32plus.opt_hdr.entry_addr;
+ context->reloc_dir = &pe_hdr->pe32plus.opt_hdr.base_relocation_table;
+ context->sec_dir = &pe_hdr->pe32plus.opt_hdr.certificate_table;
+ } else
+ {
+ context->image_address = pe_hdr->pe32.opt_hdr.image_base;
+ context->entry_point = pe_hdr->pe32.opt_hdr.entry_addr;
+ context->reloc_dir = &pe_hdr->pe32.opt_hdr.base_relocation_table;
+ context->sec_dir = &pe_hdr->pe32.opt_hdr.certificate_table;
+ }
+
+ context->first_section = (struct grub_pe32_section_table *)
+ ((char *)pe_hdr
+ + pe_hdr->pe32.file_hdr.optional_header_size
+ + sizeof(grub_efi_uint32_t)
+ + sizeof(struct grub_pe32_coff_header));
+
+ if (context->image_size < context->header_size)
+ {
+ grub_printf("Invalid image\n");
+ return GRUB_ERR_BAD_FILE_TYPE;
+ }
+
+ if ((unsigned long)((grub_efi_uint8_t *)context->sec_dir - (grub_efi_uint8_t *)data) >
+ (datasize - sizeof(struct grub_pe32_data_directory)))
+ {
+ grub_printf("Invalid image\n");
+ return GRUB_ERR_BAD_FILE_TYPE;
+ }
+
+ if (context->sec_dir->rva >= datasize)
+ {
+ grub_printf("Malformed security header\n");
+ return GRUB_ERR_BAD_FILE_TYPE;
+ }
+ return GRUB_ERR_NONE;
+}
+
+static grub_efi_status_t
+grub_shim_verify (grub_addr_t addr, grub_ssize_t size)
+{
+ struct grub_shim_lock *shim_lock;
+ shim_lock = grub_efi_locate_protocol (&grub_shim_protocol_guid, 0);
+ if (!shim_lock)
+ {
+ grub_error (GRUB_ERR_BAD_OS, "could not load shim protocol");
+ return GRUB_EFI_UNSUPPORTED;
+ }
+
+ return shim_lock->verify((void *) addr, size);
+}
+
+static grub_err_t
+grub_shim_load_image(grub_addr_t addr, grub_ssize_t size,
+ struct grub_shim_pe_coff_loader_image_context *context)
+{
+ grub_err_t status;
+ grub_efi_status_t efi_status;
+ grub_uint32_t sect_size;
+ /* TODO: can they be unsigned? */
+ grub_int8_t *base, *end;
+ grub_int32_t i;
+ struct grub_pe32_section_table *section;
+ grub_efi_boot_services_t *b;
+
+ shim_used = 0;
+ shim_buffer = 0;
+
+ status = grub_shim_verify (addr, size);
+ if (status != GRUB_ERR_NONE)
+ {
+ grub_error (GRUB_ERR_BAD_OS, "shim verification failed");
+ return GRUB_ERR_BAD_OS;
+ }
+
+ grub_memset(context, 0, sizeof(*context));
+ status = grub_shim_read_header (addr, size, context);
+ if (status != GRUB_ERR_NONE)
+ {
+ grub_error (GRUB_ERR_BAD_OS, "read header failed");
+ return GRUB_ERR_BAD_OS;
+ }
+
+ /* TODO: do we need to do this with efi_allocate? */
+ shim_pages = (((grub_efi_uintn_t) context->image_size + ((1 << 12) - 1)) >> 12);
+
+ b = grub_efi_system_table->boot_services;
+ efi_status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES,
+ GRUB_EFI_LOADER_CODE, shim_pages, &shim_buffer);
+ if (efi_status != GRUB_EFI_SUCCESS)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory for shim buffer"));
+ return GRUB_ERR_OUT_OF_MEMORY;
+ }
+
+ /* TODO: do we need the double cast? */
+ grub_memcpy ((void *) ((grub_efi_physical_address_t) shim_buffer),
+ (void *) ((grub_addr_t) addr), context->header_size);
+ /*
+ * Copy the executable's sections to their desired offsets
+ */
+ section = context->first_section;
+ for (i = 0; i < context->num_sections; i++, section++)
+ {
+ if (section->characteristics & 0x02000000)
+ /* section has EFI_IMAGE_SCN_MEM_DISCARDABLE attr set */
+ continue;
+
+ sect_size = section->virtual_size;
+
+ if (sect_size > section->raw_data_size)
+ sect_size = section->raw_data_size;
+
+ base = (grub_int8_t *)
+ grub_shim_image_address (shim_buffer, context->image_size,
+ section->virtual_address);
+ end = (grub_int8_t *)
+ grub_shim_image_address (shim_buffer, context->image_size,
+ section->virtual_address
+ + sect_size - 1);
+ if (!base || !end)
+ {
+ grub_printf("Invalid section base\n");
+ status = GRUB_ERR_BAD_FILE_TYPE;
+ goto fail;
+ }
+
+ if (section->virtual_address < context->header_size
+ || section->raw_data_offset < context->header_size)
+ {
+ grub_printf("Section is inside image headers\n");
+ status = GRUB_ERR_BAD_FILE_TYPE;
+ goto fail;
+ }
+
+ if (section->raw_data_size > 0)
+ /* TODO: do we need the double cast? */
+ grub_memcpy ((void *)base,
+ (void *) (((grub_addr_t) addr)
+ + section->raw_data_offset), sect_size);
+
+ if (sect_size < section->virtual_size)
+ grub_memset ((void *)(base + sect_size), 0,
+ section->virtual_size - sect_size);
+ }
+
+ if (context->number_of_rva_and_sizes <= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC)
+ {
+ grub_printf("Image has no relocation entry\n");
+ status = GRUB_ERR_BAD_FILE_TYPE;
+ goto fail;
+ }
+
+ if (context->reloc_dir->size)
+ {
+ status = grub_shim_relocate_coff (context, (void *) addr,
+ (void *) shim_buffer);
+ if (status != GRUB_ERR_NONE)
+ {
+ grub_printf("Relocation failed: [%u]\n", status);
+ status = GRUB_ERR_BAD_FILE_TYPE;
+ goto fail;
+ }
+ }
+ shim_entry_point = (void *)grub_shim_image_address (shim_buffer,
+ context->image_size,
+ context->entry_point);
+ if (!shim_entry_point)
+ {
+ grub_printf("Invalid entry point\n");
+ status = GRUB_ERR_BAD_FILE_TYPE;
+ goto fail;
+ }
+
+ shim_used = 1;
+ return GRUB_ERR_NONE;
+fail:
+ efi_call_2 (b->free_pages, shim_buffer, shim_pages);
+ shim_buffer = 0;
+ return status;
+}
static grub_err_t
grub_chainloader_unload (void)
--
1.9.1

View File

@@ -0,0 +1,98 @@
From f922ac74714d01972a3c291e15f0c316b67e40eb Mon Sep 17 00:00:00 2001
From: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
Date: Fri, 27 Mar 2015 08:26:08 -0700
Subject: [PATCH 5/7] efi: chainloader: use shim to load and verify an image
Upstream-Status: Inappropriate [embedded specific]
The grub chainloader module uses the UEFI LoadImage service
to load a chainloaded binary. However, if such binary is not
signed by the UEFI certification authority, LoadImage will fail.
Under shim, we can use Machine-Owned Keys (MOKs) to verify an
image. Thus, in case LoadImage fails due to a security violation
we rely on the shim verification service. If successful, the
image is parsed and loaded.
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
grub-core/loader/efi/chainloader.c | 49 +++++++++++++++++++++++++++++++-------
1 file changed, 40 insertions(+), 9 deletions(-)
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index bd83859..01d2ebe 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -733,6 +733,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
grub_efi_loaded_image_t *loaded_image;
char *filename;
grub_efi_handle_t dev_handle = 0;
+ struct grub_shim_pe_coff_loader_image_context context;
if (argc == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
@@ -827,23 +828,53 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
if (status != GRUB_EFI_SUCCESS)
{
if (status == GRUB_EFI_OUT_OF_RESOURCES)
- grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources");
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources");
+ goto fail;
+ }
+ /* try with shim */
+ else if (status == GRUB_EFI_SECURITY_VIOLATION)
+ {
+ status = grub_shim_load_image (address, size, &context);
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_error (GRUB_ERR_BAD_OS, "shim cannot load image");
+ goto fail;
+ }
+ }
else
- grub_error (GRUB_ERR_BAD_OS, "cannot load image");
-
- goto fail;
+ {
+ grub_error (GRUB_ERR_BAD_OS, "cannot load image");
+ goto fail;
+ }
}
- /* LoadImage does not set a device handler when the image is
- loaded from memory, so it is necessary to set it explicitly here.
- This is a mess. */
- loaded_image = grub_efi_get_loaded_image (image_handle);
+ /* if we use shim, the UEFI load_image failed, thus, we borrow
+ * grub_efi_image_handle and restore it later
+ */
+ if (shim_used)
+ /* if we use shim, the UEFI load_image failed, thus, we borrow
+ grub_efi_image_handle and restore it later */
+ loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
+ else
+ /* LoadImage does not set a device handler when the image is
+ loaded from memory, so it is necessary to set it explicitly here.
+ This is a mess. */
+ loaded_image = grub_efi_get_loaded_image (image_handle);
+
if (! loaded_image)
{
grub_error (GRUB_ERR_BAD_OS, "no loaded image available");
goto fail;
}
- loaded_image->device_handle = dev_handle;
+ if (shim_used)
+ {
+ grub_memcpy(&shim_li_bak, loaded_image, sizeof(shim_li_bak));
+ loaded_image->image_base = (void *)shim_buffer;
+ loaded_image->image_size = context.image_size;
+ }
+ else
+ loaded_image->device_handle = dev_handle;
grub_file_close (file);
--
1.9.1

View File

@@ -0,0 +1,63 @@
From f25778620360ccff55f3d9c1bccba14249978502 Mon Sep 17 00:00:00 2001
From: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
Date: Fri, 27 Mar 2015 08:29:13 -0700
Subject: [PATCH 6/7] efi: chainloader: boot the image using shim
Upstream-Status: Inappropriate [embedded specific]
If the image was loaded using shim, boot the image. Given that
shim loaded the image, the UEFI firmware will not know where to
jump after the execution completes. Thus, replace the UEFI boot
service Exit with our own implementation to make sure we jump
to the instruction after the call to the entry point.
Replace the system Exit service when done.
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
grub-core/loader/efi/chainloader.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index 01d2ebe..1c9795c 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -605,9 +605,34 @@ grub_chainloader_boot (void)
grub_efi_status_t status;
grub_efi_uintn_t exit_data_size;
grub_efi_char16_t *exit_data = NULL;
+ grub_efi_loaded_image_t *loaded_image = NULL;
+ grub_efi_status_t
+ (*saved_exit) (grub_efi_handle_t image_handle,
+ grub_efi_status_t exit_status,
+ grub_efi_uintn_t exit_data_size,
+ grub_efi_char16_t *exit_data) __attribute__((noreturn));
b = grub_efi_system_table->boot_services;
- status = efi_call_3 (b->start_image, image_handle, &exit_data_size, &exit_data);
+
+ if (!shim_used)
+ status = efi_call_3 (b->start_image, image_handle, &exit_data_size, &exit_data);
+ else
+ {
+ saved_exit = grub_efi_system_table->boot_services->exit;
+ grub_efi_system_table->boot_services->exit = efi_shim_exit;
+ status = efi_call_foo(shim_entry_point,
+ (grub_efi_uint64_t)grub_efi_image_handle,
+ (grub_efi_uint64_t)grub_efi_system_table);
+ grub_efi_system_table->boot_services->exit = saved_exit;
+
+ loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
+ if (!loaded_image)
+ /* TODO: this is serious, what to do? */
+ grub_error (GRUB_ERR_BAD_OS, "GRUB loaded image not found");
+ else
+ /* restore loaded image */
+ grub_memcpy(loaded_image, &shim_li_bak, sizeof(shim_li_bak));
+ }
if (status != GRUB_EFI_SUCCESS)
{
if (exit_data)
--
1.9.1

View File

@@ -0,0 +1,43 @@
From 70a30826d1cfb7a90c34760896dfd92b9c396f52 Mon Sep 17 00:00:00 2001
From: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
Date: Fri, 27 Mar 2015 08:31:27 -0700
Subject: [PATCH 7/7] efi: chainloader: take care of unload undershim
Upstream-Status: Inappropriate [embedded specific]
Under shim, we use a custom buffer to put the relocated image, make
sure we free that memory when unloading.
Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
grub-core/loader/efi/chainloader.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index 1c9795c..d0ceb6e 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -586,8 +586,18 @@ grub_chainloader_unload (void)
grub_efi_boot_services_t *b;
b = grub_efi_system_table->boot_services;
- efi_call_1 (b->unload_image, image_handle);
- efi_call_2 (b->free_pages, address, pages);
+ if (!shim_used)
+ {
+ efi_call_1 (b->unload_image, image_handle);
+ efi_call_2 (b->free_pages, address, pages);
+ }
+ else
+ {
+ if (shim_buffer)
+ {
+ efi_call_2 (b->free_pages, shim_buffer, shim_pages);
+ }
+ }
grub_free (file_path);
grub_free (cmdline);
--
1.9.1

View File

@@ -0,0 +1,252 @@
From e7b2efacc2d3acb48761aa2d62f943310fd70100 Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Mon, 25 Apr 2016 11:35:14 +0800
Subject: [PATCH] Fix 32-bit build failures
Upstream-Status: Pending
For 32-bit build, the 64-bit pointer should be replaced by grub_addr_t
which is compatible between 32-bit and 64-bit build.
In addition, the functions efi_shim_exit and efi_call_foo should be available
for 32-bit build.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
grub-core/Makefile.core.def | 1 +
grub-core/kern/i386/efi/callwrap.S | 50 ++++++++++++++++++++++++++++++++++++++
grub-core/loader/efi/chainloader.c | 30 +++++++++++------------
include/grub/efi/api.h | 8 +++---
include/grub/efi/shim.h | 2 +-
5 files changed, 71 insertions(+), 20 deletions(-)
create mode 100644 grub-core/kern/i386/efi/callwrap.S
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 39e77a4..0a78137 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -135,6 +135,7 @@ kernel = {
efi = term/efi/console.c;
i386_efi = kern/i386/tsc.c;
+ i386_efi = kern/i386/efi/callwrap.S;
i386_efi = kern/i386/efi/init.c;
i386_efi = bus/pci.c;
diff --git a/grub-core/kern/i386/efi/callwrap.S b/grub-core/kern/i386/efi/callwrap.S
new file mode 100644
index 0000000..c683444
--- /dev/null
+++ b/grub-core/kern/i386/efi/callwrap.S
@@ -0,0 +1,50 @@
+/* callwrap.S - wrapper for i386 efi calls */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2006,2007,2009 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <grub/symbol.h>
+
+ .file "callwrap.S"
+ .text
+
+FUNCTION(efi_call_foo)
+ movl 12(%esp), %eax
+ movl 8(%esp), %edx
+ movl 4(%esp), %ecx
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+ pushl %ebp
+ movl %esp, saved_sp
+ subl $40, %esp
+ pushl %eax
+ pushl %edx
+ call *%ecx
+
+FUNCTION(efi_shim_exit)
+ addl $48, %esp
+ movl saved_sp, %esp
+ popl %ebp
+ popl %edi
+ popl %esi
+ popl %ebx
+ ret
+
+ .data
+saved_sp: .long 0
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index 83769a2..e3d1138 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -149,7 +149,7 @@ grub_shim_image_is_loadable (union grub_shim_optional_header_union *pe_hdr)
/*
* Perform basic bounds checking of the intra-image pointers
*/
-static grub_efi_uint64_t
+static grub_addr_t
grub_shim_image_address (grub_addr_t image, grub_uint32_t size, grub_uint32_t addr)
{
if (addr > size)
@@ -208,12 +208,12 @@ grub_shim_relocate_coff (struct grub_shim_pe_coff_loader_image_context *context,
* yield the next entry in the array.
*/
reloc_base = (struct grub_image_base_relocation *)
- grub_shim_image_address ((grub_efi_uint64_t)orig, size,
+ grub_shim_image_address ((grub_addr_t)orig, size,
section->raw_data_offset);
/* reloc_base_end is the address of the first entry /past/ the
* table. */
reloc_base_end = (struct grub_image_base_relocation *)
- grub_shim_image_address ((grub_efi_uint64_t)orig, size,
+ grub_shim_image_address ((grub_addr_t)orig, size,
section->raw_data_offset
+ section->virtual_size - 1);
@@ -254,7 +254,7 @@ grub_shim_relocate_coff (struct grub_shim_pe_coff_loader_image_context *context,
}
fixup_base = (grub_uint8_t *)
- grub_shim_image_address ((grub_efi_uint64_t)data,
+ grub_shim_image_address ((grub_addr_t)data,
size,
reloc_base->virtual_address);
if (!fixup_base)
@@ -333,12 +333,12 @@ grub_shim_relocate_coff (struct grub_shim_pe_coff_loader_image_context *context,
* Read the binary header and grab appropriate information from it
*/
static grub_err_t
-grub_shim_read_header(grub_efi_physical_address_t data, grub_uint32_t datasize,
+grub_shim_read_header(grub_addr_t data, grub_uint32_t datasize,
struct grub_shim_pe_coff_loader_image_context *context)
{
struct grub_dos_header *dos_hdr = (struct grub_dos_header *)data;
union grub_shim_optional_header_union *pe_hdr = (union grub_shim_optional_header_union *)data;
- grub_uint64_t header_without_data_dir, section_header_offset, opt_hdr_size;
+ grub_efi_uintn_t header_without_data_dir, section_header_offset, opt_hdr_size;
if (datasize < sizeof (pe_hdr->pe32))
{
@@ -393,7 +393,7 @@ grub_shim_read_header(grub_efi_physical_address_t data, grub_uint32_t datasize,
+ sizeof (grub_efi_uint32_t)
+ sizeof (struct grub_pe32_coff_header)
+ pe_hdr->pe32.file_hdr.optional_header_size;
- if (((grub_efi_uint32_t)context->image_size - section_header_offset)
+ if ((context->image_size - section_header_offset)
/ sizeof (struct grub_pe32_section_table)
<= context->num_sections)
{
@@ -530,7 +530,7 @@ grub_shim_load_image(grub_addr_t addr, grub_ssize_t size,
}
/* TODO: do we need the double cast? */
- grub_memcpy ((void *) ((grub_efi_physical_address_t) shim_buffer),
+ grub_memcpy ((void *) ((grub_addr_t) shim_buffer),
(void *) ((grub_addr_t) addr), context->header_size);
reloc_base = (grub_int8_t *) grub_shim_image_address (shim_buffer, size,
@@ -553,10 +553,10 @@ grub_shim_load_image(grub_addr_t addr, grub_ssize_t size,
sect_size = section->raw_data_size;
base = (grub_int8_t *)
- grub_shim_image_address (shim_buffer, context->image_size,
+ grub_shim_image_address ((grub_addr_t) shim_buffer, context->image_size,
section->virtual_address);
end = (grub_int8_t *)
- grub_shim_image_address (shim_buffer, context->image_size,
+ grub_shim_image_address ((grub_addr_t) shim_buffer, context->image_size,
section->virtual_address
+ sect_size - 1);
@@ -619,7 +619,7 @@ grub_shim_load_image(grub_addr_t addr, grub_ssize_t size,
if (context->reloc_dir->size && reloc_section)
{
status = grub_shim_relocate_coff (context, reloc_section,
- (void *) addr, (void *) shim_buffer);
+ (void *) addr, (void *) ((grub_addr_t) shim_buffer));
if (status != GRUB_ERR_NONE)
{
grub_printf("Relocation failed: [%u]\n", status);
@@ -627,7 +627,7 @@ grub_shim_load_image(grub_addr_t addr, grub_ssize_t size,
goto fail;
}
}
- shim_entry_point = (void *)grub_shim_image_address (shim_buffer,
+ shim_entry_point = (void *)grub_shim_image_address ((grub_addr_t) shim_buffer,
context->image_size,
context->entry_point);
if (!shim_entry_point)
@@ -696,8 +696,8 @@ grub_chainloader_boot (void)
saved_exit = grub_efi_system_table->boot_services->exit;
grub_efi_system_table->boot_services->exit = efi_shim_exit;
status = efi_call_foo(shim_entry_point,
- (grub_efi_uint64_t)grub_efi_image_handle,
- (grub_efi_uint64_t)grub_efi_system_table);
+ grub_efi_image_handle,
+ grub_efi_system_table);
grub_efi_system_table->boot_services->exit = saved_exit;
loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
@@ -970,7 +970,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
if (shim_used)
{
grub_memcpy(&shim_li_bak, loaded_image, sizeof(shim_li_bak));
- loaded_image->image_base = (void *)shim_buffer;
+ loaded_image->image_base = (void *)(grub_addr_t) shim_buffer;
loaded_image->image_size = context.image_size;
}
else
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index 374d88b..22b3543 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -1437,10 +1437,6 @@ typedef struct grub_efi_block_io grub_efi_block_io_t;
grub_uint64_t EXPORT_FUNC(efi_wrap_0) (void *func);
grub_uint64_t EXPORT_FUNC(efi_wrap_1) (void *func, grub_uint64_t arg1);
-grub_efi_status_t EXPORT_FUNC(efi_shim_exit) (grub_efi_handle_t handle, grub_efi_status_t exit_status,
- grub_efi_uintn_t exit_data_size, grub_efi_char16_t *exit_data) __attribute__((noreturn));
-grub_uint64_t EXPORT_FUNC(efi_call_foo) (void *func, grub_uint64_t arg1,
- grub_uint64_t arg2);
grub_uint64_t EXPORT_FUNC(efi_wrap_2) (void *func, grub_uint64_t arg1,
grub_uint64_t arg2);
grub_uint64_t EXPORT_FUNC(efi_wrap_3) (void *func, grub_uint64_t arg1,
@@ -1467,4 +1463,8 @@ grub_uint64_t EXPORT_FUNC(efi_wrap_10) (void *func, grub_uint64_t arg1,
grub_uint64_t arg10);
#endif
+grub_efi_status_t EXPORT_FUNC(efi_shim_exit) (grub_efi_handle_t handle, grub_efi_status_t exit_status,
+ grub_efi_uintn_t exit_data_size, grub_efi_char16_t *exit_data) __attribute__((noreturn));
+grub_efi_status_t EXPORT_FUNC(efi_call_foo) (void *func, void *arg1, void *arg2);
+
#endif /* ! GRUB_EFI_API_HEADER */
diff --git a/include/grub/efi/shim.h b/include/grub/efi/shim.h
index 4b92a00..9fac90b 100644
--- a/include/grub/efi/shim.h
+++ b/include/grub/efi/shim.h
@@ -60,7 +60,7 @@ struct grub_image_base_relocation
struct grub_shim_pe_coff_loader_image_context {
grub_efi_uint64_t image_address;
- grub_efi_uint64_t image_size;
+ grub_efi_uintn_t image_size;
grub_efi_uint64_t entry_point;
grub_efi_uintn_t header_size;
grub_efi_uint16_t image_type;
--
1.9.1

View File

@@ -0,0 +1,263 @@
---
grub-core/Makefile.core.def | 8 +
grub-core/commands/efi/efivar.c | 238 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 246 insertions(+)
--- /dev/null
+++ b/grub-core/commands/efi/efivar.c
@@ -0,0 +1,238 @@
+/* efivar.c - Read EFI global variables. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2015 Free Software Foundation, Inc.
+ * Copyright (C) 2015 CloudFlare, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/extcmd.h>
+#include <grub/env.h>
+#include <grub/lib/hexdump.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] = {
+ {"format", 'f', GRUB_ARG_OPTION_OPTIONAL, N_("Parse EFI_VAR in specific format (hex, uint8, ascii, dump). Default: hex."), N_("FORMAT"), ARG_TYPE_STRING},
+ {"set", 's', GRUB_ARG_OPTION_OPTIONAL, N_("Save parsed result to environment variable (does not work with dump)."), N_("ENV_VAR"), ARG_TYPE_STRING},
+ {0, 0, 0, 0, 0, 0}
+};
+
+enum efi_var_type
+ {
+ EFI_VAR_ASCII = 0,
+ EFI_VAR_UINT8,
+ EFI_VAR_HEX,
+ EFI_VAR_DUMP,
+ EFI_VAR_INVALID = -1
+ };
+
+static enum efi_var_type
+parse_efi_var_type (const char *type)
+{
+ if (!grub_strncmp (type, "ascii", sizeof("ascii")))
+ return EFI_VAR_ASCII;
+
+ if (!grub_strncmp (type, "uint8", sizeof("uint8")))
+ return EFI_VAR_UINT8;
+
+ if (!grub_strncmp (type, "hex", sizeof("hex")))
+ return EFI_VAR_HEX;
+
+ if (!grub_strncmp (type, "dump", sizeof("dump")))
+ return EFI_VAR_DUMP;
+
+ return EFI_VAR_INVALID;
+}
+
+static int
+grub_print_ascii (char *str, char c)
+{
+ if (grub_iscntrl (c))
+ {
+ switch (c)
+ {
+ case '\0':
+ str[0] = '\\';
+ str[1] = '0';
+ return 2;
+
+ case '\a':
+ str[0] = '\\';
+ str[1] = 'a';
+ return 2;
+
+ case '\b':
+ str[0] = '\\';
+ str[1] = 'b';
+ return 2;
+
+ case '\f':
+ str[0] = '\\';
+ str[1] = 'f';
+ return 2;
+
+ case '\n':
+ str[0] = '\\';
+ str[1] = 'n';
+ return 2;
+
+ case '\r':
+ str[0] = '\\';
+ str[1] = 'r';
+ return 2;
+
+ case '\t':
+ str[0] = '\\';
+ str[1] = 't';
+ return 2;
+
+ case '\v':
+ str[0] = '\\';
+ str[1] = 'v';
+ return 2;
+
+ default:
+ str[0] = '.'; /* as in hexdump -C */
+ return 1;
+ }
+ }
+
+ str[0] = c;
+ return 1;
+}
+
+static grub_err_t
+grub_cmd_get_efi_var (struct grub_extcmd_context *ctxt,
+ int argc, char **args)
+{
+ struct grub_arg_list *state = ctxt->state;
+ grub_err_t status;
+ void *efi_var = NULL;
+ grub_size_t efi_var_size = 0;
+ enum efi_var_type efi_type = EFI_VAR_HEX;
+ grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
+ char *env_var = NULL;
+ grub_size_t i;
+ char *ptr;
+
+ if (1 != argc)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+
+ if (state[0].set)
+ efi_type = parse_efi_var_type (state[0].arg);
+
+ if (EFI_VAR_INVALID == efi_type)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid format specifier"));
+
+ efi_var = grub_efi_get_variable (args[0], &global, &efi_var_size);
+ if (!efi_var || !efi_var_size)
+ {
+ status = grub_error (GRUB_ERR_READ_ERROR, N_("cannot read variable"));
+ goto err;
+ }
+
+ switch (efi_type)
+ {
+ case EFI_VAR_ASCII:
+ env_var = grub_malloc (efi_var_size * 2 + 1);
+ if (!env_var)
+ {
+ status = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+ break;
+ }
+
+ ptr = env_var;
+
+ for (i = 0; i < efi_var_size; i++)
+ ptr += grub_print_ascii (ptr, ((const char *)efi_var)[i]);
+ *ptr = '\0';
+ break;
+
+ case EFI_VAR_UINT8:
+ env_var = grub_malloc (4);
+ if (!env_var)
+ {
+ status = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+ break;
+ }
+ grub_snprintf (env_var, 4, "%u", *((grub_uint8_t *)efi_var));
+ break;
+
+ case EFI_VAR_HEX:
+ env_var = grub_malloc (efi_var_size * 2 + 1);
+ if (!env_var)
+ {
+ status = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+ break;
+ }
+ for (i = 0; i < efi_var_size; i++)
+ grub_snprintf (env_var + (i * 2), 3, "%02x", ((grub_uint8_t *)efi_var)[i]);
+ break;
+
+ case EFI_VAR_DUMP:
+ if (state[1].set)
+ status = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("cannot set variable with dump format specifier"));
+ else
+ {
+ hexdump (0, (char *)efi_var, efi_var_size);
+ status = GRUB_ERR_NONE;
+ }
+ break;
+
+ default:
+ status = grub_error (GRUB_ERR_BUG, N_("should not happen (bug in module?)"));
+ }
+
+ if (efi_type != EFI_VAR_DUMP)
+ {
+ if (state[1].set)
+ status = grub_env_set (state[1].arg, env_var);
+ else
+ {
+ grub_printf ("%s\n", (const char *)env_var);
+ status = GRUB_ERR_NONE;
+ }
+ }
+
+err:
+
+ if (env_var)
+ grub_free (env_var);
+
+ if (efi_var)
+ grub_free (efi_var);
+
+ return status;
+}
+
+static grub_extcmd_t cmd = NULL;
+
+GRUB_MOD_INIT (efivar)
+{
+ cmd = grub_register_extcmd ("get_efivar", grub_cmd_get_efi_var, 0, N_("[-f FORMAT] [-s ENV_VAR] EFI_VAR"),
+ N_("Read EFI variable and print it or save its contents to environment variable."), options);
+}
+
+GRUB_MOD_FINI (efivar)
+{
+ if (cmd)
+ grub_unregister_extcmd (cmd);
+}
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -539,6 +539,14 @@ module = {
};
module = {
+ name = efivar;
+
+ common = commands/efi/efivar.c;
+
+ enable = efi;
+};
+
+module = {
name = lsacpi;
common = commands/lsacpi.c;

View File

@@ -0,0 +1,62 @@
From 9517b3173af961ea66721cfc48cd47e50a704388 Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Wed, 4 Nov 2015 17:17:06 +0800
Subject: [PATCH] Work around the failure of ExitBootServices()
ExitBootServices() will fail if any of the event handlers change
the memory map. In which case, we must be prepared to retry, but
only once so that we're guaranteed to exit on repeated failures
instead of spinning forever. This fix refers to the workaround
made by Linux kernel.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
grub-core/kern/efi/mm.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
index 461deb0..7620a47 100644
--- a/grub-core/kern/efi/mm.c
+++ b/grub-core/kern/efi/mm.c
@@ -158,6 +158,7 @@ grub_efi_finish_boot_services (grub_efi_uintn_t *outbuf_size, void *outbuf,
{
grub_efi_boot_services_t *b;
grub_efi_status_t status;
+ int called_exit = 0;
#if defined (__i386__) || defined (__x86_64__)
const grub_uint16_t apple[] = { 'A', 'p', 'p', 'l', 'e' };
@@ -167,6 +168,7 @@ grub_efi_finish_boot_services (grub_efi_uintn_t *outbuf_size, void *outbuf,
apple, sizeof (apple)) == 0);
#endif
+get_mem_map:
if (grub_efi_get_memory_map (&finish_mmap_size, finish_mmap_buf, &finish_key,
&finish_desc_size, &finish_desc_version) < 0)
return grub_error (GRUB_ERR_IO, "couldn't retrieve memory map");
@@ -186,7 +188,21 @@ grub_efi_finish_boot_services (grub_efi_uintn_t *outbuf_size, void *outbuf,
status = efi_call_2 (b->exit_boot_services, grub_efi_image_handle,
finish_key);
if (status != GRUB_EFI_SUCCESS)
- return grub_error (GRUB_ERR_IO, "couldn't terminate EFI services");
+ {
+ /*
+ * ExitBootServices() will fail if any of the event
+ * handlers change the memory map. In which case, we
+ * must be prepared to retry, but only once so that
+ * we're guaranteed to exit on repeated failures instead
+ * of spinning forever.
+ */
+ if (called_exit)
+ return grub_error (GRUB_ERR_IO, "couldn't terminate EFI services");
+
+ called_exit = 1;
+ grub_free (finish_mmap_buf);
+ goto get_mem_map;
+ }
grub_efi_is_finished = 1;
if (outbuf_size)
--
1.9.1

View File

@@ -0,0 +1,13 @@
# Note the initrd command becomes not working if the command for
# loading image is changed to the chainloader command instead of
# the linux command.
menuentry "Sample EFI boot" --unrestricted {
savedefault
set fallback=1
chainloader /bzImage root=/dev/sda2 ro rootwait initrd=/initrd
}
menuentry "Sample EFI boot (Recovery)" --unrestricted {
chainloader /bzImage_bakup root=/dev/sda2 ro rootwait initrd=/initrd_bakup
}

View File

@@ -0,0 +1,219 @@
From f6c412a240312a2be28b85905a0866288db9ffc8 Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Sun, 24 Apr 2016 19:02:28 +0800
Subject: [PATCH] chainloader: Actually find the relocations correctly and
process them that way.
Upstream-Status: Pending
Refer to a846aedd0e9dfe26ca6afaf6a1db8a54c20363c1 in shim.
Find the relocations based on the *file* address in the old binary,
because it's only the same as the virtual address some of the time.
Also perform some extra validation before processing it, and don't bail
out in /error/ if both ReloceBase and RelocEnd are null - that condition
is fine.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
grub-core/loader/efi/chainloader.c | 97 +++++++++++++++++++++++++++++++-------
1 file changed, 81 insertions(+), 16 deletions(-)
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index 0e84100..83769a2 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -162,6 +162,7 @@ grub_shim_image_address (grub_addr_t image, grub_uint32_t size, grub_uint32_t ad
*/
static grub_err_t
grub_shim_relocate_coff (struct grub_shim_pe_coff_loader_image_context *context,
+ struct grub_pe32_section_table *section,
void *orig, void *data)
{
struct grub_image_base_relocation *reloc_base, *reloc_base_end;
@@ -173,19 +174,53 @@ grub_shim_relocate_coff (struct grub_shim_pe_coff_loader_image_context *context,
grub_efi_uint64_t *fixup64;
grub_int32_t size = context->image_size;
void *image_end = (char *)orig + size;
+ int n = 0;
if (grub_shim_image_is_64_bit(context->pe_hdr))
context->pe_hdr->pe32plus.opt_hdr.image_base = (grub_efi_uint64_t)(unsigned long)data;
else
context->pe_hdr->pe32.opt_hdr.image_base = (grub_efi_uint32_t)(unsigned long)data;
+
+ /* Alright, so here's how this works:
+ *
+ * context->RelocDir gives us two things:
+ * - the VA the table of base relocation blocks are (maybe) to be
+ * mapped at (RelocDir->VirtualAddress)
+ * - the virtual size (RelocDir->Size)
+ *
+ * The .reloc section (Section here) gives us some other things:
+ * - the name! kind of. (Section->Name)
+ * - the virtual size (Section->VirtualSize), which should be the same
+ * as RelocDir->Size
+ * - the virtual address (Section->VirtualAddress)
+ * - the file section size (Section->SizeOfRawData), which is
+ * a multiple of OptHdr->FileAlignment. Only useful for image
+ * validation, not really useful for iteration bounds.
+ * - the file address (Section->PointerToRawData)
+ * - a bunch of stuff we don't use that's 0 in our binaries usually
+ * - Flags (Section->Characteristics)
+ *
+ * and then the thing that's actually at the file address is an array
+ * of EFI_IMAGE_BASE_RELOCATION structs with some values packed behind
+ * them. The SizeOfBlock field of this structure includes the
+ * structure itself, and adding it to that structure's address will
+ * yield the next entry in the array.
+ */
reloc_base = (struct grub_image_base_relocation *)
grub_shim_image_address ((grub_efi_uint64_t)orig, size,
- context->reloc_dir->rva);
+ section->raw_data_offset);
+ /* reloc_base_end is the address of the first entry /past/ the
+ * table. */
reloc_base_end = (struct grub_image_base_relocation *)
grub_shim_image_address ((grub_efi_uint64_t)orig, size,
- context->reloc_dir->rva
- + context->reloc_dir->size - 1);
+ section->raw_data_offset
+ + section->virtual_size - 1);
+
+ if (!reloc_base && !reloc_base_end)
+ {
+ return GRUB_EFI_SUCCESS;
+ }
if (!reloc_base || !reloc_base_end)
{
@@ -206,7 +241,7 @@ grub_shim_relocate_coff (struct grub_shim_pe_coff_loader_image_context *context,
if ((reloc_base->block_size == 0)
|| (reloc_base->block_size > context->reloc_dir->size))
{
- grub_printf("Reloc block size %d is invalid\n", reloc_base->block_size);
+ grub_printf("Reloc %d block size %d is invalid\n", n, reloc_base->block_size);
return GRUB_ERR_FILE_READ_ERROR;
}
@@ -214,7 +249,7 @@ grub_shim_relocate_coff (struct grub_shim_pe_coff_loader_image_context *context,
((grub_uint8_t *) reloc_base + reloc_base->block_size);
if ((void *)reloc_end < orig || (void *)reloc_end > image_end)
{
- grub_printf("Reloc entry overflows binary\n");
+ grub_printf("Reloc %d entry overflows binary\n", n);
return GRUB_ERR_FILE_READ_ERROR;
}
@@ -224,7 +259,7 @@ grub_shim_relocate_coff (struct grub_shim_pe_coff_loader_image_context *context,
reloc_base->virtual_address);
if (!fixup_base)
{
- grub_printf("Invalid fixup_base\n");
+ grub_printf("Reloc %d invalid fixup_base\n", n);
return GRUB_ERR_FILE_READ_ERROR;
}
@@ -282,12 +317,13 @@ grub_shim_relocate_coff (struct grub_shim_pe_coff_loader_image_context *context,
break;
default:
- grub_printf("Unknown relocation\n");
+ grub_printf("Reloc %d unknown relocation\n", n);
return GRUB_ERR_FILE_READ_ERROR;
}
reloc += 1;
}
reloc_base = (struct grub_image_base_relocation *) reloc_end;
+ n++;
}
return GRUB_EFI_SUCCESS;
@@ -458,9 +494,9 @@ grub_shim_load_image(grub_addr_t addr, grub_ssize_t size,
grub_efi_status_t efi_status;
grub_uint32_t sect_size;
/* TODO: can they be unsigned? */
- grub_int8_t *base, *end;
+ grub_int8_t *base, *end, *reloc_base, *reloc_base_end;
grub_int32_t i;
- struct grub_pe32_section_table *section;
+ struct grub_pe32_section_table *section, *reloc_section;
grub_efi_boot_services_t *b;
shim_used = 0;
@@ -496,16 +532,21 @@ grub_shim_load_image(grub_addr_t addr, grub_ssize_t size,
/* TODO: do we need the double cast? */
grub_memcpy ((void *) ((grub_efi_physical_address_t) shim_buffer),
(void *) ((grub_addr_t) addr), context->header_size);
+
+ reloc_base = (grub_int8_t *) grub_shim_image_address (shim_buffer, size,
+ context->reloc_dir->rva);
+ /* reloc_base_end here is the address of the last byte of the table */
+ reloc_base_end = (grub_int8_t *) grub_shim_image_address (shim_buffer, size,
+ context->reloc_dir->rva +
+ context->reloc_dir->size - 1);
+ reloc_section = NULL;
+
/*
* Copy the executable's sections to their desired offsets
*/
section = context->first_section;
for (i = 0; i < context->num_sections; i++, section++)
{
- if (section->characteristics & 0x02000000)
- /* section has EFI_IMAGE_SCN_MEM_DISCARDABLE attr set */
- continue;
-
sect_size = section->virtual_size;
if (sect_size > section->raw_data_size)
@@ -518,6 +559,30 @@ grub_shim_load_image(grub_addr_t addr, grub_ssize_t size,
grub_shim_image_address (shim_buffer, context->image_size,
section->virtual_address
+ sect_size - 1);
+
+ /* We do want to process .reloc, but it's often marked
+ * discardable, so we don't want to memcpy it. */
+ if (grub_memcmp (section->name, ".reloc\0\0", 8) == 0) {
+ if (reloc_section) {
+ grub_printf("Image has multiple relocation sections\n");
+ status = GRUB_ERR_BAD_FILE_TYPE;
+ goto fail;
+ }
+ /* If it has nonzero sizes, and our bounds check
+ * made sense, and the VA and size match RelocDir's
+ * versions, then we believe in this section table. */
+ if (section->raw_data_size && section->virtual_size &&
+ base && end &&
+ reloc_base == base &&
+ reloc_base_end == end) {
+ reloc_section = section;
+ }
+ }
+
+ if (section->characteristics & 0x02000000)
+ /* section has EFI_IMAGE_SCN_MEM_DISCARDABLE attr set */
+ continue;
+
if (!base || !end)
{
grub_printf("Invalid section base\n");
@@ -551,10 +616,10 @@ grub_shim_load_image(grub_addr_t addr, grub_ssize_t size,
goto fail;
}
- if (context->reloc_dir->size)
+ if (context->reloc_dir->size && reloc_section)
{
- status = grub_shim_relocate_coff (context, (void *) addr,
- (void *) shim_buffer);
+ status = grub_shim_relocate_coff (context, reloc_section,
+ (void *) addr, (void *) shim_buffer);
if (status != GRUB_ERR_NONE)
{
grub_printf("Relocation failed: [%u]\n", status);
--
1.9.1

View File

@@ -0,0 +1,32 @@
From d3a1198bfc671530ed77ad2b81b0ae4582f9378e Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Sun, 24 Apr 2016 15:56:38 +0800
Subject: [PATCH] chainloader: Don't check empty section in file like .bss
Upstream-Status: Pending
Because this kind of section always has a zeroed PointerToRawData denoting
the offset to file and a valid VirtualSize denoting the real size in the
memory.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
grub-core/loader/efi/chainloader.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index 2d8edc0..0e84100 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -526,7 +526,7 @@ grub_shim_load_image(grub_addr_t addr, grub_ssize_t size,
}
if (section->virtual_address < context->header_size
- || section->raw_data_offset < context->header_size)
+ || (section->raw_data_offset && section->raw_data_offset < context->header_size))
{
grub_printf("Section is inside image headers\n");
status = GRUB_ERR_BAD_FILE_TYPE;
--
1.9.1

View File

@@ -0,0 +1,32 @@
From b945262cdbad67e59f0d13725181862aa8a29561 Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Sun, 24 Apr 2016 12:58:10 +0800
Subject: [PATCH] chainloader: handle the unauthenticated image by shim
Upstream-Status: Pending
EFI_ACCESS_DENIED is another case whenever an unauthenticated image is loaded
by UEFI LoadImage() boot service. Shim verification protocol should handle
this case as EFI_SECURITY_VIOLATION.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
grub-core/loader/efi/chainloader.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index 9f908c3..2850627 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -868,7 +868,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
/* try with shim */
- else if (status == GRUB_EFI_SECURITY_VIOLATION)
+ else if ((status == GRUB_EFI_ACCESS_DENIED) || (status == GRUB_EFI_SECURITY_VIOLATION))
{
status = grub_shim_load_image (address, size, &context);
if (status != GRUB_EFI_SUCCESS)
--
1.9.1

View File

@@ -0,0 +1,38 @@
get_efivar -f uint8 -s secured SecureBoot
if [ "${secured}" = "1" ]; then
if [ -s "${prefix}/password.inc" ]; then
source "${prefix}/password.inc"
fi
fi
get_efivar -f uint8 -s unprovisioned SetupMode
if [ "${unprovisioned}" = "1" ]; then
# Create a boot entry for Automatic Certificate Provision.
# This is especially useful for certain hardware, e.g,
# Intel NUC5i3MYHE, doedn't support to display a customized
# BIOS boot option used to launch LockDown.efi.
if [ ! "${provision_failed}" ]; then
# Secure boot was disabled in BIOS setup. Overwrite the
# behavior of normal boot.
set timeout=0
set default="Automatic Certificate Provision"
elif [ "${provision_failed}" = "0" ]; then
# The auto provision was reset in BIOS setup.
set default="Automatic Certificate Provision"
fi
# This menu will be hidden as long as the provision succeeds.
menuentry "Automatic Certificate Provision" --unrestricted {
set provision_failed="0"
save_env provision_failed
chainloader "${prefix}/LockDown.efi"
# Refuse to unlimitedly run into auto provision if failed.
set provision_failed="1"
save_env provision_failed
}
fi

View File

@@ -0,0 +1,36 @@
set timeout=3
set color_normal="light-gray/black"
set color_highlight="light-green/blue"
# The first boot entry in normal boot.
set first_boot="0"
# The default boot entry after the first boot.
set default_boot="0"
function savedefault {
if [ "${chosen}" ]; then
next_boot="${chosen}"
save_env next_boot
fi
}
if [ -s "${prefix}/grubenv" ]; then
load_env
fi
if [ "${next_boot}" ]; then
set default="${next_boot}"
else
set default="${first_boot}"
set next_boot="${default_boot}"
save_env next_boot
fi
if [ -s "${prefix}/efi-secure-boot.inc" ]; then
source "${prefix}/efi-secure-boot.inc"
fi
if [ -s "${prefix}/boot-menu.inc" ]; then
source "${prefix}/boot-menu.inc"
fi

View File

@@ -0,0 +1,30 @@
From cd9fbf5dc00733f8e46966e67be85ff6f9d36e6e Mon Sep 17 00:00:00 2001
From: Paul Gortmaker <paul.gortmaker@windriver.com>
Date: Fri, 10 Apr 2015 18:38:23 -0400
Subject: [PATCH] grub: enable serial console by default
Have grub go to the serial console and the default VGA console.
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
---
util/grub.d/00_header.in | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in
index 765bfdcd30e3..86b260a2c380 100644
--- a/util/grub.d/00_header.in
+++ b/util/grub.d/00_header.in
@@ -27,6 +27,10 @@ grub_lang=`echo $LANG | cut -d . -f 1`
export TEXTDOMAIN=@PACKAGE@
export TEXTDOMAINDIR="@localedir@"
+export GRUB_TERMINAL_INPUT="console serial"
+export GRUB_TERMINAL_OUTPUT="console serial"
+export GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1"
+
. "@datadir@/@PACKAGE@/grub-mkconfig_lib"
# Do this as early as possible, since other commands might depend on it.
--
2.3.1

View File

@@ -0,0 +1,709 @@
From 46873e2c5514bf6460a2f0f39ad8f8feb8f18f68 Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Thu, 16 Mar 2017 14:49:41 +0800
Subject: [PATCH] mok2verify: support to verify non-PE file with PKCS#7
signature
MOK2 Verify Protocol is designed to verify non-PE file which cannot be
verified by the MOK verify protocol supplied by shim loader, such as grub
configuration, initrd, grub modules and so on.
Each signed file has a .p7b PKCS#7 signature file for verification. For
more details about signature format and singing tool, refer to
https://github.com/jiazhang0/SELoader and https://github.com/jiazhang0/libsign
If either kernel or initrd is not authenticated, just go to the failover
boot to avoid a much worse failure.
If any of grub config files is not authenticated, the boot process just
stops there.
In addition, the editor, rescue and cmdline modes are protected by the
combination of settings of secure boot and user authentication in order
to prevent from tampering the kernel commandline or booting unsigned
kernel.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
grub-core/Makefile.core.def | 6 ++
grub-core/commands/boot.c | 14 +++-
grub-core/gfxmenu/gui_label.c | 39 ++++++++--
grub-core/lib/efi/mok2verify.c | 172 +++++++++++++++++++++++++++++++++++++++++
grub-core/loader/i386/linux.c | 80 +++++++++++++++++++
grub-core/normal/main.c | 55 ++++++++++++-
grub-core/normal/menu.c | 29 +++++--
grub-core/normal/menu_text.c | 32 ++++++--
include/grub/efi/mok2verify.h | 48 ++++++++++++
9 files changed, 447 insertions(+), 28 deletions(-)
create mode 100644 grub-core/lib/efi/mok2verify.c
create mode 100644 include/grub/efi/mok2verify.h
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index e9e1483..8e72251 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1434,6 +1434,12 @@ module = {
};
module = {
+ name = mok2verify;
+ efi = lib/efi/mok2verify.c;
+ enable = efi;
+};
+
+module = {
name = mmap;
common = mmap/mmap.c;
x86 = mmap/i386/uppermem.c;
diff --git a/grub-core/commands/boot.c b/grub-core/commands/boot.c
index 91ec87d..5cddbb6 100644
--- a/grub-core/commands/boot.c
+++ b/grub-core/commands/boot.c
@@ -24,6 +24,9 @@
#include <grub/kernel.h>
#include <grub/mm.h>
#include <grub/i18n.h>
+#ifdef GRUB_MACHINE_EFI
+#include <grub/efi/mok2verify.h>
+#endif
GRUB_MOD_LICENSE ("GPLv3+");
@@ -143,8 +146,15 @@ grub_loader_boot (void)
struct grub_preboot *cur;
if (! grub_loader_loaded)
- return grub_error (GRUB_ERR_NO_KERNEL,
- N_("you need to load the kernel first"));
+ {
+#ifdef GRUB_MACHINE_EFI
+ if (grub_is_secured () == 1)
+ return grub_error (GRUB_ERR_BAD_OS,
+ N_("you need to load the authenticated boot components"));
+#endif
+ return grub_error (GRUB_ERR_NO_KERNEL,
+ N_("you need to load the kernel first"));
+ }
if (grub_loader_flags & GRUB_LOADER_FLAG_NORETURN)
grub_machine_fini ();
diff --git a/grub-core/gfxmenu/gui_label.c b/grub-core/gfxmenu/gui_label.c
index 637578f..84bf7d4 100644
--- a/grub-core/gfxmenu/gui_label.c
+++ b/grub-core/gfxmenu/gui_label.c
@@ -23,6 +23,9 @@
#include <grub/font.h>
#include <grub/gui_string_util.h>
#include <grub/i18n.h>
+#ifdef GRUB_MACHINE_EFI
+#include <grub/efi/mok2verify.h>
+#endif
static const char *align_options[] =
{
@@ -180,15 +183,37 @@ label_set_property (void *vself, const char *name, const char *value)
else
{
if (grub_strcmp (value, "@KEYMAP_LONG@") == 0)
- value = _("Press enter to boot the selected OS, "
- "`e' to edit the commands before booting "
- "or `c' for a command-line. ESC to return previous menu.");
+ {
+#ifdef GRUB_MACHINE_EFI
+ if (grub_is_locked () == 1)
+ value = _("Press enter to boot the selected OS. "
+ "ESC to return previous menu.");
+ else
+#endif
+ value = _("Press enter to boot the selected OS, "
+ "`e' to edit the commands before booting "
+ "or `c' for a command-line. ESC to return previous menu.");
+ }
else if (grub_strcmp (value, "@KEYMAP_MIDDLE@") == 0)
- value = _("Press enter to boot the selected OS, "
- "`e' to edit the commands before booting "
- "or `c' for a command-line.");
+ {
+#ifdef GRUB_MACHINE_EFI
+ if (grub_is_locked () == 1)
+ value = _("Press enter to boot the selected OS.");
+ else
+#endif
+ value = _("Press enter to boot the selected OS, "
+ "`e' to edit the commands before booting "
+ "or `c' for a command-line.");
+ }
else if (grub_strcmp (value, "@KEYMAP_SHORT@") == 0)
- value = _("enter: boot, `e': options, `c': cmd-line");
+ {
+#ifdef GRUB_MACHINE_EFI
+ if (grub_is_locked () == 1)
+ value = _("enter: boot");
+ else
+#endif
+ value = _("enter: boot, `e': options, `c': cmd-line");
+ }
/* FIXME: Add more templates here if needed. */
self->template = grub_strdup (value);
self->text = grub_xasprintf (value, self->value);
diff --git a/grub-core/lib/efi/mok2verify.c b/grub-core/lib/efi/mok2verify.c
new file mode 100644
index 0000000..2e48ef9
--- /dev/null
+++ b/grub-core/lib/efi/mok2verify.c
@@ -0,0 +1,172 @@
+/* mok2verify.c - MOK2 Verify Protocol support
+ *
+ * BSD 2-clause "Simplified" License
+ *
+ * Copyright (c) 2017, Lans Zhang <jia.zhang@windriver.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <grub/loader.h>
+#include <grub/file.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/charset.h>
+#include <grub/types.h>
+#include <grub/env.h>
+#include <grub/mm.h>
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/efi/mok2verify.h>
+
+GRUB_MOD_LICENSE ("GPLv2+");
+
+#define EFI_MOK2_VERIFY_PROTOCOL_GUID \
+ { 0x4eda73ad, 0x07aa, 0x4b7a, \
+ { 0xa1, 0x91, 0xd4, 0xd4, 0x10, 0xfb, 0x8c, 0xb4 } \
+ }
+
+typedef struct efi_mok2_verify_protocol efi_mok2_verify_protocol_t;
+
+typedef grub_efi_status_t
+(*grub_efi_mok2_verify_signature) (efi_mok2_verify_protocol_t *this,
+ void *signature,
+ grub_efi_uintn_t signature_size,
+ void *data, grub_efi_uintn_t data_size);
+
+typedef grub_efi_status_t
+(*grub_efi_mok2_verify_file_buffer) (efi_mok2_verify_protocol_t *this,
+ void **data, grub_efi_uintn_t *data_size,
+ const grub_efi_char16_t *path);
+
+typedef grub_efi_status_t
+(*grub_efi_mok2_verify_file) (efi_mok2_verify_protocol_t *this,
+ const grub_efi_char16_t *path);
+
+struct efi_mok2_verify_protocol {
+ grub_efi_uint8_t revision;
+ grub_efi_mok2_verify_signature verify_signature;
+ grub_efi_mok2_verify_file_buffer verify_file_buffer;
+ grub_efi_mok2_verify_file verify_file;
+};
+
+static grub_efi_guid_t grub_efi_mok2_verify_protoco_guid = EFI_MOK2_VERIFY_PROTOCOL_GUID;
+
+int
+grub_is_secured (void)
+{
+ grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
+ void *efi_var;
+ grub_size_t efi_var_size = 0;
+ int secured = 0;
+
+ efi_var = grub_efi_get_variable ("SecureBoot", &global, &efi_var_size);
+ if (!efi_var)
+ return grub_error (GRUB_ERR_READ_ERROR, N_("cannot read variable"));
+
+ if (efi_var_size == 1 && *(grub_uint8_t *) efi_var == 1)
+ secured = 1;
+
+ grub_free (efi_var);
+
+ return secured;
+}
+
+int
+grub_is_unlockable (void)
+{
+ return !! grub_env_get ("superusers");
+}
+
+int
+grub_is_locked (void)
+{
+ return ! grub_is_unlockable () && grub_is_secured ();
+}
+
+grub_err_t
+grub_verify_file (const char *path)
+{
+ efi_mok2_verify_protocol_t *mok2;
+ grub_efi_char16_t *p;
+ grub_size_t len = grub_strlen (path);
+ grub_efi_char16_t file_path[(len + 1) * GRUB_MAX_UTF16_PER_UTF8];
+ const char *root;
+ const char *real_path;
+ grub_efi_status_t status;
+
+ mok2 = grub_efi_locate_protocol (&grub_efi_mok2_verify_protoco_guid, 0);
+ if (!mok2)
+ {
+ grub_dprintf ("mok2verify", "unable to load mok2 verify protocol\n");
+ return GRUB_ERR_NONE;
+ }
+
+ grub_dprintf ("mok2verify", "attempting to verify the file %s ...\n", path);
+
+ real_path = path;
+ root = grub_env_get ("root");
+ if (root)
+ {
+ char *pattern;
+
+ pattern = grub_xasprintf ("(%s)", root);
+ if (!pattern)
+ return grub_errno;
+
+ if (grub_strstr (path, pattern) == path)
+ {
+ real_path = path + grub_strlen (pattern);
+ len -= grub_strlen (pattern);
+ }
+
+ grub_free (pattern);
+ }
+
+ len = grub_utf8_to_utf16 (file_path, len * GRUB_MAX_UTF16_PER_UTF8,
+ (const grub_uint8_t *) real_path, len, 0);
+ file_path[len] = 0;
+ for (p = file_path; p < file_path + len; ++p)
+ if (*p == '/')
+ *p = '\\';
+
+ status = efi_call_2 (mok2->verify_file, mok2, file_path);
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ if (status == GRUB_EFI_NOT_FOUND)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, "the specified file %s is not found",
+ path);
+ else
+ {
+ grub_printf ("failed to verify file %s (err: 0x%lx)\n",
+ path, status);
+
+ return grub_error (GRUB_ERR_ACCESS_DENIED, "the file %s is not verified",
+ path);
+ }
+ }
+
+ grub_dprintf ("mok2verify", "succeeded to verify file %s\n", path);
+
+ return GRUB_ERR_NONE;
+}
diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
index e2425c8..5a12444 100644
--- a/grub-core/loader/i386/linux.c
+++ b/grub-core/loader/i386/linux.c
@@ -34,6 +34,9 @@
#include <grub/i386/relocator.h>
#include <grub/i18n.h>
#include <grub/lib/cmdline.h>
+#ifdef GRUB_MACHINE_EFI
+#include <grub/efi/mok2verify.h>
+#endif
GRUB_MOD_LICENSE ("GPLv3+");
@@ -664,6 +667,55 @@ grub_linux_unload (void)
return GRUB_ERR_NONE;
}
+#ifdef GRUB_MACHINE_EFI
+static grub_err_t
+grub_verify_linux (const char *path)
+{
+ grub_file_t file;
+ grub_ssize_t size;
+ grub_uint8_t *buf = NULL;
+
+ grub_dprintf ("linux", "Verifying kernel %s\n", path);
+
+ file = grub_file_open (path);
+ if (!file)
+ return grub_errno;
+
+ size = grub_file_size (file);
+
+ buf = grub_malloc (size);
+ if (!buf)
+ goto fail;
+
+ if (grub_file_read (file, buf, size) != size)
+ {
+ if (!grub_errno)
+ grub_error (GRUB_ERR_BAD_OS, N_("premature end of kernel file %s"),
+ path);
+ goto fail;
+ }
+
+ if (grub_verify_file (path) == GRUB_ERR_NONE)
+ grub_dprintf ("linux", "kernel %s verified\n", path);
+ else
+ grub_error (grub_errno, N_("failed to verify kernel %s"), path);
+
+fail:
+ if (buf)
+ grub_free (buf);
+
+ grub_file_close (file);
+
+ return grub_errno;
+}
+#else
+static grub_err_t
+grub_verify_linux (const char *path)
+{
+ return GRUB_ERR_NONE;
+}
+#endif
+
static grub_err_t
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
@@ -687,6 +739,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
+ if (grub_verify_linux (argv[0]))
+ goto fail;
+
file = grub_file_open (argv[0]);
if (! file)
goto fail;
@@ -1132,6 +1187,26 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
argv[i]);
goto fail;
}
+
+#ifdef GRUB_MACHINE_EFI
+ grub_dprintf ("linux", "Verifying initrd %s, addr=0x%lx, size=0x%lx\n",
+ argv[i], (unsigned long) ptr, (unsigned long) cursize);
+
+ /*
+ * XXX: use grub_verify_file_buffer (argv[i], ptr, cursize) in future
+ */
+ err = grub_verify_file (argv[i]);
+ if (err == GRUB_ERR_NONE)
+ {
+ grub_dprintf ("linux", "initrd %s verified\n", argv[i]);
+ }
+ else
+ {
+ grub_error (err, N_("failed to verify initrd %s"), argv[i]);
+ goto fail;
+ }
+#endif
+
ptr += cursize;
grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
ptr += ALIGN_UP_OVERHEAD (cursize, 4);
@@ -1149,6 +1224,11 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
grub_file_close (files[i]);
grub_free (files);
+#ifdef GRUB_MACHINE_EFI
+ /* An unauthenticated initrd always causes a complete boot failure. */
+ if (grub_is_secured () == 1 && grub_errno != GRUB_ERR_NONE)
+ grub_loader_unset();
+#endif
return grub_errno;
}
diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
index 13473ec..f11ce2a 100644
--- a/grub-core/normal/main.c
+++ b/grub-core/normal/main.c
@@ -32,6 +32,9 @@
#include <grub/i18n.h>
#include <grub/charset.h>
#include <grub/script_sh.h>
+#ifdef GRUB_MACHINE_EFI
+#include <grub/efi/mok2verify.h>
+#endif
GRUB_MOD_LICENSE ("GPLv3+");
@@ -233,6 +236,16 @@ grub_normal_init_page (struct grub_term_output *term)
grub_term_cls (term);
+#ifdef GRUB_MACHINE_EFI
+ if (grub_is_secured () == 1)
+ {
+ if (grub_is_unlockable () == 1)
+ msg = _("GNU GRUB version %s (UNLOCKABLE)");
+ else
+ msg = _("GNU GRUB version %s (LOCKED)");
+ }
+#endif
+
msg_formatted = grub_xasprintf (msg, PACKAGE_VERSION);
if (!msg_formatted)
return;
@@ -294,6 +307,24 @@ grub_normal_execute (const char *config, int nested, int batch)
if (config)
{
+#ifdef GRUB_MACHINE_EFI
+ grub_err_t err;
+
+ err = grub_verify_file (config);
+ if (err != GRUB_ERR_NONE)
+ {
+ grub_error (err, "Security Violation: grub.cfg failed to load");
+ grub_print_error ();
+
+ /* System halt. */
+ asm volatile ("cli");
+ while (1)
+ {
+ asm volatile ("hlt");
+ }
+ }
+#endif
+
menu = read_config_file (config);
/* Ignore any error. */
@@ -317,7 +348,10 @@ grub_enter_normal_mode (const char *config)
{
nested_level++;
grub_normal_execute (config, 0, 0);
- grub_cmdline_run (0);
+#ifdef GRUB_MACHINE_EFI
+ if (grub_is_locked () == 0)
+#endif
+ grub_cmdline_run (0);
nested_level--;
if (grub_normal_exit_level)
grub_normal_exit_level--;
@@ -352,6 +386,18 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
grub_enter_normal_mode (argv[0]);
quit:
+#ifdef GRUB_MACHINE_EFI
+ if (grub_is_secured () == 1)
+ {
+ /* Never return back to the rescue mode */
+ asm volatile ("cli");
+
+ while (1)
+ {
+ asm volatile ("hlt");
+ }
+ }
+#endif
return 0;
}
@@ -527,8 +573,11 @@ GRUB_MOD_INIT(normal)
/* Register a command "normal" for the rescue mode. */
grub_register_command ("normal", grub_cmd_normal,
0, N_("Enter normal mode."));
- grub_register_command ("normal_exit", grub_cmd_normal_exit,
- 0, N_("Exit from normal mode."));
+#ifdef GRUB_MACHINE_EFI
+ if (grub_is_secured () == 0)
+#endif
+ grub_register_command ("normal_exit", grub_cmd_normal_exit,
+ 0, N_("Exit from normal mode."));
/* Reload terminal colors when these variables are written to. */
grub_register_variable_hook ("color_normal", NULL, grub_env_write_color_normal);
diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
index 7e0a158..5ed9670 100644
--- a/grub-core/normal/menu.c
+++ b/grub-core/normal/menu.c
@@ -32,6 +32,9 @@
#include <grub/script_sh.h>
#include <grub/gfxterm.h>
#include <grub/dl.h>
+#ifdef GRUB_MACHINE_EFI
+#include <grub/efi/mok2verify.h>
+#endif
/* Time to delay after displaying an error message about a default/fallback
entry failing to boot. */
@@ -633,18 +636,28 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
break;
case 'c':
- menu_fini ();
- grub_cmdline_run (1);
- goto refresh;
+#ifdef GRUB_MACHINE_EFI
+ if (grub_is_locked () == 0)
+#endif
+ {
+ menu_fini ();
+ grub_cmdline_run (1);
+ goto refresh;
+ }
case 'e':
- menu_fini ();
+#ifdef GRUB_MACHINE_EFI
+ if (grub_is_locked () == 0)
+#endif
{
- grub_menu_entry_t e = grub_menu_get_entry (menu, current_entry);
- if (e)
- grub_menu_entry_run (e);
+ menu_fini ();
+ {
+ grub_menu_entry_t e = grub_menu_get_entry (menu, current_entry);
+ if (e)
+ grub_menu_entry_run (e);
+ }
+ goto refresh;
}
- goto refresh;
default:
{
diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
index 1687c28..6e4fbfb 100644
--- a/grub-core/normal/menu_text.c
+++ b/grub-core/normal/menu_text.c
@@ -27,6 +27,9 @@
#include <grub/menu_viewer.h>
#include <grub/i18n.h>
#include <grub/charset.h>
+#ifdef GRUB_MACHINE_EFI
+#include <grub/efi/mok2verify.h>
+#endif
static grub_uint8_t grub_color_menu_normal;
static grub_uint8_t grub_color_menu_highlight;
@@ -179,19 +182,32 @@ command-line or ESC to discard edits and return to the GRUB menu."),
if (nested)
{
+#ifdef GRUB_MACHINE_EFI
+ if (grub_is_locked () == 1)
+ msg = _("Press enter to boot the selected OS. "
+ "ESC to return previous menu.");
+ else
+#endif
+ msg = _("Press enter to boot the selected OS, "
+ "`e' to edit the commands before booting "
+ "or `c' for a command-line. ESC to return previous menu.");
+
ret += grub_print_message_indented_real
- (_("Press enter to boot the selected OS, "
- "`e' to edit the commands before booting "
- "or `c' for a command-line. ESC to return previous menu."),
- STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
+ (msg, STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
}
else
{
+#ifdef GRUB_MACHINE_EFI
+ if (grub_is_locked () == 1)
+ msg = _("Press enter to boot the selected OS.");
+ else
+#endif
+ msg = _("Press enter to boot the selected OS, "
+ "`e' to edit the commands before booting "
+ "or `c' for a command-line.");
+
ret += grub_print_message_indented_real
- (_("Press enter to boot the selected OS, "
- "`e' to edit the commands before booting "
- "or `c' for a command-line."),
- STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
+ (msg, STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
}
}
return ret;
diff --git a/include/grub/efi/mok2verify.h b/include/grub/efi/mok2verify.h
new file mode 100644
index 0000000..98ef2d4
--- /dev/null
+++ b/include/grub/efi/mok2verify.h
@@ -0,0 +1,48 @@
+/*
+ * mok2verify.h - interface to MOK2 Verify Protocol
+ *
+ * BSD 2-clause "Simplified" License
+ *
+ * Copyright (c) 2017, Lans Zhang <jia.zhang@windriver.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GRUB_EFI_MOK2_VERIFY_HEADER
+#define GRUB_EFI_MOK2_VERIFY_HEADER 1
+
+#include <grub/types.h>
+
+int
+EXPORT_FUNC (grub_is_secured) (void);
+
+int
+EXPORT_FUNC (grub_is_locked) (void);
+
+int
+EXPORT_FUNC (grub_is_unlockable) (void);
+
+grub_err_t
+EXPORT_FUNC (grub_verify_file) (const char *path);
+
+#endif /* ! GRUB_EFI_MOK2_VERIFY_HEADER */
--
2.7.4

View File

@@ -0,0 +1,2 @@
set superusers="root"
password_pbkdf2 root grub.pbkdf2.sha512.10000.4039B6F2AC3D0E349479D2573BC4B206E022E9308DBCBA8F42FBBBF64B699B79A5426CE58503ACBB37CA4116CA1B95C89BEC5F804CB91C8ED5A7381C9E03EDE8.69E763E475CF993A6B4954F9BA863E45E8DFAF2BCEBEAAB21319DC766287FA1A621807F6E2AAD9277A6BA3B9B56A14C0918C441EE47BE304D23ADA562CA018E9

View File

@@ -0,0 +1,22 @@
---
grub-core/term/efi/console.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
--- a/grub-core/term/efi/console.c
+++ b/grub-core/term/efi/console.c
@@ -124,9 +124,12 @@ grub_console_getkey (struct grub_term_in
if (status != GRUB_EFI_SUCCESS)
return GRUB_TERM_NO_KEY;
- if (key.scan_code == 0)
- return key.unicode_char;
- else if (key.scan_code < ARRAY_SIZE (efi_codes))
+ if (key.scan_code == 0) {
+ if (key.unicode_char < 0x20 && key.unicode_char != 0 && key.unicode_char != '\t' && key.unicode_char != '\b' && key.unicode_char != '\n' && key.unicode_char != '\r')
+ return GRUB_TERM_CTRL | (key.unicode_char - 1 + 'a');
+ else
+ return key.unicode_char;
+ } else if (key.scan_code < ARRAY_SIZE (efi_codes))
return efi_codes[key.scan_code];
return GRUB_TERM_NO_KEY;

View File

@@ -0,0 +1,146 @@
FILESEXTRAPATHS_prepend := "${THISDIR}/grub-efi:"
EXTRA_SRC_URI = " \
${@'file://efi-secure-boot.inc file://password.inc' if d.getVar('UEFI_SB', True) == '1' else ''} \
"
SRC_URI += " \
file://0001-pe32.h-add-header-structures-for-TE-and-DOS-executab.patch \
file://0002-shim-add-needed-data-structures.patch \
file://0003-efi-chainloader-implement-an-UEFI-Exit-service-for-s.patch \
file://0004-efi-chainloader-port-shim-to-grub.patch \
file://0005-efi-chainloader-use-shim-to-load-and-verify-an-image.patch \
file://0006-efi-chainloader-boot-the-image-using-shim.patch \
file://0007-efi-chainloader-take-care-of-unload-undershim.patch \
file://chainloader-handle-the-unauthenticated-image-by-shim.patch \
file://chainloader-Don-t-check-empty-section-in-file-like-..patch \
file://chainloader-Actually-find-the-relocations-correctly-.patch \
file://Grub-get-and-set-efi-variables.patch \
file://Fix-32-bit-build-failures.patch;apply=0 \
file://Work-around-the-failure-of-ExitBootServices.patch;apply=0 \
file://serial-redirect-control-x-fix.patch;apply=0 \
file://mok2verify-support-to-verify-non-PE-file-with-PKCS-7.patch;apply=0 \
file://grub-efi.cfg \
file://boot-menu.inc \
${EXTRA_SRC_URI} \
"
EFI_BOOT_PATH = "/boot/efi/EFI/BOOT"
#GRUB_BUILDIN_append = " chain ${@'efivar mok2verify password_pbkdf2' if d.getVar('UEFI_SB', True) == '1' else ''}"
GRUB_BUILDIN_append += " chain ${@'efivar password_pbkdf2' if d.getVar('UEFI_SB', True) == '1' else ''}"
# For efi_call_foo and efi_shim_exit
CFLAGS_append = " -fno-toplevel-reorder"
# Set a default root specifier.
inherit user-key-store
python __anonymous () {
if d.getVar('UEFI_SB', True) != "1":
return
# Override the default filename if efi-secure-boot enabled.
# grub-efi must be renamed as grub${arch}.efi for working with shim
# or SELoader.
import re
target = d.getVar('TARGET_ARCH', True)
if target == "x86_64":
grubimage = "grubx64.efi"
elif re.match('i.86', target):
grubimage = "grubia32.efi"
else:
raise bb.parse.SkipPackage("grub-efi is incompatible with target %s" % target)
d.setVar("GRUB_IMAGE", grubimage)
}
do_compile_append_class-native() {
make grub-editenv
}
do_install_append_class-native() {
install -m 0755 grub-editenv "${D}${bindir}"
}
do_install_append_class-target() {
local menu="${WORKDIR}/boot-menu.inc"
# Enable the default IMA rules if IMA is enabled and encrypted-storage is
# disabled. This is because unseal operation will fail when any PCR is
# extended due to updating the aggregate integrity value by the default
# IMA rules.
[ x"${IMA}" = x"1" -a x"${@bb.utils.contains('DISTRO_FEATURES', 'encrypted-storage', '1', '0', d)}" != x"1" ] && {
! grep -q "ima_policy=tcb" "$menu" &&
sed -i 's/^\s*chainloader\s\+.*bzImage.*/& ima_policy=tcb/g' "$menu"
}
[ x"${UEFI_SB}" = x"1" ] && {
# Don't allow to load the detached initramfs if the bundled kernel used.
[ x"${INITRAMFS_IMAGE_BUNDLE}" = x"1" ] &&
sed -i 's/\(^\s*chainloader\s\+.*bzImage.*\)\s\+initrd=[^[:space:]]*\(.*\)/\1\2/g' "$menu"
}
# Install the stacked grub configs.
install -d "${D}${EFI_BOOT_PATH}"
install -m 0600 "${WORKDIR}/grub-efi.cfg" "${D}${EFI_BOOT_PATH}/grub.cfg"
install -m 0600 "$menu" "${D}${EFI_BOOT_PATH}"
[ x"${UEFI_SB}" = x"1" ] && {
install -m 0600 "${WORKDIR}/efi-secure-boot.inc" "${D}${EFI_BOOT_PATH}"
install -m 0600 "${WORKDIR}/password.inc" "${D}${EFI_BOOT_PATH}"
}
# Create the initial environment block with empty item.
grub-editenv "${D}${EFI_BOOT_PATH}/grubenv" create
install -d "${D}${EFI_BOOT_PATH}/${GRUB_TARGET}-efi"
grub-mkimage -p /EFI/BOOT -d "./grub-core" \
-O "${GRUB_TARGET}-efi" -o "${B}/${GRUB_IMAGE}" \
${GRUB_BUILDIN}
install -m 0644 "${B}/${GRUB_IMAGE}" "${D}${EFI_BOOT_PATH}/${GRUB_IMAGE}"
# Install the modules to grub-efi's search path
make -C grub-core install DESTDIR="${D}${EFI_BOOT_PATH}" pkglibdir=""
# Remove .module
rm -f ${D}${EFI_BOOT_PATH}/${GRUB_TARGET}-efi/*.module
}
fakeroot python do_sign_class-target() {
image_dir = d.getVar('D', True)
efi_boot_path = d.getVar('EFI_BOOT_PATH', True)
grub_image = d.getVar('GRUB_IMAGE', True)
dir = image_dir + efi_boot_path + '/'
sb_sign(dir + grub_image, dir + grub_image, d)
uks_sel_sign(dir + 'grub.cfg', d)
uks_sel_sign(dir + 'boot-menu.inc', d)
if d.getVar('UEFI_SB', True) == "1":
uks_sel_sign(dir + 'efi-secure-boot.inc', d)
uks_sel_sign(dir + 'password.inc', d)
}
fakeroot python do_sign() {
}
addtask sign after do_install before do_deploy do_package
# Override the do_deploy() in oe-core.
do_deploy_class-target() {
install -m 0644 "${D}${EFI_BOOT_PATH}/${GRUB_IMAGE}" "${DEPLOYDIR}"
install -d "${DEPLOYDIR}/efi-unsigned"
install -m 0644 "${B}/${GRUB_IMAGE}" "${DEPLOYDIR}/efi-unsigned"
cp -af "${D}${EFI_BOOT_PATH}/${GRUB_TARGET}-efi" "${DEPLOYDIR}/efi-unsigned"
}
FILES_${PN} += "/boot/efi"
CONFFILES_${PN} += " \
${EFI_BOOT_PATH}/grub.cfg \
${EFI_BOOT_PATH}/grubenv \
${EFI_BOOT_PATH}/boot-menu.inc \
${EFI_BOOT_PATH}/efi-secure-boot.inc \
"

View File

@@ -0,0 +1,94 @@
SUMMARY = "The bootloader capable of authenticating the PE and non-PE files."
DESCRIPTION = "The SELoader is designed to authenticate the non-PE files, \
such as grub configuration, initrd, grub modules, which cannot be verified \
by the MOK Verify Protocol registered by shim loader. \
\
In order to conveniently authenticate the PE file with gBS->LoadImage() \
and gBS->StartImage(), the SELoader hooks EFI Security2 Architectural \
Protocol and employs MOK Verify Protocol to verify the PE file. If only \
UEFI Secure Boot is enabled, the SELoader just simplily calls \
gBS->LoadImage() and gBS->StartImage() to allow BIOS to verify PE file. \
\
The SELoader publishes MOK2 Verify Protocol which provides a flexible \
interface to allow the bootloader to verify the file, file buffer or \
memory buffer without knowing the file format. \
"
HOMEPAGE = "https://github.com/jiazhang0/SELoader.git"
SECTION = "bootloaders"
LICENSE = "BSD-3-Clause"
LIC_FILES_CHKSUM = "file://LICENSE;md5=d9bf404642f21afb4ad89f95d7bc91ee"
PR = "r0"
SRC_URI = " \
git://github.com/jiazhang0/SELoader.git \
"
SRCREV = "32e3292c33603f319354aac273938fe63897a8da"
PV = "0.4.5+git${SRCPV}"
COMPATIBLE_HOST = '(i.86|x86_64).*-linux'
inherit deploy user-key-store
S = "${WORKDIR}/git"
DEPENDS += " \
gnu-efi sbsigntool-native \
"
EFI_ARCH_x86 = "ia32"
EFI_ARCH_x86-64 = "x64"
EXTRA_OEMAKE = " \
CROSS_COMPILE="${TARGET_PREFIX}" \
SBSIGN=${STAGING_BINDIR_NATIVE}/sbsign \
gnuefi_libdir=${STAGING_LIBDIR} \
LIB_GCC="`${CC} -print-libgcc-file-name`" \
"
PARALLEL_MAKE = ""
EFI_TARGET = "/boot/efi/EFI/BOOT"
FILES_${PN} += "${EFI_TARGET}"
python do_sign() {
sb_sign(d.expand('${B}/Src/Efi/SELoader.efi'), d.expand('${B}/Src/Efi/SELoader.efi.signed'), d)
sb_sign(d.expand('${B}/Bin/Hash2DxeCrypto.efi'), d.expand('${B}/Bin/Hash2DxeCrypto.efi.signed'), d)
sb_sign(d.expand('${B}/Bin/Pkcs7VerifyDxe.efi'), d.expand('${B}/Bin/Pkcs7VerifyDxe.efi.signed'), d)
}
addtask sign after do_compile before do_install
do_install() {
install -d ${D}${EFI_TARGET}
oe_runmake install EFI_DESTDIR=${D}${EFI_TARGET}
if [ x"${UEFI_SB}" = x"1" ]; then
if [ x"${MOK_SB}" != x"1" ]; then
mv ${D}${EFI_TARGET}/SELoader${EFI_ARCH}.efi \
${D}${EFI_TARGET}/boot${EFI_ARCH}.efi
fi
fi
}
do_deploy() {
# Deploy the unsigned images for manual signing
install -d ${DEPLOYDIR}/efi-unsigned
install -m 0600 ${B}/Src/Efi/SELoader.efi \
${DEPLOYDIR}/efi-unsigned/SELoader${EFI_ARCH}.efi
install -m 0600 ${B}/Bin/Hash2DxeCrypto.efi ${DEPLOYDIR}/efi-unsigned/
install -m 0600 ${B}/Bin/Pkcs7VerifyDxe.efi ${DEPLOYDIR}/efi-unsigned/
# Deploy the signed images
if [ x"${UEFI_SB}" = x"1" -a x"${MOK_SB}" != x"1" ]; then
SEL_NAME=boot
else
SEL_NAME=SELoader
fi
install -m 0600 ${D}${EFI_TARGET}/${SEL_NAME}${EFI_ARCH}.efi \
${DEPLOYDIR}/${SEL_NAME}${EFI_ARCH}.efi
install -m 0600 ${D}${EFI_TARGET}/Hash2DxeCrypto.efi \
${DEPLOYDIR}/Hash2DxeCrypto.efi
install -m 0600 ${D}${EFI_TARGET}/Pkcs7VerifyDxe.efi \
${DEPLOYDIR}/Pkcs7VerifyDxe.efi
}
addtask deploy after do_install before do_build

View File

@@ -0,0 +1,156 @@
From 88806eaf9f1726d06eb4e88f12ca86537dbaab75 Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Fri, 16 Jun 2017 15:16:35 +0800
Subject: [PATCH] shim: allow to verify sha1 digest for Authenticode
Upstream-Status: Pending
The EV code signing cert sometimes doesn't comply the Authenticode spec to
employ a sha256 digest.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
shim.c | 48 +++++++++++++++++++++++++++++++++++-------------
1 file changed, 35 insertions(+), 13 deletions(-)
diff --git a/shim.c b/shim.c
index 6e040c4..384ccd7 100644
--- a/shim.c
+++ b/shim.c
@@ -428,7 +428,8 @@ static BOOLEAN verify_eku(UINT8 *Cert, UINTN CertSize)
static CHECK_STATUS check_db_cert_in_ram(EFI_SIGNATURE_LIST *CertList,
UINTN dbsize,
WIN_CERTIFICATE_EFI_PKCS *data,
- UINT8 *hash)
+ UINT8 *hash,
+ UINTN hashsize)
{
EFI_SIGNATURE_DATA *Cert;
UINTN CertSize;
@@ -445,7 +446,7 @@ static CHECK_STATUS check_db_cert_in_ram(EFI_SIGNATURE_LIST *CertList,
data->Hdr.dwLength - sizeof(data->Hdr),
Cert->SignatureData,
CertSize,
- hash, SHA256_DIGEST_SIZE);
+ hash, hashsize);
if (IsFound)
return DATA_FOUND;
}
@@ -462,7 +463,7 @@ static CHECK_STATUS check_db_cert_in_ram(EFI_SIGNATURE_LIST *CertList,
}
static CHECK_STATUS check_db_cert(CHAR16 *dbname, EFI_GUID guid,
- WIN_CERTIFICATE_EFI_PKCS *data, UINT8 *hash)
+ WIN_CERTIFICATE_EFI_PKCS *data, UINT8 *hash, UINTN hashsize)
{
CHECK_STATUS rc;
EFI_STATUS efi_status;
@@ -477,7 +478,7 @@ static CHECK_STATUS check_db_cert(CHAR16 *dbname, EFI_GUID guid,
CertList = (EFI_SIGNATURE_LIST *)db;
- rc = check_db_cert_in_ram(CertList, dbsize, data, hash);
+ rc = check_db_cert_in_ram(CertList, dbsize, data, hash, hashsize);
FreePool(db);
@@ -571,7 +572,8 @@ static EFI_STATUS check_blacklist (WIN_CERTIFICATE_EFI_PKCS *cert,
DATA_FOUND)
return EFI_SECURITY_VIOLATION;
if (cert && check_db_cert_in_ram(dbx, vendor_dbx_size, cert,
- sha256hash) == DATA_FOUND)
+ sha256hash, SHA256_DIGEST_SIZE) ==
+ DATA_FOUND)
return EFI_SECURITY_VIOLATION;
if (check_db_hash(L"dbx", secure_var, sha256hash, SHA256_DIGEST_SIZE,
@@ -580,14 +582,14 @@ static EFI_STATUS check_blacklist (WIN_CERTIFICATE_EFI_PKCS *cert,
if (check_db_hash(L"dbx", secure_var, sha1hash, SHA1_DIGEST_SIZE,
EFI_CERT_SHA1_GUID) == DATA_FOUND)
return EFI_SECURITY_VIOLATION;
- if (cert && check_db_cert(L"dbx", secure_var, cert, sha256hash) ==
+ if (cert && check_db_cert(L"dbx", secure_var, cert, sha256hash, SHA256_DIGEST_SIZE) ==
DATA_FOUND)
return EFI_SECURITY_VIOLATION;
if (check_db_hash(L"MokListX", shim_var, sha256hash, SHA256_DIGEST_SIZE,
EFI_CERT_SHA256_GUID) == DATA_FOUND) {
return EFI_SECURITY_VIOLATION;
}
- if (cert && check_db_cert(L"MokListX", shim_var, cert, sha256hash) ==
+ if (cert && check_db_cert(L"MokListX", shim_var, cert, sha256hash, SHA256_DIGEST_SIZE) ==
DATA_FOUND) {
return EFI_SECURITY_VIOLATION;
}
@@ -622,7 +624,7 @@ static EFI_STATUS check_whitelist (WIN_CERTIFICATE_EFI_PKCS *cert,
update_verification_method(VERIFIED_BY_HASH);
return EFI_SUCCESS;
}
- if (cert && check_db_cert(L"db", secure_var, cert, sha256hash)
+ if (cert && check_db_cert(L"db", secure_var, cert, sha256hash, SHA256_DIGEST_SIZE)
== DATA_FOUND) {
verification_method = VERIFIED_BY_CERT;
update_verification_method(VERIFIED_BY_CERT);
@@ -636,7 +638,7 @@ static EFI_STATUS check_whitelist (WIN_CERTIFICATE_EFI_PKCS *cert,
update_verification_method(VERIFIED_BY_HASH);
return EFI_SUCCESS;
}
- if (cert && check_db_cert(L"MokList", shim_var, cert, sha256hash) ==
+ if (cert && check_db_cert(L"MokList", shim_var, cert, sha256hash, SHA256_DIGEST_SIZE) ==
DATA_FOUND) {
verification_method = VERIFIED_BY_CERT;
update_verification_method(VERIFIED_BY_CERT);
@@ -1020,27 +1022,47 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
/*
* Check against the shim build key
*/
- if (sizeof(shim_cert) &&
- AuthenticodeVerify(cert->CertData,
+ if (sizeof(shim_cert)) {
+ if (AuthenticodeVerify(cert->CertData,
cert->Hdr.dwLength - sizeof(cert->Hdr),
shim_cert, sizeof(shim_cert), sha256hash,
SHA256_DIGEST_SIZE)) {
update_verification_method(VERIFIED_BY_CERT);
status = EFI_SUCCESS;
return status;
+ }
+
+ if (AuthenticodeVerify(cert->CertData,
+ cert->Hdr.dwLength - sizeof(cert->Hdr),
+ shim_cert, sizeof(shim_cert), sha1hash,
+ SHA1_DIGEST_SIZE)) {
+ update_verification_method(VERIFIED_BY_CERT);
+ status = EFI_SUCCESS;
+ return status;
+ }
}
/*
* And finally, check against shim's built-in key
*/
- if (vendor_cert_size &&
- AuthenticodeVerify(cert->CertData,
+ if (vendor_cert_size) {
+ if (AuthenticodeVerify(cert->CertData,
cert->Hdr.dwLength - sizeof(cert->Hdr),
vendor_cert, vendor_cert_size,
sha256hash, SHA256_DIGEST_SIZE)) {
update_verification_method(VERIFIED_BY_CERT);
status = EFI_SUCCESS;
return status;
+ }
+
+ if (AuthenticodeVerify(cert->CertData,
+ cert->Hdr.dwLength - sizeof(cert->Hdr),
+ vendor_cert, vendor_cert_size,
+ sha1hash, SHA1_DIGEST_SIZE)) {
+ update_verification_method(VERIFIED_BY_CERT);
+ status = EFI_SUCCESS;
+ return status;
+ }
}
}
--
2.7.5

View File

@@ -0,0 +1,36 @@
From 85e74fa95094175753e39acdd694f9c639069abf Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Fri, 18 Mar 2016 12:30:08 +0800
Subject: [PATCH 05/11] Fix signing failure due to not finding certificate
Upstream-Status: Pending
The shim.p12 containing private sample key should be imported after
importing the corresponding certificate shim.crt. Otherwise, the
nick name of shim certificate cannot be used.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
Makefile | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile
index dcfa357..efab050 100644
--- a/Makefile
+++ b/Makefile
@@ -124,10 +124,10 @@ version.c : version.c.in
-e "s,@@COMMIT@@,$(shell if [ -d .git ] ; then git log -1 --pretty=format:%H ; elif [ -f commit ]; then cat commit ; else echo commit id not available; fi)," \
< version.c.in > version.c
-certdb/secmod.db: shim.crt
+certdb/secmod.db: shim.crt shim.p12
-mkdir certdb
- $(PK12UTIL) -d certdb/ -i shim.p12 -W "" -K ""
$(CERTUTIL) -d certdb/ -A -i shim.crt -n shim -t u
+ $(PK12UTIL) -d certdb/ -i shim.p12 -W "" -K ""
shim.o: $(SOURCES) shim_cert.h
shim.o: $(wildcard *.h)
--
2.11.0

View File

@@ -0,0 +1,33 @@
From 1f03018aa0b7df2eab576d410ec88e8cf66b06e0 Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Wed, 21 Sep 2016 11:25:14 +0800
Subject: [PATCH 06/11] Prevent from removing intermediate .efi
Upstream-Status: Pending
Otherwise Make will delete the .efi during the build:
sysroots/x86_64-linux/usr/bin/pesign -n certdb -i MokManager.efi -c "shim" -s -o MokManager.efi.signed -f
rm fallback.efi MokManager.efi
DEBUG: Shell function do_compile finished
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
Makefile | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Makefile b/Makefile
index efab050..7c71993 100644
--- a/Makefile
+++ b/Makefile
@@ -100,6 +100,8 @@ MOK_SOURCES = MokManager.c shim.h include/console.h PasswordCrypt.c PasswordCryp
FALLBACK_OBJS = fallback.o
FALLBACK_SRCS = fallback.c
+.PRECIOUS: $(MMNAME).efi $(FBNAME).efi
+
ifneq ($(origin ENABLE_HTTPBOOT), undefined)
OBJS += httpboot.o
SOURCES += httpboot.c httpboot.h
--
2.11.0

View File

@@ -0,0 +1,44 @@
From 04da6c928d5f15b7adb6c51e55b9aa0a8126063d Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Wed, 21 Sep 2016 11:31:02 +0800
Subject: [PATCH 07/11] Use sbsign to sign MokManager and fallback
Upstream-Status: Pending
pesign is written with -std=gnu11 and thus the host gcc version lower
than 4.7 cannot build out pesign.
sbsign is another alternate used to sign efi binary and it works well.
Therefore, drop to use sbsign to sign efi binary.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
Makefile | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile
index 7c71993..58b4b4c 100644
--- a/Makefile
+++ b/Makefile
@@ -12,6 +12,7 @@ HEXDUMP ?= hexdump
PK12UTIL ?= pk12util
CERTUTIL ?= certutil
PESIGN ?= pesign
+SBSIGN ?= sbsign
ARCH = $(shell $(CC) -dumpmachine | cut -f1 -d- | sed s,i[3456789]86,ia32,)
OBJCOPY_GTE224 = $(shell expr `$(OBJCOPY) --version |grep ^"GNU objcopy" | sed 's/^.*\((.*)\|version\) //g' | cut -f1-2 -d.` \>= 2.24)
@@ -190,8 +191,8 @@ endif
-j .note.gnu.build-id \
$(FORMAT) $^ $@.debug
-%.efi.signed: %.efi certdb/secmod.db
- $(PESIGN) -n certdb -i $< -c "shim" -s -o $@ -f
+%.efi.signed: %.efi shim.key shim.crt
+ $(SBSIGN) --key shim.key --cert shim.crt --output $@ $<
clean:
$(MAKE) -C Cryptlib clean
--
2.11.0

View File

@@ -0,0 +1,35 @@
From 508a31905aff2d271f1b82a5a36a614113b7fe85 Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Mon, 6 Jun 2016 16:28:09 +0800
Subject: [PATCH 08/11] Fix the world build failure due to the missing rule of
generating shim.key
Upstream-Status: Pending
shim.key is not given without feature/mok-secure-boot, the script
make-certs already integrated in shim is able to generate it and shim.crt
for signing. However, the commit 79c0d3ab3964ff03483277a515aaf50016bbe786
forgets to add the rule of generating shim.key, causing the world build
failure.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index 58b4b4c..0da5e6c 100644
--- a/Makefile
+++ b/Makefile
@@ -110,7 +110,7 @@ endif
all: $(TARGET)
-shim.crt:
+shim.crt shim.key:
./make-certs shim shim@xn--u4h.net all codesign 1.3.6.1.4.1.311.10.3.1 </dev/null
shim.cer: shim.crt
--
2.11.0

View File

@@ -0,0 +1,35 @@
From b3d57a092d837fe8134e0b3ff408040fa33d4efc Mon Sep 17 00:00:00 2001
From: Yunguo Wei <yunguo.wei@windriver.com>
Date: Wed, 28 Dec 2016 11:08:37 +0800
Subject: [PATCH 10/11] Makefile: do not sign the efi file
Shim tries to sign all the efi binaries at build time, but is not
suitable for us. Because the private key has to be supplied, and this
doesn't make sense to EDSS key.
We will use a seperated function in bitbake file to
sign these efi binaries, so that we can freely use EDSS key, Wind
River sample key or user key.
Signed-off-by: Yunguo Wei <yunguo.wei@windriver.com>
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index 24e21a8..0912cd0 100644
--- a/Makefile
+++ b/Makefile
@@ -92,7 +92,7 @@ endif
LDFLAGS = --hash-style=sysv -nostdlib -znocombreloc -T $(EFI_LDS) -shared -Bsymbolic -L$(EFI_PATH) -L$(LIB_PATH) -LCryptlib -LCryptlib/OpenSSL $(EFI_CRT_OBJS) --build-id=sha1
-TARGET = $(SHIMNAME).efi $(MMNAME).efi.signed $(FBNAME).efi.signed
+TARGET = $(SHIMNAME).efi $(MMNAME).efi $(FBNAME).efi
OBJS = shim.o netboot.o cert.o replacements.o tpm.o version.o
KEYS = shim_cert.h ocsp.* ca.* shim.crt shim.csr shim.p12 shim.pem shim.key shim.cer
SOURCES = shim.c shim.h netboot.c include/PeImage.h include/wincert.h include/console.h replacements.c replacements.h tpm.c tpm.h version.c version.h
--
2.11.0

View File

@@ -0,0 +1,69 @@
From 62489adc36c5177f90ed16af936a4c0a992cea7e Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Wed, 21 Sep 2016 11:17:29 +0800
Subject: [PATCH 11/11] Update verification_method if the loaded image is
signed by shim/vendor cert
Upstream-Status: Pending
Also, if the loaded image is not verfied by cert, the validation process
should be allowed as well.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
replacements.c | 2 +-
shim.c | 4 ++++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/replacements.c b/replacements.c
index 01eda0e..9ed5a5d 100644
--- a/replacements.c
+++ b/replacements.c
@@ -144,7 +144,7 @@ start_image(EFI_HANDLE image_handle, UINTN *exit_data_size, CHAR16 **exit_data)
static EFI_STATUS EFIAPI
exit_boot_services(EFI_HANDLE image_key, UINTN map_key)
{
- if (loader_is_participating || verification_method == VERIFIED_BY_HASH) {
+ if (loader_is_participating || verification_method != VERIFIED_BY_NOTHING) {
unhook_system_services();
EFI_STATUS status;
status = systab->BootServices->ExitBootServices(image_key, map_key);
diff --git a/shim.c b/shim.c
index 364784b..ef62145 100644
--- a/shim.c
+++ b/shim.c
@@ -1029,6 +1029,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
cert->Hdr.dwLength - sizeof(cert->Hdr),
shim_cert, sizeof(shim_cert), sha256hash,
SHA256_DIGEST_SIZE)) {
+ update_verification_method(VERIFIED_BY_CERT);
status = EFI_SUCCESS;
return status;
}
@@ -1037,6 +1038,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
cert->Hdr.dwLength - sizeof(cert->Hdr),
shim_cert, sizeof(shim_cert), sha1hash,
SHA1_DIGEST_SIZE)) {
+ update_verification_method(VERIFIED_BY_CERT);
status = EFI_SUCCESS;
return status;
}
@@ -1050,6 +1052,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
cert->Hdr.dwLength - sizeof(cert->Hdr),
vendor_cert, vendor_cert_size,
sha256hash, SHA256_DIGEST_SIZE)) {
+ update_verification_method(VERIFIED_BY_CERT);
status = EFI_SUCCESS;
return status;
}
@@ -1058,6 +1061,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
cert->Hdr.dwLength - sizeof(cert->Hdr),
vendor_cert, vendor_cert_size,
sha1hash, SHA1_DIGEST_SIZE)) {
+ update_verification_method(VERIFIED_BY_CERT);
status = EFI_SUCCESS;
return status;
}
--
2.11.0

View File

@@ -0,0 +1,28 @@
From 1f22dc6be768b7032b73ea963901de270e3c99d9 Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Sun, 18 Jun 2017 21:50:26 +0800
Subject: [PATCH] netboot: replace the depreciated EFI_PXE_BASE_CODE
The newer gnu-efi already uses EFI_PXE_BASE_CODE_PROTOCOL instead.
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
netboot.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/netboot.c b/netboot.c
index 1cc1a2b..32c9b0a 100644
--- a/netboot.c
+++ b/netboot.c
@@ -43,7 +43,7 @@
#define ntohs(x) __builtin_bswap16(x) /* supported both by GCC and clang */
#define htons(x) ntohs(x)
-static EFI_PXE_BASE_CODE *pxe;
+static EFI_PXE_BASE_CODE_PROTOCOL *pxe;
static EFI_IP_ADDRESS tftp_addr;
static CHAR8 *full_path;
--
2.7.5

View File

@@ -0,0 +1,30 @@
Copyright 2012 Red Hat, Inc <mjg@redhat.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
Significant portions of this code are derived from Tianocore
(http://tianocore.sf.net) and are Copyright 2009-2012 Intel
Corporation.

View File

@@ -0,0 +1,137 @@
SUMMARY = "shim is a trivial EFI application."
DESCRIPTION = "shim is a trivial EFI application that, when run, attempts to open and \
execute another application. It will initially attempt to do this via the \
standard EFI LoadImage() and StartImage() calls. If these fail (because secure \
boot is enabled and the binary is not signed with an appropriate key, for \
instance) it will then validate the binary against a built-in certificate. If \
this succeeds and if the binary or signing key are not blacklisted then shim \
will relocate and execute the binary."
HOMEPAGE = "https://github.com/rhinstaller/shim.git"
SECTION = "bootloaders"
LICENSE = "BSD-2-Clause"
LIC_FILES_CHKSUM = "file://COPYRIGHT;md5=b92e63892681ee4e8d27e7a7e87ef2bc"
PR = "r0"
COMPATIBLE_HOST = '(i.86|x86_64).*-linux'
inherit deploy user-key-store
SRC_URI = " \
git://github.com/rhinstaller/shim.git \
file://0001-shim-allow-to-verify-sha1-digest-for-Authenticode.patch \
file://0005-Fix-signing-failure-due-to-not-finding-certificate.patch;apply=0 \
file://0006-Prevent-from-removing-intermediate-.efi.patch \
file://0007-Use-sbsign-to-sign-MokManager-and-fallback.patch \
file://0008-Fix-the-world-build-failure-due-to-the-missing-rule-.patch \
file://0010-Makefile-do-not-sign-the-efi-file.patch \
file://0011-Update-verification_method-if-the-loaded-image-is-si.patch;apply=0 \
file://0012-netboot-replace-the-depreciated-EFI_PXE_BASE_CODE.patch \
"
SRC_URI_append_x86-64 = " \
${@bb.utils.contains('DISTRO_FEATURES', 'msft', 'file://shim${EFI_ARCH}.efi.signed file://LICENSE' if uks_signing_model(d) == 'sample' else '', '', d)} \
"
SRCREV = "55c65546e46a78edbe41e88cb4ccbd2522e09625"
PV = "12+git${SRCPV}"
S = "${WORKDIR}/git"
DEPENDS += "\
gnu-efi nss openssl util-linux-native openssl-native nss-native \
"
EFI_ARCH_x86 = "ia32"
EFI_ARCH_x86-64 = "x64"
EXTRA_OEMAKE = " \
CROSS_COMPILE="${TARGET_PREFIX}" \
LIB_GCC="`${CC} -print-libgcc-file-name`" \
LIB_PATH="${STAGING_LIBDIR}" \
EFI_PATH="${STAGING_LIBDIR}" \
EFI_INCLUDE="${STAGING_INCDIR}/efi" \
RELEASE="_${DISTRO}_${DISTRO_VERSION}" \
DEFAULT_LOADER=\\\\\\SELoader${EFI_ARCH}.efi \
OPENSSL=${STAGING_BINDIR_NATIVE}/openssl \
HEXDUMP=${STAGING_BINDIR_NATIVE}/hexdump \
PK12UTIL=${STAGING_BINDIR_NATIVE}/pk12util \
CERTUTIL=${STAGING_BINDIR_NATIVE}/certutil \
SBSIGN=${STAGING_BINDIR_NATIVE}/sbsign \
AR=${AR} \
${@'VENDOR_CERT_FILE=${WORKDIR}/vendor_cert.cer' if d.getVar('MOK_SB', True) == '1' else ''} \
${@'VENDOR_DBX_FILE=${WORKDIR}/vendor_dbx.esl' if uks_signing_model(d) == 'user' else ''} \
"
PARALLEL_MAKE = ""
EFI_TARGET = "/boot/efi/EFI/BOOT"
FILES_${PN} += "${EFI_TARGET}"
MSFT = "${@bb.utils.contains('DISTRO_FEATURES', 'msft', '1', '0', d)}"
# Prepare the signing certificate and keys
python do_prepare_signing_keys() {
# For UEFI_SB, shim is not built
if d.getVar('MOK_SB', True) != '1':
return
path = create_mok_vendor_dbx(d)
# Prepare shim_cert and vendor_cert.
dir = mok_sb_keys_dir(d)
import shutil
shutil.copyfile(dir + 'shim_cert.pem', d.getVar('S', True) + '/shim.crt')
pem2der(dir + 'vendor_cert.pem', d.getVar('WORKDIR', True) + '/vendor_cert.cer', d)
# Replace the shim certificate with EV certificate for speeding up
# the progress of MSFT signing.
if d.expand('${MSFT}') == "1" and uks_signing_model(d) == "sample":
shutil.copyfile(d.expand('${EV_CERT}'), d.expand('${S}/shim.crt'))
}
addtask prepare_signing_keys after do_configure before do_compile
python do_sign() {
# The pre-signed shim binary will override the one built from the
# scratch.
pre_signed = d.expand('${WORKDIR}/shim${EFI_ARCH}.efi.signed')
dst = d.expand('${B}/shim${EFI_ARCH}.efi.signed')
if d.expand('${MSFT}') == "1" and os.path.exists(pre_signed):
import shutil
shutil.copyfile(pre_signed, dst)
else:
if uks_signing_model(d) in ('sample', 'user'):
uefi_sb_sign(d.expand('${S}/shim${EFI_ARCH}.efi'), dst, d)
elif uks_signing_model(d) == 'edss':
edss_sign_efi_image(d.expand('${S}/shim${EFI_ARCH}.efi'), dst, d)
sb_sign(d.expand('${S}/mm${EFI_ARCH}.efi'), d.expand('${B}/mm${EFI_ARCH}.efi.signed'), d)
sb_sign(d.expand('${S}/fb${EFI_ARCH}.efi'), d.expand('${B}/fb${EFI_ARCH}.efi.signed'), d)
}
addtask sign after do_compile before do_install
do_install() {
install -d ${D}${EFI_TARGET}
local shim_dst="${D}${EFI_TARGET}/boot${EFI_ARCH}.efi"
local mm_dst="${D}${EFI_TARGET}/mm${EFI_ARCH}.efi"
if [ x"${UEFI_SB}" = x"1" ]; then
install -m 0600 ${B}/shim${EFI_ARCH}.efi.signed $shim_dst
install -m 0600 ${B}/mm${EFI_ARCH}.efi.signed $mm_dst
else
install -m 0600 ${B}/shim${EFI_ARCH}.efi $shim_dst
install -m 0600 ${B}/mm${EFI_ARCH}.efi $mm_dst
fi
}
# Install the unsigned images for manual signing
do_deploy() {
install -d ${DEPLOYDIR}/efi-unsigned
install -m 0600 ${B}/shim${EFI_ARCH}.efi ${DEPLOYDIR}/efi-unsigned/boot${EFI_ARCH}.efi
install -m 0600 ${B}/mm${EFI_ARCH}.efi ${DEPLOYDIR}/efi-unsigned/mm${EFI_ARCH}.efi
install -m 0600 "${D}${EFI_TARGET}/boot${EFI_ARCH}.efi" "${DEPLOYDIR}"
install -m 0600 "${D}${EFI_TARGET}/mm${EFI_ARCH}.efi" "${DEPLOYDIR}"
}
addtask deploy after do_install before do_build

View File

@@ -0,0 +1,7 @@
DEPENDS += " \
${@bb.utils.contains('MACHINE_FEATURES', 'efi', 'gnu-efi', '', d)} \
"
EXTRA_OECONF += " \
${@bb.utils.contains('MACHINE_FEATURES', 'efi', '--enable-efi --enable-gnuefi --with-efi-libdir=${STAGING_LIBDIR} --with-efi-ldsdir=${STAGING_LIBDIR} --with-efi-includedir=${STAGING_INCDIR}', '', d)} \
"

View File

@@ -0,0 +1,48 @@
SUMMARY = "A generic signing tool framework"
DESCRIPTION = " \
This project targets to provide a generic signing framework. This framework \
separates the signing request and signing process and correspondingly forms \
the so-called signlet and signaturelet. \
Each signaturelet only concerns about the details about how to construct the \
layout of a signature format, and signlet only cares how to construct the \
signing request. \
"
SECTION = "devel"
LICENSE = "BSD-3-Clause"
LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=d9bf404642f21afb4ad89f95d7bc91ee"
SRC_URI = " \
git://github.com/jiazhang0/libsign.git \
"
SRCREV = "dfab84b4235a36bb395bc6663e50578bb2f9edca"
PV = "0.3.2+git${SRCPV}"
DEPENDS += "openssl"
RDEPENDS_${PN}_class-target += "libcrypto"
RDEPENDS_${PN}_class-native += "openssl"
PARALLEL_MAKE = ""
S = "${WORKDIR}/git"
EXTRA_OEMAKE = " \
CC="${CC}" \
bindir="${STAGING_BINDIR}" \
libdir="${STAGING_LIBDIR}" \
includedir="${STAGING_INCDIR}" \
EXTRA_CFLAGS="${CFLAGS}" \
EXTRA_LDFLAGS="${LDFLAGS}" \
SIGNATURELET_DIR="${libdir}/signaturelet" \
BINDIR="${bindir}" \
LIBDIR="${libdir}" \
"
do_install() {
oe_runmake install DESTDIR="${D}"
}
FILES_${PN} += " \
${libdir}/signaturelet \
"
BBCLASSEXTEND = "native"

View File

@@ -0,0 +1,50 @@
SUMMARY = "Signing utility for UEFI secure boot"
LICENSE = "GPLv3"
LIC_FILES_CHKSUM = "file://LICENSE.GPLv3;md5=9eef91148a9b14ec7f9df333daebc746"
SRC_URI = "git://kernel.ubuntu.com/jk/sbsigntool \
file://ccan.git.tar.bz2 \
file://disable-man-page-creation.patch \
file://Fix-for-multi-sign.patch \
file://sbsign-add-x-option-to-avoid-overwrite-existing-sign.patch \
file://fix-mixed-implicit-and-normal-rules.patch;apply=0 \
file://image-fix-the-segment-fault-caused-by-the-uninitiali.patch \
"
SRCREV="951ee95a301674c046f55330cd7460e1314deff2"
PV = "0.6+git${SRCPV}"
inherit autotools-brokensep pkgconfig native
DEPENDS_append = " binutils-native openssl-native gnu-efi-native util-linux-native"
S = "${WORKDIR}/git"
do_configure() {
cd ${S}
rm -rf lib/ccan.git
git clone ${WORKDIR}/ccan.git lib/ccan.git
cd lib/ccan.git && git apply ${WORKDIR}/fix-mixed-implicit-and-normal-rules.patch && cd -
OLD_CC="${CC}"
if [ ! -e lib/ccan ]; then
export CC="${BUILD_CC}"
export TMPDIR=${B}
lib/ccan.git/tools/create-ccan-tree \
--build-type=automake lib/ccan \
talloc read_write_all build_assert array_size || exit 2
fi
export CC="${OLD_CC}"
./autogen.sh --noconfigure
oe_runconf
}
EXTRA_OEMAKE += " \
INCLUDES='-I../lib/ccan.git/' \
EFI_CPPFLAGS='-DEFI_FUNCTION_WRAPPER \
-I${STAGING_INCDIR}/efi \
-I${STAGING_INCDIR}/efi/${BUILD_ARCH}' \
"

View File

@@ -0,0 +1,41 @@
From e58a528ef57e53008222f238cce7c326a14572e2 Mon Sep 17 00:00:00 2001
From: James Bottomley <JBottomley@Parallels.com>
Date: Mon, 30 Sep 2013 19:25:37 -0700
Subject: [PATCH] Fix for multi-sign
Upstream-Status: Inappropriate [embedded specific]
The new Tianocore multi-sign code fails now for images signed with
sbsigntools. The reason is that we don't actually align the signature table,
we just slap it straight after the binary data. Unfortunately, the new
multi-signature code checks that our alignment offsets are correct and fails
the signature for this reason. Fix by adding junk to the end of the image to
align the signature section.
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
---
src/image.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/image.c b/src/image.c
index 10eba0e..519e288 100644
--- a/src/image.c
+++ b/src/image.c
@@ -385,7 +385,13 @@ static int image_find_regions(struct image *image)
/* record the size of non-signature data */
r = &image->checksum_regions[image->n_checksum_regions - 1];
- image->data_size = (r->data - (void *)image->buf) + r->size;
+ /*
+ * The new Tianocore multisign does a stricter check of the signatures
+ * in particular, the signature table must start at an aligned offset
+ * fix this by adding bytes to the end of the text section (which must
+ * be included in the hash)
+ */
+ image->data_size = align_up((r->data - (void *)image->buf) + r->size, 8);
return 0;
}
--
1.8.4

View File

@@ -0,0 +1,15 @@
Upstream-Status: Inappropriate [embedded specific]
diff --git a/docs/Makefile.am b/docs/Makefile.am
index 1b5a588..6918dd8 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -1,8 +1,4 @@
-man1_MANS = sbsign.1 sbverify.1 sbattach.1 sbvarsign.1 sbsiglist.1
-
-EXTRA_DIST = sbsign.1.in sbverify.1.in sbattach.1.in \
- sbvarsign.1.in sbsiglist.1.in
CLEANFILES = $(man1_MANS)
$(builddir)/%.1: $(srcdir)/%.1.in $(top_builddir)/src/%

View File

@@ -0,0 +1,33 @@
From 05e73dbe1f25600ad0dbb36b2d690560c5a36281 Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Tue, 31 Mar 2015 15:34:38 +0800
Subject: [PATCH] Fix mixed implicit and normal rules
Upstream-Status: Inappropriate [embedded specific]
This patch comes from upstream:
http://git.yoctoproject.org/cgit/cgit.cgi/meta-luv/plain/recipes-devtools/sbsigntool/sbsigntool/fix-mixed-implicit-and-normal-rules.patch
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
Makefile | 4 ----
1 file changed, 4 deletions(-)
diff --git a/Makefile b/Makefile
index 65d0d8f..a83185d 100644
--- a/Makefile
+++ b/Makefile
@@ -39,10 +39,6 @@ $(SCOREDIR)/SUMMARY: $(MODS:%=$(SCOREDIR)/%.score)
$(CC) -v >> $@
cat $^ | grep 'Total score:' >> $@
-$(SCOREDIR)/%.score: ccan/%/_info tools/ccanlint/ccanlint $(OBJFILES)
- mkdir -p `dirname $@`
- $(CCANLINT) -v -s ccan/$* > $@ || true
-
$(ALL_DEPENDS): %/.depends: %/_info tools/ccan_depends
tools/ccan_depends $* > $@ || ( rm -f $@; exit 1 )
--
1.8.3.1

View File

@@ -0,0 +1,30 @@
From a6862cb3bb3b00a1d6704b2bd1fedbd1374be861 Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Thu, 6 Apr 2017 11:11:14 +0800
Subject: [PATCH] image: fix the segment fault caused by the uninitialized
sigbuf
The uninitialized struct image might contain a non-zeroed sigbuf and then
it is wrongly freed by image_add_signature().
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
src/image.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/image.c b/src/image.c
index cc55791..644e8f1 100644
--- a/src/image.c
+++ b/src/image.c
@@ -395,7 +395,7 @@ struct image *image_load(const char *filename)
struct image *image;
int rc;
- image = talloc(NULL, struct image);
+ image = talloc_zero(NULL, struct image);
if (!image) {
perror("talloc(image)");
return NULL;
--
2.11.0

View File

@@ -0,0 +1,75 @@
From 0016a571a5ea1ab65817973f179800947e1aa8de Mon Sep 17 00:00:00 2001
From: Lans Zhang <jia.zhang@windriver.com>
Date: Fri, 15 Jan 2016 09:40:56 +0800
Subject: [PATCH] sbsign: add -x option to avoid overwrite existing signature
Upstream-Status: Pending
Signed-off-by: Lans Zhang <jia.zhang@windriver.com>
---
src/sbsign.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/src/sbsign.c b/src/sbsign.c
index dcf6eed..7dc101f 100644
--- a/src/sbsign.c
+++ b/src/sbsign.c
@@ -66,6 +66,7 @@ struct sign_context {
};
static struct option options[] = {
+ { "noresign", no_argument, NULL, 'x' },
{ "output", required_argument, NULL, 'o' },
{ "cert", required_argument, NULL, 'c' },
{ "key", required_argument, NULL, 'k' },
@@ -87,6 +88,7 @@ static void usage(void)
"\t--cert <certfile> certificate (x509 certificate)\n"
"\t--detached write a detached signature, instead of\n"
"\t a signed binary\n"
+ "\t--noresign don't re-sign the binary if signed\n"
"\t--output <file> write signed data to <file>\n"
"\t (default <efi-boot-image>.signed,\n"
"\t or <efi-boot-image>.pk7 for detached\n"
@@ -114,7 +116,7 @@ int main(int argc, char **argv)
const char *keyfilename, *certfilename;
struct sign_context *ctx;
uint8_t *buf, *tmp;
- int rc, c, sigsize;
+ int rc, c, sigsize, no_resign = 0;
ctx = talloc_zero(NULL, struct sign_context);
@@ -123,11 +125,14 @@ int main(int argc, char **argv)
for (;;) {
int idx;
- c = getopt_long(argc, argv, "o:c:k:dvVh", options, &idx);
+ c = getopt_long(argc, argv, "xo:c:k:dvVh", options, &idx);
if (c == -1)
break;
switch (c) {
+ case 'x':
+ no_resign = 1;
+ break;
case 'o':
ctx->outfilename = talloc_strdup(ctx, optarg);
break;
@@ -178,6 +183,14 @@ int main(int argc, char **argv)
if (!ctx->image)
return EXIT_FAILURE;
+ if (ctx->image->cert_table) {
+ if (no_resign) {
+ fprintf(stderr,
+ "Don't overwrite existing signature\n");
+ return EXIT_SUCCESS;
+ }
+ }
+
talloc_steal(ctx, ctx->image);
ERR_load_crypto_strings();
--
1.9.1

View File

@@ -0,0 +1,24 @@
SUMMARY = "The utility to manipulate machines owner keys which managed in shim"
LICENSE = "GPLv3"
LIC_FILES_CHKSUM = "file://COPYING;md5=d32239bcb673463ab874e80d47fae504"
SRC_URI = "\
git://github.com/lcp/mokutil.git \
"
S = "${WORKDIR}/git"
SRCREV = "e19adc575c1f9d8f08b7fbc594a0887ace63f83f"
PV = "0.3.0+git${SRCPV}"
inherit autotools pkgconfig
DEPENDS += "openssl efivar"
RDEPENDS_${PN} += "openssl efivar"
EXTRA_OEMAKE += "\
EFIVAR_LIBS='-L${STAGING_LIBDIR} -lefivar' \
OPENSSL_LIBS='-L${STAGING_LIBDIR} -lssl -lcrypto' \
"
FILES_${PN} += "${datadir}/bash-completion/*"

View File

@@ -0,0 +1,101 @@
FILESEXTRAPATHS_prepend := "${THISDIR}/linux-yocto:"
sccs = " \
${@bb.utils.contains('DISTRO_FEATURES', 'efi-secure-boot', \
'cfg/efi-ext.scc', '', d)} \
"
KERNEL_FEATURES_append_x86 += "${sccs}"
KERNEL_FEATURES_append_x86-64 += "${sccs}"
inherit user-key-store
fakeroot python do_sign() {
import re
if (d.expand('${TARGET_ARCH}') != 'x86_64') and (not re.match('i.86', d.expand('${TARGET_ARCH}'))):
return
if d.expand('${UEFI_SB}') != '1':
return
import shutil
for type in d.expand('${KERNEL_IMAGETYPES}').split():
kernel = d.expand('${B}/${KERNEL_OUTPUT_DIR}/') + type
# Prepare the unsigned kernel image for manual signing.
shutil.copy(kernel, d.expand('${B}/') + type + '.unsigned')
# SELoader signature is always based on the unsigned kernel image,
# disallowing chainloader to kernel efi-stub.
uks_sel_sign(kernel, d)
shutil.copyfile(kernel, d.expand('${D}/boot/') + type + d.expand('-${KERNEL_RELEASE}'))
shutil.copyfile(kernel + '.p7b', d.expand('${D}/boot/') + type + d.expand('-${KERNEL_RELEASE}.p7b'))
}
# Make sure the kernel image has been signed before kernel_do_deploy()
# which prepares the kernel image for creating usb/iso.
addtask sign after do_install before do_package do_populate_sysroot do_deploy
fakeroot python do_sign_bundled_kernel() {
import re
if (d.expand('${TARGET_ARCH}') != 'x86_64') and (not re.match('i.86', d.expand('${TARGET_ARCH}'))):
return
if d.expand('${UEFI_SB}') != '1':
return
if (d.expand('${INITRAMFS_IMAGE}') == '') or (d.expand('${INITRAMFS_IMAGE_BUNDLE}') != '1'):
return
import shutil
for type in d.expand('${KERNEL_IMAGETYPES}').split():
kernel = d.expand('${B}/${KERNEL_OUTPUT_DIR}/') + type + '.initramfs'
# Prepare the unsigned kernel image for manual signing.
shutil.copy(kernel, d.expand('${B}/') + type + '.initramfs.unsigned')
# SELoader signature is always based on the unsigned kernel image,
# disallowing chainloader to kernel efi-stub.
uks_sel_sign(kernel, d)
shutil.copyfile(kernel, d.expand('${D}/boot/') + type + d.expand('-initramfs-${MACHINE}.bin'))
shutil.copyfile(kernel + '.p7b', d.expand('${D}/boot/') + type + d.expand('-initramfs-${MACHINE}.bin.p7b'))
}
addtask sign_bundled_kernel after do_bundle_initramfs before do_deploy
do_deploy_append() {
install -d "${DEPLOYDIR}/efi-unsigned"
for type in ${KERNEL_IMAGETYPES}; do
if [ -f "${B}/$type.unsigned" ]; then
install -m 0644 "${B}/$type.unsigned" "${DEPLOYDIR}/efi-unsigned/$type"
fi
if [ -f "${B}/$type.initramfs.unsigned" ]; then
install -m 0644 "${B}/$type.initramfs.unsigned" "${DEPLOYDIR}/efi-unsigned/type.initramfs"
fi
if [ -f "${D}/boot/$type-initramfs-${MACHINE}.bin.p7b" ]; then
install -m 0644 "${D}/boot/$type-initramfs-${MACHINE}.bin.p7b" "${DEPLOYDIR}"
fi
if [ -f "${B}/${KERNEL_OUTPUT_DIR}/$type.p7b" ]; then
base_name="${type}-${KERNEL_IMAGE_BASE_NAME}.bin.p7b"
install -m 0644 "${B}/${KERNEL_OUTPUT_DIR}/$type.p7b" "${DEPLOYDIR}/$base_name"
ln -sf "$base_name" "${DEPLOYDIR}/$type-${KERNEL_IMAGE_SYMLINK_NAME}.bin.p7b"
ln -sf "$base_name" "${DEPLOYDIR}/$type.p7b"
fi
done
}
# Ship *.p7b files to related packages
python do_package_prepend() {
for type in d.expand('${KERNEL_IMAGETYPES}').split():
typelower = type.lower()
d.appendVar('FILES_kernel-image-' + typelower, ' /boot/' + type + d.expand('-${KERNEL_VERSION_NAME}.p7b'))
}

View File

@@ -0,0 +1 @@
require linux-yocto-efi-secure-boot.inc

View File

@@ -0,0 +1 @@
require linux-yocto-efi-secure-boot.inc

View File

@@ -0,0 +1,15 @@
DESCRIPTION = "Slurp entire files into variables."
SECTION = "libs"
LICENSE = "Artistic-1.0 | GPL-1.0+"
LIC_FILES_CHKSUM = "file://README;beginline=37;endline=41;md5=255fbd5f98a90d51d9908d31271ae4d4"
SRC_URI = "http://search.cpan.org/CPAN/authors/id/U/UR/URI/File-Slurp-9999.19.tar.gz"
S = "${WORKDIR}/File-Slurp-${PV}"
inherit cpan
BBCLASSEXTEND="native"
PACKAGE_ARCH = "all"
SRC_URI[md5sum] = "7d584cd15c4f8b9547765eff8c4ef078"
SRC_URI[sha256sum] = "ce29ebe995097ebd6e9bc03284714cdfa0c46dc94f6b14a56980747ea3253643"

View File

@@ -0,0 +1,44 @@
From 7078852e4a89f5ba27e7a70bc69641e01a6bff7a Mon Sep 17 00:00:00 2001
From: Yunguo Wei <yunguo.wei@windriver.com>
Date: Thu, 19 Jan 2017 15:11:25 +0800
Subject: [PATCH] Remove use of deprecated readdir_r
Backport 1dc6d576fa4(Remove use of deprecated readdir_r) from
https://github.com/rhinstaller/efivar.git
Signed-off-by: Yunguo Wei <yunguo.wei@windriver.com>
---
src/vars.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/src/vars.c b/src/vars.c
index 2a276de..ec0d6bf 100644
--- a/src/vars.c
+++ b/src/vars.c
@@ -126,19 +126,15 @@ is_64bit(void)
if (dfd < 0)
goto err;
- struct dirent entry;
- struct dirent *result = NULL;
while (1) {
- int rc = readdir_r(dir, &entry, &result);
- if (rc != 0)
- break;
- if (result == NULL)
+ struct dirent *entry = readdir(dir);
+ if (entry == NULL)
break;
- if (!strcmp(entry.d_name, "..") || !strcmp(entry.d_name, "."))
+ if (!strcmp(entry->d_name, "..") || !strcmp(entry->d_name, "."))
continue;
- ssize_t size = get_file_data_size(dfd, entry.d_name);
+ ssize_t size = get_file_data_size(dfd, entry->d_name);
if (size < 0) {
continue;
} else if (size == 2084) {
--
2.7.4

View File

@@ -0,0 +1,13 @@
FILESEXTRAPATHS_prepend := "${THISDIR}/efivar:"
SRC_URI += "\
file://Remove-use-of-deprecated-readdir_r.patch \
"
# In dp.h, 'for' loop initial declarations are used
CFLAGS_append = " -std=gnu99"
# In order to install headers and libraries to sysroot
do_install_append() {
oe_runmake DESTDIR=${D} install
}

View File

@@ -0,0 +1,179 @@
### Storage Encryption
This feature provides secure storage for application data. Some applications
need secure storage for sensitive data which must not be accessible to another
device. For example, only an application with the right signature can update
the data on an encrypted SD card. If you move that SD card to another device,
the data cannot be either read or updated. One application of this capability
is a POS application. The application keeps tax information in secure storage
that cannot be modified by another device.
This feature gives 2 types of granularity for storage encryption. Data volume
encryption allows the user to create encryption partition with a passphrase
typed by the end user. Root filesystem encryption enables the data encryption
on the entire rootfs except the boot partition.
Both types of storage encryption are based on device-mapper crypt target,
which provides transparent encryption of block devices using the kernel crypto
API. Additionally, the utility cryptsetup is used to conveniently set up disk
encryption, aka LUKS partition, based on device-mapper crypt target.
Due to the use of TPM state to seal the passphrase used to encrypt the storage,
the encrypted storage cannot be accessed on another machine, preventing from
the so-called offline attack.
### Dependency
This feature depends on meta-tpm2.
Note:
Even though the hardware doesn't have a TPM 2.0 device, this feature can still
run on it, although without the guarantee of compromise detection.
### Limit
- TPM 2.0 is validated and officially supported. But TPM 1.2 device is not
supported by this feature.
### Data Volume Encryption
#### Use case 1: manual operation
##### Create the LUKS partition
```
# cryptsetup --type luks --cipher aes-xts-plain --hash sha256 \
--use-random luksFormat /dev/$dev
```
where $dev is the device node of the partition to be encrypted.
This command initializes a LUKS partition and prompts to input an initial
passphrase used to encrypt the data. Don't disclose the passphrase used for
product.
##### Open the LUKS partition
```
# cryptsetup luksOpen /dev/$dev $name
```
This command opens the LUKS device $dev and sets up a mapping $name after
successful verification of the supplied passphrase typed interactively. From
now on, the data written to /dev/mapper/$name is encrypted and the data
read back from /dev/mapper/$name is decrypted transparently and automatically.
##### Create the filesystem on top of the LUKS partition
The user can run any available filesytem formatting program on
/dev/mapper/$name to create the filesytem with the data encryption.
##### Close the LUKS partition
```
# cryptsetup luksClose $name
```
This command removes the existing mapping $name and wipes the key from kernel
memory.
To access the encryped partition, follow the instruction "Open the LUKS partition"
and then manually mount /dev/mapper/$name to a mount point.
#### Use case 2: luks-setup.sh
This script provides a semi automatic method to set up LUKS partition. The user
still needs to manually create the filesystem on top of the newly created LUKS
partition.
##### LUKS partition creation
In runtime, for example, create LUKS partition on /dev/sdb1 with the
name "my_luks_part":
```
# luks-setup.sh -d /dev/sdb1 -n my_luks_name -e
```
Note: if TPM is detected, the passphrase will be generated automatically.
For more uses about luks-setup.sh, run it with -h option.
##### Retrieve the passphrase
```
# cryptfs-tpm2 -q unseal passphrase -P sha1 -o /tmp/passphrase
```
This command will unseal the passphrase from TPM device and save the content
of passphrase to the file /tmp/passphrase.
The passphrase should not be disclosed and needs to be backed up to a off-line
storage.
##### Open the LUKS partition
```
# cryptsetup luksOpen --key-file /tmp/passphrase /dev/$dev $name
```
##### Mount the LUKS partition
```
# mount /dev/mapper/$name $mount_point
```
The remaining operations are left to the user. Don't forget to close the LUKS
partition if not used.
Note:
If TPM device exists in the system, the passphrase will be bound to PCR 7,
gating the unseal operation. If the value of PCR 7 when unsealing the
passphrase doesn't match up the value when creating the passphrase, the
passphrase cannot be unsealed. The value of PCR 7 is usually affected by the
status of UEFI secure boot.
### Root Filesystem Encryption
This enables the data encryption on the rootfs without the need of a human
entering an user passphrase. Therefore, it is required to employ an initramfs
where the unique identity from the platform is collected from the devices on
the platform and used to unlock the root filesystem encryption. Meanwhile, use
TPM to protect the user passphrase for volume decryption to avoid disclosing
the user passphrase. If the TPM device is not detected, the end user will be
prompted to type the user passphrase.
#### Operations
Note:
The instructions below with the prefix "[TPM]" indicate the operation
requires TPM device. Oppositely, the prefix "[Non-TPM]" indicates this
operation is required if the target board doesn't have a TPM device.
- Ensure a hard drive is attached on target board
WARNNING: the following instructions will wipe all data in the hard drive.
- Create overc installer on a USB device
Refer to layers/meta-overc/README.install for the details about how to
run cubeit to install overc installer to a USB device.
- Attach the USB device to the board
- Power on
- [TPM] Clear TPM
Refer to meta-tpm2/README.md for the details.
- Boot to Linux
- Install overc runtime on the hard drive
Refer to layers/meta-overc/README.install for the details about how to
run cubeit-installer to install overc runtime to a hard drive. In
addition, beware of specifying "--encrypt" option to set up an
encrypted rootfs.
- Reboot
After reboot to initramfs, it employs a init script to transparently
unseal the passphrase and mount the rootfs without any interaction.
### Best Practice
- The benefit of anchoring the TPM is that the machine status cannot be
compromised by any attack. If compromised, the system cannot boot up
due to the failure when mouting the rootfs, or access the encrypted partition
when mounting the LUKS partition. This is caused by the fact that the content
of PCR 7 is different with the value when creating the encrypted storage.
Usually, the content of PCR 7 is calculated based on the status of UEFI
secure boot.
Based on the above conclusion, it is recommended to provision UEFI secure
boot and turn on it prior to setting up the encrypted storage.
- The non-default seal secret is supported to provide extra protection, and it
is user configurable. Modify the values of CRYPTFS_TPM2_PRIMARY_KEY_SECRET
and CRYPTFS_TPM2_PASSPHRASE_SECRET in cryptfs-tpm2 with your preference.
### Known Issues
- The default IMA rules provides the ability of measuring the boot components
and calculating the aggregate integrity value for attesting. However, this
function conflicts with this feature which employs PCR policy session to
retrieve the passphrase in a safe way. If the installer enables both of
them, the default IMA rules will be not used.
### Reference
- [OpenEmbedded layer for TPM 2.0 enablement](https://github.com/jiazhang0/meta-tpm2)

View File

@@ -0,0 +1,15 @@
# We have a conf and classes directory, add to BBPATH
BBPATH .= ":${LAYERDIR}"
# We have recipes-* directories, add to BBFILES
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
${LAYERDIR}/recipes-*/*/*.bbappend"
BBFILE_COLLECTIONS += "encrypted-storage"
BBFILE_PATTERN_encrypted-storage = "^${LAYERDIR}/"
BBFILE_PRIORITY_encrypted-storage = "10"
LAYERDEPENDS_encrypted-storage = "\
core \
tpm2 \
"

View File

@@ -0,0 +1,8 @@
include packagegroup-encrypted-storage.inc
DESCRIPTION = "The packages used for encrypted storage in initramfs."
RDEPENDS_${PN} += " \
cryptfs-tpm2-initramfs \
packagegroup-tpm2-initramfs \
"

View File

@@ -0,0 +1,14 @@
include packagegroup-encrypted-storage.inc
DESCRIPTION = "The packages used for encrypted storage."
# Install the minimal stuffs only for the linux rootfs.
# The common packages shared between initramfs and rootfs
# are listed in the .inc.
# @util-linux: fdisk
# @parted: parted
RDEPENDS_${PN} += " \
util-linux-fdisk \
parted \
packagegroup-tpm2 \
"

View File

@@ -0,0 +1,25 @@
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COREBASE}/LICENSE;md5=4d92cd373abda3937c2bc47fbc49d690 \
file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420"
ALLOW_EMPTY_${PN} = "1"
S = "${WORKDIR}"
# Install the minimal stuffs for the common uses between initramfs
# and linux rootfs.
# @util-linux: mount, umount
# @cryptsetup: cryptsetup
# @cryptfs-tpm: tpm_gen_dmcrypt_key, tpm_unwrap_dmcrypt_key
# @kmod: modprobe
# @coreutils: cat, mkdir, mknod, cp, rm
# @trousers: tcsd
RDEPENDS_${PN} = " \
util-linux-mount \
util-linux-umount \
cryptsetup \
kmod \
coreutils \
cryptfs-tpm2 \
procps \
"

View File

@@ -0,0 +1,6 @@
FILESEXTRAPATHS_prepend := "${THISDIR}/linux-yocto:"
SRC_URI += " \
${@bb.utils.contains('DISTRO_FEATURES', 'encrypted-storage', \
'file://dmcrypt.scc file://dmcrypt.cfg', '', d)} \
"

View File

@@ -0,0 +1 @@
include linux-yocto-encrypted-storage.inc

View File

@@ -0,0 +1,11 @@
# Enable device-mapper crypt target
CONFIG_DM_CRYPT=y
# Enable the default cipher-spec for LUKS
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_AES_NI_INTEL=y
CONFIG_CRYPTO_XTS=y
# Use entropy-strong source for RNG
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_TPM=m

View File

@@ -0,0 +1 @@
kconf non-hardware dmcrypt.cfg

View File

@@ -0,0 +1 @@
include linux-yocto-encrypted-storage.inc

View File

@@ -0,0 +1,55 @@
SUMMARY = "A tool used to create, persist, evict a passphrase \
for full-disk-encryption with TPM 2.0"
DESCRIPTION = " \
This project provides with an implementation for \
creating, persisting and evicting a passphrase with TPM 2.0. \
The passphrase and its associated primary key are automatically \
created by RNG engine in TPM. In order to avoid saving the \
context file, the created passphrase and primary key are always \
persistent in TPM. \
"
SECTION = "devel"
LICENSE = "BSD-3-Clause"
LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=89c8ce1346a3dfe75379e84f3ba9d641"
SRC_URI = " \
git://github.com/WindRiver-OpenSourceLabs/cryptfs-tpm2.git \
"
SRCREV = "32b49092d54b3d59c482d77d5eb1e36993912e89"
PV = "0.6.0+git${SRCPV}"
DEPENDS += "tpm2.0-tss tpm2-abrmd pkgconfig-native"
RDEPENDS_${PN} += "libtss2 libtctidevice libtctisocket"
PACKAGES =+ " \
${PN}-initramfs \
"
PARALLEL_MAKE = ""
S = "${WORKDIR}/git"
EXTRA_OEMAKE = " \
sbindir="${sbindir}" \
libdir="${libdir}" \
includedir="${includedir}" \
tpm2_tss_includedir="${STAGING_INCDIR}/sapi" \
tpm2_tss_libdir="${STAGING_LIBDIR}" \
tpm2_tabrmd_includedir="${STAGING_INCDIR}" \
CC="${CC}" \
PKG_CONFIG="${STAGING_BINDIR_NATIVE}/pkg-config" \
EXTRA_CFLAGS="${CFLAGS}" \
EXTRA_LDFLAGS="${LDFLAGS}" \
"
do_install() {
oe_runmake install DESTDIR="${D}"
if [ x"${@bb.utils.contains('DISTRO_FEATURES', 'encrypted-storage', '1', '0', d)}" = x"1" ]; then
install -m 0500 ${S}/script/init.cryptfs ${D}
fi
}
FILES_${PN}-initramfs = "\
/init.cryptfs \
"

View File

@@ -0,0 +1,17 @@
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

166
meta-integrity/README.md Normal file
View File

@@ -0,0 +1,166 @@
### meta-integrity
OpenEmbedded layer for Linux integrity support
#### Integrity Measurement Architecture (IMA)
The Linux IMA subsystem introduces hooks within the Linux kernel to support
measuring the integrity of files that are loaded (including application code)
before it is executed or mmap()ed to memory. The measured value (hash) is then
registered in a log that can be consulted by administrators.
To support proven integrity of the files, the IMA subsystem can interact with
the TPM chip within the system to protect the registered hashes from tampering
by a rogue administrator or application. The IMA subsystem, as already
supported by the Linux kernel, supports reporting on the hashes of files and
commands ran by privileged accounts (and more if you create your own
measurement policies).
In addition, IMA appraisal can even register the measured value as an extended
attribute, and after subsequent measurement(s) validate this extended attribute
against the measured value and refuse to load the file (or execute the
application) if the hash does not match. In that case, the IMA subsystem allows
files and applications to be loaded if the hashes match (and will save the
updated hash if the file is modified) but refuse to load it if it doesn't. This
provides some protection against offline tampering of the files.
NOTE: Extended file system attribute is required for IMA appraisal, but not
all file systems can support it. Typically, the pseudo file systems, such as
sysfs, proc, tmpfs and ramfs, certain disk-based file systems, such as FAT,
and network file systems, such as NFS, don't support extended attribute,
meaning IMA appraisal is not available with them.
##### Dependency
- meta-tpm
This layer provides the kernel configurations for TPM 1.x enablement.
- meta-tpm2
This layer provides the kernel configurations for TPM 2.0 enablement.
##### Use The External IMA Policy
initramfs is a good place to run some IMA initializations, such as loading
the IMA policy, as well as the public keys used to verify IMA signatures.
###### The default external IMA policy
The default external IMA policy enforces appraising all the executable, shared
library, kernel modules and firmwares with the digital signature in the
effective root identity (euid=0). Hence, the opportunity of loading the default
external IMA policy occurs at the end of initramfs initializations, just before
switch_root.
Instead of running switch_root directly from initramfs, a statically linked
switch_root from the real rootfs is called and it must be already signed
properly. Otherwise, switch_root will fail to mount the real rootfs and kernel
panic will happen due to this failure.
The default external IMA policy is located at `/etc/ima_policy.default` in
initramfs. If a custom external IMA policy file exists, the default external
IMA policy file won't be used any more.
The default external IMA policy enables the following constraint conditions:
- Appraise the files for exec'd (the executables), files mmap'd for exec
(shared libraries), kernel modules and firmwares in effective root identity
(euid=0).
- Enforce verifying the IMA signature when running the executables, shared
libraries, kernel modules and firmwares.
- Deny to run the newly created executables, shared libraries, kernel modules
and firmwares.
- Deny to run the tampered executables, shared libraries, kernel modules and
firmwares.
- Deny to run any executables, shared libraries, kernel modules and firmwares
in the filesystems without file extended attribute supported.
- Allow to run the manually signed executables, shared libraries, kernel
modules and firmwares.
- Allow to run the updated executables, shared libraries, kernel modules and
firmwares during RPM installation.
- Note the different behaviors when executing a script.
e.g, launching a python script with "./test.py" is allowed only when test.py
is signed, and launching a python script with "python test.py" is always
allowed as long as the python interpreter is signed.
###### The custom external IMA policy
If the default external IMA policy cannot meet the protection requirement, it
is allowed to define the custom external IMA policy.
- Deploy the custom policy file to installer image
- Create `/opt/installer/sbin/config-installer.sh` in installer image
Define the IMA_POLICY variable, pointing to the path of policy file.
The custom external IMA policy file is eventually installed to `/etc/ima_policy`
in initramfs.
##### IMA certificate & private Key
The private key come in two flavors; one used by an installer to sign all
regular files in rootfs and one used by RPM to re-sign the executable, shared
library, kernel module and firmware during RPM installation. Correspondingly,
the IMA certificate is used to verify the IMA signature signed by the private
key.
In addition, initramfs is a good place to import the IMA certificate likewise.
###### The default IMA certificate & private key
The default IMA certificate & private key are generated by the build system. By
default, the sample keys are used for the purpose of development and
demonstration. Please ensure you know what your risk is to use the sample keys
in your product, because they are completely public.
### Best practice
The following best practices should be applied with using IMA.
- Enable UEFI/MOK secure boot
UEFI/MOK secure boot can verify the integrity of initramfs, providing the
protection against tampering of the external IMA policy files and IMA public
keys stored in initramfs.
- Moderate measuring
Measuring the files owned by non-root user may introduce malicious attack.
Malicious user may create lots of files with different names or trigger
violation conditions to generate a mass of event logs recorded in the runtime
measurement list, and thus exhaust the persistent kernel memory.
- Performance influence
Moderate policy can make a good balance between the performance and security.
Tune the default external policy (`/etc/ima_policy.default`) and modulate the
custom policy for the product requirement.
- Use IMA digital signature to protect the executable
Using the digital signature scheme DIGSIG is safer than digest-based scheme.
Meanwhile, use `appraise_type=imasig` in your IMA policy to enforce running
this.
- Use the measurement and audit rules together
The runtime measurement list is unable to track down the order of changes for
a file, e.g, a file content varies in order of X -> Y -> X. However, audit log
can record these changes in the right order.
##### Known Issues
- The following operations may break the behavior of appraisal and cause the
failure of launching the executables, shared libraries, kernel modules and
firmwares:
- the syscalls used to set file last access and modification times.
- the syscalls used to set ownership of a file.
- the syscalls used to set permissions of a file.
To fix the failure, manually re-sign the affected file.
Note: RPM installation violates the IMA appraisal but its post_install
operation will always re-sign the affected files.
- Overwriting an existing file with the same content is deemed as tampering of
the file.
- The default IMA rules provides the ability of measuring the boot components
and calculating the aggregate integrity value for attesting. However, this
function conflicts with encrypted-storage feature which employs PCR policy
session to retrieve the passphrase in a safe way. If the installer enables
both of them, the default IMA rules will be not used.
### Reference
[IMA wiki page](https://sourceforge.net/p/linux-ima/wiki/Home/)
[OpenEmbedded layer for EFI Secure Boot](https://github.com/jiazhang0/meta-efi-secure-boot)
[OpenEmbedded layer for signing key management](https://github.com/jiazhang0/meta-signing-key)
[OpenEmbedded layer for TPM 1.x](https://github.com/jiazhang0/meta-tpm)
[OpenEmbedded layer for TPM 2.0](https://github.com/jiazhang0/meta-tpm2)

View File

@@ -0,0 +1,156 @@
inherit package
PACKAGEFUNCS =+ "package_ima_hook"
# security.ima is generated during the RPM build, and the base64-encoded
# value is written during RPM installation. In addition, if the private
# key is deployed on board, re-sign the updated files during RPM
# installation in higher priority.
python package_ima_hook() {
packages = d.getVar('PACKAGES', True)
pkgdest = d.getVar('PKGDEST', True)
ima_signing_blacklist = d.getVar('IMA_SIGNING_BLACKLIST', True)
ima_keys_dir = d.getVar('IMA_KEYS_DIR', True)
pkg_suffix_blacklist = ('dbg', 'dev', 'doc', 'locale', 'staticdev')
pkg_blacklist = ()
with open(ima_signing_blacklist, 'r') as f:
pkg_blacklist = [ _.strip() for _ in f.readlines() ]
pkg_blacklist = tuple(pkg_blacklist)
import base64, pipes, stat
for pkg in packages.split():
if (pkg.split('-')[-1] in pkg_suffix_blacklist) is True:
continue
if pkg.startswith(pkg_blacklist) is True:
continue
bb.note("Writing IMA %%post hook for %s ..." % pkg)
pkgdestpkg = os.path.join(pkgdest, pkg)
cmd = 'evmctl ima_sign --hashalgo sha256 -n --sigfile --key %s/x509_ima.key ' % (ima_keys_dir)
sig_list = []
pkg_sig_list = []
for _ in pkgfiles[pkg]:
# Ignore the symbol links.
if os.path.islink(_):
continue
# IMA appraisal is only applied to the regular file.
if not stat.S_ISREG(os.stat(_)[stat.ST_MODE]):
continue
bb.note("Preparing to sign %s ..." % _)
sh_name = pipes.quote(_)
print("Signing command: %s" % cmd + sh_name)
rc, res = oe.utils.getstatusoutput(cmd + sh_name + " >/dev/null")
if rc:
bb.fatal('Calculate IMA signature for %s failed with exit code %s:\n%s' % \
(_, rc, res if res else ""))
with open(_ + '.sig', 'rb') as f:
s = str(base64.b64encode(f.read()).decode('ascii')) + '|'
sig_list.append(s + os.sep + os.path.relpath(_, pkgdestpkg))
os.remove(_ + '.sig')
ima_sig_list = '&'.join(sig_list)
# When the statically linked binary is updated, use the
# dynamically linked one to resign or set. This situation
# occurs in runtime only.
setfattr_bin = 'setfattr.static'
evmctl_bin = 'evmctl.static'
# We don't want to create a statically linked echo program
# any more.
safe_echo = '1'
if pkg == 'attr-setfattr.static':
setfattr_bin = 'setfattr'
elif pkg == 'ima-evm-utils-evmctl.static':
evmctl_bin = 'evmctil'
elif pkg == 'coreutils':
safe_echo = '0'
# The %post is dynamically constructed according to the currently
# installed package and enviroment.
postinst = r'''#!/bin/sh
# %post hook for IMA appraisal
ima_resign=0
sig_list="''' + ima_sig_list + r'''"
if [ -z "$D" ]; then
evmctl_bin="${sbindir}/''' + evmctl_bin + r'''"
setfattr_bin="${bindir}/''' + setfattr_bin + r'''"
[ -f "/etc/keys/privkey_evm.pem" -a -x "$evmctl_bin" ] && \
ima_resign=1
safe_echo="''' + safe_echo + r'''"
cond_print()
{
[ $safe_echo = "1" ] && echo $1
}
saved_IFS="$IFS"
IFS="&"
for entry in $sig_list; do
IFS="|"
tokens=""
for token in $entry; do
tokens="$tokens$token|"
done
for sig in $tokens; do
break
done
IFS="$saved_IFS"
f="$token"
# If the filesystem doesn't support xattr, skip the following steps.
res=`"$setfattr_bin" -x security.ima "$f" 2>&1 | grep "Operation not supported$"`
[ x"$res" != x"" ] && {
cond_print "Current file system doesn't support to set xattr"
break
}
if [ $ima_resign -eq 0 ]; then
cond_print "Setting up security.ima for $f ..."
"$setfattr_bin" -n security.ima -v "0s$sig" "$f" || {
err=$?
cond_print "Unable to set up security.ima for $f (err: $err)"
exit 1
}
else
cond_print "IMA signing for $f ..."
"$evmctl_bin" ima_sign --hashalgo sha256 "$f" || {
err=$?
cond_print "Unable to sign $f (err: $err)"
exit 1
}
fi
IFS="&"
done
IFS="$saved_IFS"
fi
'''
postinst = postinst + (d.getVar('pkg_postinst_%s' % pkg, True) or '')
d.setVar('pkg_postinst_%s' % pkg, postinst)
}
do_package[depends] += "ima-evm-utils-native:do_populate_sysroot"

View File

@@ -0,0 +1,19 @@
# We have a conf and classes directory, add to BBPATH
BBPATH .= ":${LAYERDIR}"
# We have recipes-* directories, add to BBFILES
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
${LAYERDIR}/recipes-*/*/*.bbappend"
BBFILE_COLLECTIONS += "integrity"
BBFILE_PATTERN_integrity = "^${LAYERDIR}/"
BBFILE_PRIORITY_integrity = "10"
IMA_SIGNING_BLACKLIST ??= "${LAYERDIR}/files/ima_signing_blacklist"
LAYERDEPENDS_integrity = "\
core \
signing-key \
tpm2 \
tpm \
"

View File

@@ -0,0 +1 @@
kernel-devsrc

View File

@@ -0,0 +1,12 @@
DESCRIPTION = "Linux Integrity Measurement Architecture (IMA) subsystem for initramfs"
include packagegroup-ima.inc
RDEPENDS_${PN} += " \
util-linux-mount \
util-linux-umount \
gawk \
ima-policy \
key-store-ima-cert \
initrdscripts-ima \
"

View File

@@ -0,0 +1,21 @@
DESCRIPTION = "Linux Integrity Measurement Architecture (IMA) subsystem"
include packagegroup-ima.inc
DEPENDS += " \
ima-evm-utils-native \
attr-native \
"
RDEPENDS_${PN} += " \
attr \
util-linux-switch_root.static \
attr-setfattr.static \
ima-evm-utils-evmctl.static \
"
# Note any private key is not available if user key signing model used.
RRECOMMENDS_${PN} += " \
key-store-ima-privkey \
key-store-system-trusted-privkey \
"

View File

@@ -0,0 +1,13 @@
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COREBASE}/LICENSE;md5=4d92cd373abda3937c2bc47fbc49d690 \
file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420"
S = "${WORKDIR}"
ALLOW_EMPTY_${PN} = "1"
RDEPENDS_${PN} = " \
ima-evm-utils \
coreutils \
grep \
"

View File

@@ -0,0 +1,4 @@
# Append iversion option for auto types
do_install_append() {
sed -i 's/\s*auto\s*defaults/&,iversion/' ${D}${sysconfdir}/fstab
}

View File

@@ -0,0 +1,129 @@
#!/bin/sh
# Initramfs script for IMA initialzation
#
# This script is a halper used to load the external
# IMA policy and public keys used to verify the IMA
# signature.
#
# Copyright (c) 2017, Jia Zhang <lans.zhang2008@gmail.com>
# All rights reserved.
#
# See "LICENSE" for license terms.
# Exit code:
# 0 - IMA initialiazation complete
# 1 - Kernel doesn't support securityfs
# 2 - Kernel doesn't support IMA
# 3 - There is no public key to load
# 4 - There is no IMA policy file defined
# 5 - Unable to load IMA policy file
# If root directory is not specified, the root of
# initramfs assumed.
ROOT_DIR="${1}"
SECURITYFS_DIR="${ROOT_DIR}/sys/kernel/security"
# The policy files are always placed in initramfs
IMA_POLICY=/etc/ima_policy
SECURITYFS_MOUNTED=0
function print_critical
{
printf "\033[1;35m"
echo "$@"
printf "\033[0m"
}
function print_error
{
printf "\033[1;31m"
echo "$@"
printf "\033[0m"
}
function print_warning
{
printf "\033[1;33m"
echo "$@"
printf "\033[0m"
}
function print_info
{
printf "\033[1;32m"
echo "$@"
printf "\033[0m"
}
function print_verbose
{
printf "\033[1;36m"
echo "$@"
printf "\033[0m"
}
function trap_handler
{
local err=$?
print_verbose "Cleaning up with exit code $err ..."
[ $SECURITYFS_MOUNTED -eq 1 ] &&
umount "$SECURITYFS_DIR" 2>"${ROOT_DIR}/dev/null"
}
trap "trap_handler $?" SIGINT EXIT
if grep -q "ima_appraise=off" "${ROOT_DIR}/proc/cmdline"; then
print_info "Skip to load the public key and IMA policy"
exit 0
fi
if ! grep -q securityfs "${ROOT_DIR}/proc/mounts"; then
! mount -t securityfs none "$SECURITYFS_DIR" 2>"${ROOT_DIR}/dev/null" && {
print_error "Unable to mount securityfs filesystem"
exit 1
}
SECURITYFS_MOUNTED=1
securityfs_dir="$SECURITYFS_DIR"
else
securityfs_dirs="$(grep securityfs ${ROOT_DIR}/proc/mounts | awk '{print $2}')"
# Use the first one.
for securityfs_dir in "$securityfs_dirs"; do
break
done
fi
[ ! -d "$securityfs_dir/ima" ] &&
print_info "IMA is not enabled. Exiting ..." && exit 2
keyring_id=0x`grep '\skeyring\s*\.ima: ' "${ROOT_DIR}/proc/keys" | awk '{ print $1 }'`
for key in ${ROOT_DIR}/etc/keys/x509_evm*.pem; do
[ ! -s "$key" ] && continue
if ! evmctl import "$key" "$keyring_id" >"${ROOT_DIR}/dev/null"; then
print_critical "Unable to load the public key $key for IMA appraisal"
else
print_verbose "The external public key $key loaded for IMA appraisal"
fi
done
# Attempt to load the default policy.
[ ! -f "${IMA_POLICY}" ] && IMA_POLICY="${IMA_POLICY}.default"
[ ! -f "${IMA_POLICY}" ] && {
print_warning "No IMA policy file defined"
exit 4
}
cat "${IMA_POLICY}" > "$securityfs_dir/ima/policy" && {
exit 0
} || {
print_critical "Unable to load the IMA policy ${IMA_POLICY}"
exit 5
}

View File

@@ -0,0 +1,47 @@
DESCRIPTION = "The initrd script for Linux Integrity Measurement Architecture (IMA)"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COREBASE}/LICENSE;md5=4d92cd373abda3937c2bc47fbc49d690 \
file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420"
S = "${WORKDIR}"
ALLOW_EMPTY_${PN} = "1"
SRC_URI = "\
file://init.ima \
"
do_install() {
if [ x"${@bb.utils.contains('DISTRO_FEATURES', 'ima', '1', '0', d)}" = x"1" ]; then
install -m 0500 ${WORKDIR}/init.ima ${D}
fi
}
FILES_${PN} += " \
${@bb.utils.contains('DISTRO_FEATURES', 'ima', '/init.ima', '', d)} \
"
# Install the minimal stuffs only, and don't care how the external
# environment is configured.
# @bash: sh
# @coreutils: echo, mkdir, mknod, dirname, basename, cp, rm, sleep
# seq, printf, cut
# @grep: grep
# @gawk: awk
# @kmod: modprobe, depmod
# @net-tools: ifconfig
# @trousers: tcsd
# @procps: pkill
# @util-linux: blkid, mount, umount
RDEPENDS_${PN} += "\
bash \
coreutils \
grep \
gawk \
kmod \
net-tools \
procps \
util-linux-blkid \
util-linux-mount \
util-linux-umount \
"

View File

@@ -0,0 +1,16 @@
PACKAGES =+ "${PN}-switch_root.static"
CFLAGS_remove += "-pie -fpie"
do_compile_append_class-target() {
${CC} ${CFLAGS} ${LDFLAGS} -static \
sys-utils/switch_root.o \
-o switch_root.static
}
do_install_append_class-target() {
install -d ${D}${sbindir}
install -m 0700 ${B}/switch_root.static ${D}${sbindir}/switch_root.static
}
FILES_${PN}-switch_root.static = "${sbindir}/switch_root.static"

View File

@@ -0,0 +1,18 @@
FILESEXTRAPATHS_prepend := "${THISDIR}/linux-yocto:"
IMA_ENABLED = "${@bb.utils.contains('DISTRO_FEATURES', 'ima', '1', '0', d)}"
DEPENDS += "${@'key-store openssl-native' if d.getVar('IMA_ENABLED', True) == '1' else ''}"
# key-store-ima-cert is required in runtime but we hope it is available
# in initramfs only. So we don't add it to RDEPENDS_${PN} here.
SRC_URI += " \
${@'file://ima.scc file://ima.cfg' if d.getVar('IMA_ENABLED', True) == '1' else ''} \
"
do_configure_append() {
[ -f "${STAGING_DIR_TARGET}${sysconfdir}/keys/system_trusted_key.pem" ] &&
openssl x509 -in "${STAGING_DIR_TARGET}${sysconfdir}/keys/system_trusted_key.pem" \
-outform DER -out "${B}/system_trusted_cert.x509" ||
true
}

View File

@@ -0,0 +1 @@
include linux-yocto-integrity.inc

View File

@@ -0,0 +1,35 @@
..........................................................................
. WARNING
.
. This file is a kernel configuration fragment, and not a full kernel
. configuration file. The final kernel configuration is made up of
. an assembly of processed fragments, each of which is designed to
. capture a specific part of the final configuration (e.g. platform
. configuration, feature configuration, and board specific hardware
. configuration). For more information on kernel configuration, please
. consult the product documentation.
.
..........................................................................
CONFIG_IMA=y
CONFIG_IMA_MEASURE_PCR_IDX=10
# CONFIG_IMA_TEMPLATE is not set
# CONFIG_IMA_NG_TEMPLATE=y is not set
CONFIG_IMA_SIG_TEMPLATE=y
CONFIG_IMA_DEFAULT_TEMPLATE="ima-sig"
# CONFIG_IMA_DEFAULT_HASH_SHA1 is not set
CONFIG_IMA_DEFAULT_HASH_SHA256=y
# CONFIG_IMA_DEFAULT_HASH_SHA512 is not set
# CONFIG_IMA_DEFAULT_HASH_WP512 is not set
CONFIG_IMA_DEFAULT_HASH="sha256"
CONFIG_IMA_APPRAISE=y
CONFIG_INTEGRITY_SIGNATURE=y
CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y
CONFIG_INTEGRITY_TRUSTED_KEYRING=y
CONFIG_SYSTEM_TRUSTED_KEYRING=y
CONFIG_IMA_LOAD_X509=y
CONFIG_IMA_TRUSTED_KEYRING=y
CONFIG_IMA_X509_PATH="/etc/keys/x509_evm.der"
# CONFIG_IMA_APPRAISE_SIGNED_INIT is not set
CONFIG_AUDIT=y
CONFIG_INTEGRITY_AUDIT=y

View File

@@ -0,0 +1,4 @@
define KFEATURE_DESCRIPTION "Integrity Measurement Architecture (IMA) enablement"
define KFEATURE_COMPATIBILITY board
kconf non-hardware ima.cfg

Some files were not shown because too many files have changed in this diff Show More