Merge branch 'master' of https://git.savannah.gnu.org/git/grub into gfxmenu/time

This commit is contained in:
☙◦ The Tablet ❀ GamerGirlandCo ◦❧ 2026-01-30 13:29:51 -05:00
commit 0482ab6010
249 changed files with 14845 additions and 1320 deletions

3
.gitignore vendored
View File

@ -249,8 +249,6 @@ widthspec.bin
/pata_test /pata_test
/po/*.gmo /po/*.gmo
/po/*.mo /po/*.mo
/po/*.po
/po/LINGUAS
/po/Makefile.in.in /po/Makefile.in.in
/po/Makevars /po/Makevars
/po/Makevars.template /po/Makevars.template
@ -283,3 +281,4 @@ widthspec.bin
/xfs_test /xfs_test
/xzcompress_test /xzcompress_test
/zfs_test /zfs_test
/zfs_zstd_test

8
BUGS
View File

@ -1,7 +1,3 @@
GRUB team is aware of following problems: Open bugs and issues are captured in the GRUB bug tracking system:
- Currently search and assembling multidevice abstractions scans
all the devices which can be slow.
- Cache isn't used correctly for video which results in slowness.
While these are bugs their solution has a potential of breaking more and more https://savannah.gnu.org/bugs/?group=grub
seriously. So it was decided for 1.99 that they aren't fixed.

39
INSTALL
View File

@ -25,6 +25,7 @@ configuring the GRUB.
* Flex 2.5.35 or later * Flex 2.5.35 or later
* pkg-config * pkg-config
* GNU patch * GNU patch
* wget (for downloading updated translations)
* Other standard GNU/Unix tools * Other standard GNU/Unix tools
* a libc with large file support (e.g. glibc 2.1 or later) * a libc with large file support (e.g. glibc 2.1 or later)
@ -45,12 +46,17 @@ To build GRUB's graphical terminal (gfxterm), you need:
To build grub-mkfont the unicode fonts are required (xfonts-unifont package To build grub-mkfont the unicode fonts are required (xfonts-unifont package
on Debian). on Debian).
To build the optional grub-protect utility the following is needed:
* libtasn1 (libtasn1-6-dev on Debian)
If you use a development snapshot or want to hack on GRUB you may If you use a development snapshot or want to hack on GRUB you may
need the following. need the following.
* Python 3 (NOTE: python 2.6 should still work, but it's not tested) * Python 3 (NOTE: python 2.6 should still work, but it's not tested)
* Autoconf 2.64 or later * Autoconf 2.64 or later
* Automake 1.14 or later * Automake 1.14 or later
* GNU Autoconf Archive (autoconf-archive on Debian)
Your distro may package cross-compiling toolchains such as the following Your distro may package cross-compiling toolchains such as the following
incomplete list on Debian: gcc-aarch64-linux-gnu, gcc-arm-linux-gnueabihf, incomplete list on Debian: gcc-aarch64-linux-gnu, gcc-arm-linux-gnueabihf,
@ -62,7 +68,7 @@ More cross compiling toolchains can be found at the following trusted sites:
* https://mirrors.kernel.org/pub/tools/crosstool/ * https://mirrors.kernel.org/pub/tools/crosstool/
* https://toolchains.bootlin.com/ * https://toolchains.bootlin.com/
Prerequisites for make-check: Prerequisites for running make-check successfully:
* qemu, specifically the binary "qemu-system-ARCH" where ARCH is the * qemu, specifically the binary "qemu-system-ARCH" where ARCH is the
architecture GRUB has been built for; the "qemu-system" package on Debian architecture GRUB has been built for; the "qemu-system" package on Debian
@ -82,6 +88,8 @@ Prerequisites for make-check:
reiserfs, udf, xfs reiserfs, udf, xfs
- On newer kernels, the exfat kernel modules may be used instead of the - On newer kernels, the exfat kernel modules may be used instead of the
exfat FUSE filesystem exfat FUSE filesystem
- Kernel version 6.12.x was the last series to include reiserfs support,
so later kernels will fail the reiser filesystem test.
* The following are Debian named packages required mostly for the full * The following are Debian named packages required mostly for the full
suite of filesystem testing (but some are needed by other tests as well): suite of filesystem testing (but some are needed by other tests as well):
- btrfs-progs, dosfstools, e2fsprogs, erofs-utils, exfatprogs, exfat-fuse, - btrfs-progs, dosfstools, e2fsprogs, erofs-utils, exfatprogs, exfat-fuse,
@ -92,8 +100,8 @@ Prerequisites for make-check:
- attr, cpio, g++, gawk, parted, recode, tar, util-linux - attr, cpio, g++, gawk, parted, recode, tar, util-linux
Note that `make check' will run and many tests may complete successfully Note that `make check' will run and many tests may complete successfully
with only a subset of these prerequisites. However, some tests may be with only a subset of these prerequisites. However, some tests may fail
skipped or fail due to missing prerequisites. due to missing prerequisites.
To build the documentation you'll need: To build the documentation you'll need:
* texinfo, for the info and html documentation * texinfo, for the info and html documentation
@ -136,15 +144,12 @@ The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code. 1. `cd' to the directory containing the package's source code.
2. Skip this and following step if you use release tarball and proceed to 2. Type `./bootstrap'.
step 4. If you want translations type `./linguas.sh'.
3. Type `./bootstrap'. The autogen.sh (called by bootstrap) uses python. By default it is
autodetected, but it can be overridden by setting the PYTHON variable.
The autogen.sh (called by bootstrap) uses python. By default autodetect 3. Type `./configure' to configure the package for your system.
it, but it can be overridden by setting the PYTHON variable.
4. Type `./configure' to configure the package for your system.
If you're using `csh' on an old version of System V, you might If you're using `csh' on an old version of System V, you might
need to type `sh ./configure' instead to prevent `csh' from trying need to type `sh ./configure' instead to prevent `csh' from trying
to execute `configure' itself. to execute `configure' itself.
@ -152,19 +157,19 @@ The simplest way to compile this package is:
Running `configure' takes awhile. While running, it prints some Running `configure' takes awhile. While running, it prints some
messages telling which features it is checking for. messages telling which features it is checking for.
6. Type `make' to compile the package. 4. Type `make' to compile the package.
7. Optionally, type `make check' to run any self-tests that come with 5. Optionally, type `make check' to run any self-tests that come with
the package. Note that many of the tests require root privileges in the package. Note that many of the tests require root privileges and
order to run. a specially crafted environment in order to run.
8. Type `make install' to install the programs and any data files and 6. Type `make install' to install the programs and any data files and
documentation. documentation.
9. Type `make html' or `make pdf' to generate the html or pdf 7. Type `make html' or `make pdf' to generate the html or pdf
documentation. Note, these are not built by default. documentation. Note, these are not built by default.
10. You can remove the program binaries and object files from the 8. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is a different kind of computer), type `make distclean'. There is

View File

@ -36,6 +36,7 @@ library = {
common = grub-core/kern/misc.c; common = grub-core/kern/misc.c;
common = grub-core/kern/partition.c; common = grub-core/kern/partition.c;
common = grub-core/lib/crypto.c; common = grub-core/lib/crypto.c;
common = grub-core/lib/hwfeatures-gcry.c;
common = grub-core/lib/json/json.c; common = grub-core/lib/json/json.c;
common = grub-core/disk/luks.c; common = grub-core/disk/luks.c;
common = grub-core/disk/luks2.c; common = grub-core/disk/luks2.c;
@ -43,6 +44,7 @@ library = {
common = grub-core/disk/key_protector.c; common = grub-core/disk/key_protector.c;
common = grub-core/disk/cryptodisk.c; common = grub-core/disk/cryptodisk.c;
common = grub-core/disk/AFSplitter.c; common = grub-core/disk/AFSplitter.c;
common = grub-core/lib/argon2.c;
common = grub-core/lib/pbkdf2.c; common = grub-core/lib/pbkdf2.c;
common = grub-core/commands/extcmd.c; common = grub-core/commands/extcmd.c;
common = grub-core/lib/arg.c; common = grub-core/lib/arg.c;
@ -162,6 +164,7 @@ library = {
common = grub-core/io/gzio.c; common = grub-core/io/gzio.c;
common = grub-core/io/xzio.c; common = grub-core/io/xzio.c;
common = grub-core/io/lzopio.c; common = grub-core/io/lzopio.c;
common = grub-core/io/zstdio.c;
common = grub-core/kern/ia64/dl_helper.c; common = grub-core/kern/ia64/dl_helper.c;
common = grub-core/kern/arm/dl_helper.c; common = grub-core/kern/arm/dl_helper.c;
common = grub-core/kern/arm64/dl_helper.c; common = grub-core/kern/arm64/dl_helper.c;
@ -201,8 +204,8 @@ program = {
extra_dist = util/grub-mkimagexx.c; extra_dist = util/grub-mkimagexx.c;
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBLZMA)'; ldadd = '$(LIBLZMA)';
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
@ -225,8 +228,8 @@ program = {
cflags = '-I$(srcdir)/grub-core/lib/tss2 -I$(srcdir)/grub-core/commands/tpm2_key_protector'; cflags = '-I$(srcdir)/grub-core/lib/tss2 -I$(srcdir)/grub-core/commands/tpm2_key_protector';
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBTASN1)'; ldadd = '$(LIBTASN1)';
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
@ -243,8 +246,8 @@ program = {
common = grub-core/osdep/init.c; common = grub-core/osdep/init.c;
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };
@ -258,8 +261,8 @@ program = {
common = grub-core/osdep/init.c; common = grub-core/osdep/init.c;
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };
@ -284,8 +287,8 @@ program = {
ldadd = '$(LIBLZMA)'; ldadd = '$(LIBLZMA)';
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };
@ -300,8 +303,8 @@ program = {
common = grub-core/osdep/init.c; common = grub-core/osdep/init.c;
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };
@ -323,8 +326,8 @@ program = {
common = grub-core/osdep/init.c; common = grub-core/osdep/init.c;
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };
@ -341,8 +344,8 @@ program = {
cflags = '$(FUSE_CFLAGS)'; cflags = '$(FUSE_CFLAGS)';
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM) $(FUSE_LIBS)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM) $(FUSE_LIBS)';
condition = COND_GRUB_MOUNT; condition = COND_GRUB_MOUNT;
@ -359,8 +362,8 @@ program = {
cppflags = '-DGRUB_MKFONT=1'; cppflags = '-DGRUB_MKFONT=1';
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(FREETYPE_LIBS)'; ldadd = '$(FREETYPE_LIBS)';
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
@ -378,8 +381,8 @@ program = {
common = grub-core/osdep/init.c; common = grub-core/osdep/init.c;
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };
@ -436,8 +439,8 @@ program = {
common = grub-core/osdep/init.c; common = grub-core/osdep/init.c;
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };
@ -451,8 +454,8 @@ program = {
common = grub-core/osdep/init.c; common = grub-core/osdep/init.c;
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };
@ -466,8 +469,8 @@ program = {
common = grub-core/kern/emu/argp_common.c; common = grub-core/kern/emu/argp_common.c;
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };
@ -605,8 +608,8 @@ program = {
ldadd = '$(LIBLZMA)'; ldadd = '$(LIBLZMA)';
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
@ -652,8 +655,8 @@ program = {
ldadd = '$(LIBLZMA)'; ldadd = '$(LIBLZMA)';
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };
@ -691,8 +694,8 @@ program = {
ldadd = '$(LIBLZMA)'; ldadd = '$(LIBLZMA)';
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };
@ -727,8 +730,8 @@ program = {
ldadd = '$(LIBLZMA)'; ldadd = '$(LIBLZMA)';
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };
@ -911,6 +914,12 @@ script = {
common = tests/zfs_test.in; common = tests/zfs_test.in;
}; };
script = {
testcase = native;
name = zfs_zstd_test;
common = tests/zfs_zstd_test.in;
};
script = { script = {
testcase = native; testcase = native;
name = cpio_test; name = cpio_test;
@ -1285,13 +1294,13 @@ script = {
}; };
script = { script = {
testcase = native; testcase = nonnative;
name = asn1_test; name = asn1_test;
common = tests/asn1_test.in; common = tests/asn1_test.in;
}; };
script = { script = {
testcase = native; testcase = nonnative;
name = tpm2_key_protector_test; name = tpm2_key_protector_test;
common = tests/tpm2_key_protector_test.in; common = tests/tpm2_key_protector_test.in;
}; };
@ -1305,8 +1314,8 @@ program = {
common = grub-core/kern/misc.c; common = grub-core/kern/misc.c;
common = grub-core/tests/lib/test.c; common = grub-core/tests/lib/test.c;
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };
@ -1320,8 +1329,8 @@ program = {
common = grub-core/kern/misc.c; common = grub-core/kern/misc.c;
common = grub-core/tests/lib/test.c; common = grub-core/tests/lib/test.c;
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };
@ -1335,8 +1344,8 @@ program = {
common = grub-core/kern/misc.c; common = grub-core/kern/misc.c;
common = grub-core/tests/lib/test.c; common = grub-core/tests/lib/test.c;
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };
@ -1351,8 +1360,8 @@ program = {
common = grub-core/tests/lib/test.c; common = grub-core/tests/lib/test.c;
common = grub-core/lib/priority_queue.c; common = grub-core/lib/priority_queue.c;
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
condition = COND_HAVE_CXX; condition = COND_HAVE_CXX;
@ -1367,8 +1376,8 @@ program = {
common = grub-core/kern/misc.c; common = grub-core/kern/misc.c;
common = grub-core/tests/lib/test.c; common = grub-core/tests/lib/test.c;
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };
@ -1382,8 +1391,8 @@ program = {
common = grub-core/osdep/init.c; common = grub-core/osdep/init.c;
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };
@ -1400,8 +1409,8 @@ program = {
common = grub-core/kern/emu/argp_common.c; common = grub-core/kern/emu/argp_common.c;
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };
@ -1416,8 +1425,8 @@ program = {
common = grub-core/osdep/init.c; common = grub-core/osdep/init.c;
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };
@ -1434,8 +1443,8 @@ program = {
common = grub-core/osdep/init.c; common = grub-core/osdep/init.c;
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };
@ -1463,8 +1472,8 @@ program = {
common = grub-core/osdep/init.c; common = grub-core/osdep/init.c;
ldadd = libgrubmods.a; ldadd = libgrubmods.a;
ldadd = libgrubgcry.a;
ldadd = libgrubkern.a; ldadd = libgrubkern.a;
ldadd = libgrubgcry.a;
ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = grub-core/lib/gnulib/libgnu.a;
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
}; };

23
NEWS
View File

@ -1,3 +1,26 @@
New in 2.14:
* libgcrypt 1.11.
* LVM LV integrity and cachevol support.
* EROFS support.
* GRUB environment block inside the Btrfs header support.
* NX support for EFI platforms.
* shim loader protocol support.
* BLS and UKI support.
* Argon2 KDF support.
* TPM2 key protector support.
* Appended Signature Secure Boot Support for PowerPC.
* New option to block command line interface.
* Support dates outside of 1901..2038 range.
* zstdio decompression support.
* EFI code improvements and fixes.
* TPM driver fixes.
* Filesystems fixes.
* CVE and Coverity fixes.
* Tests improvements.
* Documentation improvements.
* ... and tons of other fixes and cleanups...
New in 2.12: New in 2.12:
* GCC 13 support. * GCC 13 support.

View File

@ -79,6 +79,11 @@ AC_DEFUN([grub_PROG_OBJCOPY_ABSOLUTE],
[AC_MSG_CHECKING([whether ${TARGET_OBJCOPY} works for absolute addresses]) [AC_MSG_CHECKING([whether ${TARGET_OBJCOPY} works for absolute addresses])
AC_CACHE_VAL(grub_cv_prog_objcopy_absolute, AC_CACHE_VAL(grub_cv_prog_objcopy_absolute,
[cat > conftest.c <<\EOF [cat > conftest.c <<\EOF
asm (
".globl start, _start, __start\n"
".ifdef cmain; .set start = _start = __start = cmain\n.endif\n"
".ifdef _cmain; .set start = _start = __start = _cmain\n.endif\n"
);
void cmain (void); void cmain (void);
void void
cmain (void) cmain (void)

View File

@ -52,6 +52,17 @@ for x in mpi-asm-defs.h mpih-add1.c mpih-sub1.c mpih-mul1.c mpih-mul2.c mpih-mul
cp grub-core/lib/libgcrypt-grub/mpi/generic/"$x" grub-core/lib/libgcrypt-grub/mpi/"$x" cp grub-core/lib/libgcrypt-grub/mpi/generic/"$x" grub-core/lib/libgcrypt-grub/mpi/"$x"
done done
for x in sha256-ssse3-amd64.S sha256-avx-amd64.S sha256-avx2-bmi2-amd64.S sha256-intel-shaext.c sha512-ssse3-amd64.S sha512-avx-amd64.S sha512-avx2-bmi2-amd64.S sha512-avx512-amd64.S; do
if [ -h grub-core/lib/libgcrypt-grub/cipher/"$x" ] || [ -f grub-core/lib/libgcrypt-grub/cipher/"$x" ]; then
rm grub-core/lib/libgcrypt-grub/cipher/"$x"
fi
cp grub-core/lib/libgcrypt/cipher/"$x" grub-core/lib/libgcrypt-grub/cipher/"$x"
done
if [ -f grub-core/lib/libgcrypt-grub/src/hwfeatures.c ]; then
rm grub-core/lib/libgcrypt-grub/src/hwfeatures.c
fi
for x in grub-core/lib/libgcrypt-patches/*.patch; do for x in grub-core/lib/libgcrypt-patches/*.patch; do
patch -i $x -p1 patch -i $x -p1
done done

1622
bootstrap

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,7 @@ gnulib_modules="
argp argp
base64 base64
error error
filevercmp
fnmatch fnmatch
getdelim getdelim
getline getline
@ -62,8 +63,6 @@ checkout_only_file=
copy=true copy=true
vc_ignore= vc_ignore=
SKIP_PO=t
# Build prerequisites # Build prerequisites
buildreq="\ buildreq="\
autoconf 2.64 autoconf 2.64
@ -107,4 +106,23 @@ bootstrap_post_import_hook () {
bootstrap_epilogue () { bootstrap_epilogue () {
mv INSTALL.grub INSTALL mv INSTALL.grub INSTALL
if [ "x$SKIP_PO" = "x" ]; then
# Generate LINGUAS with all supported languages. Bootstrap will
# generate a LINGUAS, but it will not contain the autogenerated
# languages.
autogenerated="en@quot en@hebrew de@hebrew en@cyrillic en@greek en@arabic en@piglatin de_CH"
{
# NOTE: xargs has no POSIX compliant way to avoid running the program
# given as an argument when there are no input lines. So ensure that
# basename is always run with at least one argument, the empty string,
# and ignore the first line of output.
ls po/*.po | xargs -L 100 basename -s .po -a "" | tail -n +2
for x in $autogenerated; do
rm -f "po/$x.po"
echo "$x"
done
} | sort | uniq | xargs >po/LINGUAS
fi
} }

View File

@ -24,6 +24,8 @@ if COND_HAVE_PCI
CFLAGS_PLATFORM += -DGRUB_HAS_PCI CFLAGS_PLATFORM += -DGRUB_HAS_PCI
endif endif
CPPFLAGS_GCRY_ASM = @CPPFLAGS_GCRY_ASM@
# Other options # Other options
CPPFLAGS_DEFAULT = -DGRUB_FILE=\"$(subst $(srcdir)/,,$<)\" CPPFLAGS_DEFAULT = -DGRUB_FILE=\"$(subst $(srcdir)/,,$<)\"

View File

@ -34,23 +34,63 @@ EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regexec-resource-leak.patch
EXTRA_DIST += grub-core/lib/gnulib-patches/fix-gcc-15-compile.patch EXTRA_DIST += grub-core/lib/gnulib-patches/fix-gcc-15-compile.patch
EXTRA_DIST += grub-core/lib/gnulib-patches/fix-unused-value.patch EXTRA_DIST += grub-core/lib/gnulib-patches/fix-unused-value.patch
EXTRA_DIST += grub-core/lib/libgcrypt-patches/01_md.patch
EXTRA_DIST += grub-core/lib/libgcrypt-patches/02_keccak_sse.patch
EXTRA_DIST += grub-core/lib/libgcrypt-patches/03_mpiutil_alloc.patch
EXTRA_DIST += grub-core/lib/libgcrypt-patches/03_sexp_free.patch
EXTRA_DIST += grub-core/lib/libgcrypt-patches/04_aria.patch
EXTRA_DIST += grub-core/lib/libgcrypt-patches/05_disable_rsa_shake.patch
EXTRA_DIST += grub-core/lib/libgcrypt-patches/06_blake.patch
EXTRA_DIST += grub-core/lib/libgcrypt-patches/07_disable_64div.patch
EXTRA_DIST += grub-core/lib/libgcrypt-patches/08_sexp_leak.patch
EXTRA_DIST += grub-core/lib/libgcrypt-patches/09-blake2b-hash-buffers.patch
EXTRA_DIST += grub-core/lib/libgcrypt-patches/10-kdf-use-GPG-errs.patch
EXTRA_DIST += grub-core/lib/libgcrypt-patches/11-kdf-remove-unsupported-kdfs.patch
EXTRA_DIST += grub-core/lib/libgcrypt-patches/12-kdf-use-grub_divmod64.patch
EXTRA_DIST += grub-core/lib/libgcrypt-patches/13_add_hwfeatures.patch
EXTRA_DIST += grub-core/lib/libgcrypt-patches/14_fix_build_shaext.patch
EXTRA_DIST += grub-core/lib/libgcrypt-patches/15_build_sha256_x86_64_efi_opt_code.patch
EXTRA_DIST += grub-core/lib/libgcrypt-patches/16_build_sha512_x86_64_efi_opt_code.patch
EXTRA_DIST += grub-core/lib/libtasn1-patches/0001-libtasn1-disable-code-not-needed-in-grub.patch
EXTRA_DIST += grub-core/lib/libtasn1-patches/0002-libtasn1-replace-strcat-with-strcpy-in-_asn1_str_cat.patch
EXTRA_DIST += grub-core/lib/libtasn1-patches/0003-libtasn1-replace-strcat-with-_asn1_str_cat.patch
EXTRA_DIST += grub-core/lib/libtasn1-patches/0004-libtasn1-adjust-the-header-paths-in-libtasn1.h.patch
EXTRA_DIST += grub-core/lib/libtasn1-patches/0005-libtasn1-Use-grub_divmod64-for-division.patch
EXTRA_DIST += grub-core/lib/libtasn1-patches/0006-libtasn1-fix-the-potential-buffer-overrun.patch
EXTRA_DIST += grub-core/lib/libtasn1-patches/0007-asn1_test-include-asn1_test.h-only.patch
EXTRA_DIST += grub-core/lib/libtasn1-patches/0008-asn1_test-rename-the-main-functions-to-the-test-name.patch
EXTRA_DIST += grub-core/lib/libtasn1-patches/0009-asn1_test-return-either-0-or-1-to-reflect-the-result.patch
EXTRA_DIST += grub-core/lib/libtasn1-patches/0010-asn1_test-remove-verbose-and-the-unnecessary-printf.patch
EXTRA_DIST += grub-core/lib/libtasn1-patches/0011-asn1_test-print-the-error-messages-with-grub_printf.patch
EXTRA_DIST += grub-core/lib/libtasn1-patches/0012-asn1_test-use-the-grub-specific-functions-and-types.patch
EXTRA_DIST += grub-core/lib/libtasn1-patches/0013-asn1_test-enable-the-testcase-only-when-GRUB_LONG_MA.patch
EXTRA_DIST += grub-core/lib/libgcrypt EXTRA_DIST += grub-core/lib/libgcrypt
EXTRA_DIST += grub-core/lib/libgcrypt-grub/mpi/generic EXTRA_DIST += grub-core/lib/libgcrypt-grub/mpi/generic
EXTRA_DIST += grub-core/lib/libtasn1
EXTRA_DIST += $(shell find $(top_srcdir)/include -name '*.h') EXTRA_DIST += $(shell find $(top_srcdir)/include -name '*.h')
EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/lib -name '*.h') EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/lib -name '*.h')
EXTRA_DIST += grub-core/efiemu/runtime/config.h EXTRA_DIST += grub-core/efiemu/runtime/config.h
EXTRA_DIST += grub-core/tests/crypto_cipher_mode_vectors.h
EXTRA_DIST += grub-core/tests/asn1/asn1_test.h EXTRA_DIST += grub-core/tests/asn1/asn1_test.h
EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/tests/asn1/tests -name '*.h') EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/tests/asn1/tests -name '*.h')
EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/commands/tpm2_key_protector -name '*.h') EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/commands/tpm2_key_protector -name '*.h')
EXTRA_DIST += grub-core/commands/tpm2_key_protector/tpm2key.asn
EXTRA_DIST += grub-core/commands/appendedsig/appendedsig.h
EXTRA_DIST += grub-core/lib/LzmaDec.c EXTRA_DIST += grub-core/lib/LzmaDec.c
EXTRA_DIST += grub-core/fs/cpio_common.c EXTRA_DIST += grub-core/fs/cpio_common.c
EXTRA_DIST += BUGS EXTRA_DIST += BUGS
EXTRA_DIST += MAINTAINERS
EXTRA_DIST += SECURITY
EXTRA_DIST += util/i386/efi/grub-dumpdevtree EXTRA_DIST += util/i386/efi/grub-dumpdevtree
EXTRA_DIST += util/spkmodem-recv.c EXTRA_DIST += util/spkmodem-recv.c
EXTRA_DIST += util/import_gcrypth.sed EXTRA_DIST += util/import_gcrypth.sed
EXTRA_DIST += util/import_gcrypt_inth.sed
EXTRA_DIST += util/bin2h.c EXTRA_DIST += util/bin2h.c
EXTRA_DIST += util/grub-gen-asciih.c EXTRA_DIST += util/grub-gen-asciih.c
EXTRA_DIST += util/grub-gen-widthspec.c EXTRA_DIST += util/grub-gen-widthspec.c
@ -132,6 +172,9 @@ EXTRA_DIST += po/hebrew.sed
EXTRA_DIST += tests/dfly-mbr-mbexample.mbr.img.gz EXTRA_DIST += tests/dfly-mbr-mbexample.mbr.img.gz
EXTRA_DIST += tests/dfly-mbr-mbexample.dfly.img.gz EXTRA_DIST += tests/dfly-mbr-mbexample.dfly.img.gz
EXTRA_DIST += tests/iso9660_ce_loop2.iso.gz
EXTRA_DIST += tests/iso9660_ce_loop.iso.gz
EXTRA_DIST += tests/iso9660_early_ce.iso.gz
EXTRA_DIST += coreboot.cfg EXTRA_DIST += coreboot.cfg
@ -142,6 +185,8 @@ EXTRA_DIST += tests/file_filter/file.lzop
EXTRA_DIST += tests/file_filter/file.lzop.sig EXTRA_DIST += tests/file_filter/file.lzop.sig
EXTRA_DIST += tests/file_filter/file.xz EXTRA_DIST += tests/file_filter/file.xz
EXTRA_DIST += tests/file_filter/file.xz.sig EXTRA_DIST += tests/file_filter/file.xz.sig
EXTRA_DIST += tests/file_filter/file.zstd
EXTRA_DIST += tests/file_filter/file.zstd.sig
EXTRA_DIST += tests/file_filter/keys EXTRA_DIST += tests/file_filter/keys
EXTRA_DIST += tests/file_filter/keys.pub EXTRA_DIST += tests/file_filter/keys.pub
EXTRA_DIST += tests/file_filter/test.cfg EXTRA_DIST += tests/file_filter/test.cfg

View File

@ -34,7 +34,7 @@ dnl "TARGET_" (such as TARGET_CC, TARGET_CFLAGS, etc.) are used for
dnl the target type. See INSTALL for full list of variables and dnl the target type. See INSTALL for full list of variables and
dnl description of the relationships between them. dnl description of the relationships between them.
AC_INIT([GRUB],[2.13],[bug-grub@gnu.org]) AC_INIT([GRUB],[2.15],[bug-grub@gnu.org])
AS_CASE(["$ERROR_PLATFORM_NOT_SUPPORT_SSP"], AS_CASE(["$ERROR_PLATFORM_NOT_SUPPORT_SSP"],
[n | no | nO | N | No | NO], [ERROR_PLATFORM_NOT_SUPPORT_SSP=no], [n | no | nO | N | No | NO], [ERROR_PLATFORM_NOT_SUPPORT_SSP=no],
@ -53,7 +53,7 @@ save_program_prefix="${program_prefix}"
AC_CANONICAL_TARGET AC_CANONICAL_TARGET
program_prefix="${save_program_prefix}" program_prefix="${save_program_prefix}"
AM_INIT_AUTOMAKE([1.11]) AM_INIT_AUTOMAKE([1.11 tar-ustar])
AC_PREREQ(2.64) AC_PREREQ(2.64)
AC_CONFIG_SRCDIR([include/grub/dl.h]) AC_CONFIG_SRCDIR([include/grub/dl.h])
AC_CONFIG_HEADERS([config-util.h]) AC_CONFIG_HEADERS([config-util.h])
@ -1148,6 +1148,239 @@ if test "x$grub_cv_cc_fno_ident" = xyes; then
TARGET_CFLAGS="$TARGET_CFLAGS -fno-ident" TARGET_CFLAGS="$TARGET_CFLAGS -fno-ident"
fi fi
# Implementation of the --disable-amd64-as-feature-detection switch.
AC_MSG_CHECKING([whether to enable AMD64 as(1) feature detection])
if test x$target_cpu = xx86_64 -a x$platform = xefi; then
CPPFLAGS_GCRY_ASM="-D__x86_64 -DHAVE_CPU_ARCH_X86"
AC_ARG_ENABLE(amd64-as-feature-detection,
AS_HELP_STRING([--disable-amd64-as-feature-detection],
[Disable the auto-detection of AMD64 as(1) features]),
[amd64_as_feature_detection=$enableval],
[amd64_as_feature_detection=yes])
else
CPPFLAGS_GCRY_ASM=
amd64_as_feature_detection=no
fi
AC_MSG_RESULT($amd64_as_feature_detection)
#
# Check whether GCC assembler supports features needed for libgcrypt amd64
# implementations
#
if test $amd64_as_feature_detection = yes; then
AC_CACHE_CHECK([whether GCC assembler is compatible for amd64 assembly implementations],
[grub_cv_gcc_x86_platform_as_ok],
[if test "$target_cpu" != "x86_64" ; then
grub_cv_gcc_x86_platform_as_ok="n/a"
else
grub_cv_gcc_x86_platform_as_ok=no
AC_LINK_IFELSE([AC_LANG_PROGRAM(
[[__asm__(
/* Test if '.type' and '.size' are supported. */
/* These work only on ELF targets. */
".text\n\t"
"asmfunc:\n\t"
".size asmfunc,.-asmfunc;\n\t"
".type asmfunc,@function;\n\t"
/* Test if assembler allows use of '/' for constant division
* (Solaris/x86 issue). If previous constant division check
* and "-Wa,--divide" workaround failed, this causes assembly
* to be disable on this machine. */
"xorl \$(123456789/12345678), %ebp;\n\t"
);
void asmfunc(void);]], [ asmfunc(); ])],
[grub_cv_gcc_x86_platform_as_ok=yes])
fi])
if test "$grub_cv_gcc_x86_platform_as_ok" = "yes"; then
# Define __PIC__ to ensure the assembly code use PIC instructions
CPPFLAGS_GCRY_ASM="$CPPFLAGS_GCRY_ASM -D__PIC__=1 -DHAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS"
fi
#
# Check whether GCC assembler supports Intel syntax
#
AC_CACHE_CHECK([whether GCC assembler is compatible for Intel syntax assembly implementations],
[grub_cv_gcc_platform_as_ok_for_intel_syntax],
[if test "$target_cpu" != "x86_64" ; then
grub_cv_gcc_platform_as_ok_for_intel_syntax="n/a"
else
grub_cv_gcc_platform_as_ok_for_intel_syntax=no
AC_LINK_IFELSE([AC_LANG_PROGRAM(
[[__asm__(
".intel_syntax noprefix\n\t"
".text\n\t"
"actest:\n\t"
"pxor xmm1, xmm7;\n\t"
"vperm2i128 ymm2, ymm3, ymm0, 1;\n\t"
"add eax, ebp;\n\t"
"rorx eax, ebp, 1;\n\t"
"sub eax, [esp + 4];\n\t"
"add dword ptr [esp + eax], 0b10101;\n\t"
".att_syntax prefix\n\t"
);
void actest(void);]], [ actest(); ])],
[grub_cv_gcc_platform_as_ok_for_intel_syntax=yes])
fi])
if test "$grub_cv_gcc_platform_as_ok_for_intel_syntax" = "yes" ; then
CPPFLAGS_GCRY_ASM="$CPPFLAGS_GCRY_ASM -DHAVE_INTEL_SYNTAX_PLATFORM_AS"
fi
#
# Check whether GCC inline assembler supports SSSE3 instructions
#
AC_CACHE_CHECK([whether GCC inline assembler supports SSSE3 instructions],
[grub_cv_gcc_inline_asm_ssse3],
[if test "$target_cpu" != "x86_64" ; then
grub_cv_gcc_inline_asm_ssse3="n/a"
else
grub_cv_gcc_inline_asm_ssse3=no
AC_LINK_IFELSE([AC_LANG_PROGRAM(
[[static unsigned char be_mask[16] __attribute__ ((aligned (16))) =
{ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
void a(void) {
__asm__("pshufb %[mask], %%xmm2\n\t"::[mask]"m"(*be_mask):);
}]], [ a(); ] )],
[grub_cv_gcc_inline_asm_ssse3=yes])
fi])
if test "$grub_cv_gcc_inline_asm_ssse3" = "yes" ; then
CPPFLAGS_GCRY_ASM="$CPPFLAGS_GCRY_ASM -DHAVE_GCC_INLINE_ASM_SSSE3"
fi
#
# Check whether GCC inline assembler supports SHA Extensions instructions.
#
AC_CACHE_CHECK([whether GCC inline assembler supports SHA Extensions instructions],
[grub_cv_gcc_inline_asm_shaext],
[if test "$target_cpu" != "x86_64" ; then
grub_cv_gcc_inline_asm_shaext="n/a"
else
grub_cv_gcc_inline_asm_shaext=no
AC_LINK_IFELSE([AC_LANG_PROGRAM(
[[void a(void) {
__asm__("sha1rnds4 \$0, %%xmm1, %%xmm3\n\t":::"cc");
__asm__("sha1nexte %%xmm1, %%xmm3\n\t":::"cc");
__asm__("sha1msg1 %%xmm1, %%xmm3\n\t":::"cc");
__asm__("sha1msg2 %%xmm1, %%xmm3\n\t":::"cc");
__asm__("sha256rnds2 %%xmm0, %%xmm1, %%xmm3\n\t":::"cc");
__asm__("sha256msg1 %%xmm1, %%xmm3\n\t":::"cc");
__asm__("sha256msg2 %%xmm1, %%xmm3\n\t":::"cc");
}]], [ a(); ] )],
[grub_cv_gcc_inline_asm_shaext=yes])
fi])
if test "$grub_cv_gcc_inline_asm_shaext" = "yes" ; then
CPPFLAGS_GCRY_ASM="$CPPFLAGS_GCRY_ASM -DHAVE_GCC_INLINE_ASM_SHAEXT -DENABLE_SHAEXT_SUPPORT"
fi
#
# Check whether GCC inline assembler supports SSE4.1 instructions.
#
AC_CACHE_CHECK([whether GCC inline assembler supports SSE4.1 instructions],
[grub_cv_gcc_inline_asm_sse41],
[if test "$target_cpu" != "x86_64" ; then
grub_cv_gcc_inline_asm_sse41="n/a"
else
grub_cv_gcc_inline_asm_sse41=no
AC_LINK_IFELSE([AC_LANG_PROGRAM(
[[void a(void) {
int i;
__asm__("pextrd \$2, %%xmm0, %[out]\n\t" : [out] "=m" (i));
}]], [ a(); ] )],
[grub_cv_gcc_inline_asm_sse41=yes])
fi])
if test "$grub_cv_gcc_inline_asm_sse41" = "yes" ; then
CPPFLAGS_GCRY_ASM="$CPPFLAGS_GCRY_ASM -DHAVE_GCC_INLINE_ASM_SSE41"
fi
#
# Check whether GCC inline assembler supports AVX instructions
#
AC_CACHE_CHECK([whether GCC inline assembler supports AVX instructions],
[grub_cv_gcc_inline_asm_avx],
[if test "$target_cpu" != "x86_64" ; then
grub_cv_gcc_inline_asm_avx="n/a"
else
grub_cv_gcc_inline_asm_avx=no
AC_LINK_IFELSE([AC_LANG_PROGRAM(
[[void a(void) {
__asm__("xgetbv; vaesdeclast (%[mem]),%%xmm0,%%xmm7\n\t"::[mem]"r"(0):);
}]], [ a(); ] )],
[grub_cv_gcc_inline_asm_avx=yes])
fi])
if test "$grub_cv_gcc_inline_asm_avx" = "yes" ; then
CPPFLAGS_GCRY_ASM="$CPPFLAGS_GCRY_ASM -DHAVE_GCC_INLINE_ASM_AVX"
fi
#
# Check whether GCC inline assembler supports AVX2 instructions
#
AC_CACHE_CHECK([whether GCC inline assembler supports AVX2 instructions],
[grub_cv_gcc_inline_asm_avx2],
[if test "$target_cpu" != "x86_64" ; then
grub_cv_gcc_inline_asm_avx2="n/a"
else
grub_cv_gcc_inline_asm_avx2=no
AC_LINK_IFELSE([AC_LANG_PROGRAM(
[[void a(void) {
__asm__("xgetbv; vpbroadcastb %%xmm7,%%ymm1\n\t":::"cc");
}]], [ a(); ] )],
[grub_cv_gcc_inline_asm_avx2=yes])
fi])
if test "$grub_cv_gcc_inline_asm_avx2" = "yes" ; then
CPPFLAGS_GCRY_ASM="$CPPFLAGS_GCRY_ASM -DHAVE_GCC_INLINE_ASM_AVX2"
fi
#
# Check whether GCC inline assembler supports AVX512 instructions
#
AC_CACHE_CHECK([whether GCC inline assembler supports AVX512 instructions],
[grub_cv_gcc_inline_asm_avx512],
[if test "$target_cpu" != "x86_64" ; then
grub_cv_gcc_inline_asm_avx512="n/a"
else
grub_cv_gcc_inline_asm_avx512=no
AC_LINK_IFELSE([AC_LANG_PROGRAM(
[[void a(void) {
__asm__("xgetbv; vpopcntq %%zmm7, %%zmm1%{%%k1%}%{z%};\n\t":::"cc");
__asm__("vpexpandb %%zmm3, %%zmm1;\n\t":::"cc");
__asm__("vpxorq %%xmm7, %%xmm7, %%xmm7;\n\t":::"cc");
__asm__("vpxorq %%ymm7, %%ymm7, %%ymm7;\n\t":::"cc");
__asm__("vpxorq (%%eax)%{1to8%}, %%zmm7, %%zmm7;\n\t":::"cc");
}]], [ a(); ] )],
[grub_cv_gcc_inline_asm_avx512=yes])
fi])
if test "$grub_cv_gcc_inline_asm_avx512" = "yes" ; then
CPPFLAGS_GCRY_ASM="$CPPFLAGS_GCRY_ASM -DHAVE_GCC_INLINE_ASM_AVX512"
fi
#
# Check whether GCC inline assembler supports BMI2 instructions
#
AC_CACHE_CHECK([whether GCC inline assembler supports BMI2 instructions],
[grub_cv_gcc_inline_asm_bmi2],
[if test "$target_cpu" != "x86_64" ; then
grub_cv_gcc_inline_asm_bmi2="n/a"
else
grub_cv_gcc_inline_asm_bmi2=no
AC_LINK_IFELSE([AC_LANG_PROGRAM(
[[unsigned int a(unsigned int x, unsigned int y) {
unsigned int tmp1, tmp2;
asm ("rorxl %2, %1, %0"
: "=r" (tmp1)
: "rm0" (x), "J" (32 - ((23) & 31)));
asm ("andnl %2, %1, %0"
: "=r" (tmp2)
: "r0" (x), "rm" (y));
return tmp1 + tmp2;
}]], [ a(1, 2); ] )],
[grub_cv_gcc_inline_asm_bmi2=yes])
fi])
if test "$grub_cv_gcc_inline_asm_bmi2" = "yes" ; then
CPPFLAGS_GCRY_ASM="$CPPFLAGS_GCRY_ASM -DHAVE_GCC_INLINE_ASM_BMI2"
fi
fi
AC_SUBST(CPPFLAGS_GCRY_ASM)
CFLAGS="$TARGET_CFLAGS" CFLAGS="$TARGET_CFLAGS"
@ -1228,7 +1461,6 @@ elif test x$grub_cv_target_cc_link_format = x-mi386pe || test x$grub_cv_target_c
TARGET_IMG_LDSCRIPT='$(top_srcdir)'"/conf/i386-cygwin-img-ld.sc" TARGET_IMG_LDSCRIPT='$(top_srcdir)'"/conf/i386-cygwin-img-ld.sc"
TARGET_IMG_LDFLAGS="-Wl,-T${TARGET_IMG_LDSCRIPT}" TARGET_IMG_LDFLAGS="-Wl,-T${TARGET_IMG_LDSCRIPT}"
TARGET_IMG_LDFLAGS_AC="-Wl,-T${srcdir}/conf/i386-cygwin-img-ld.sc" TARGET_IMG_LDFLAGS_AC="-Wl,-T${srcdir}/conf/i386-cygwin-img-ld.sc"
TARGET_IMG_BASE_LDOPT="-Wl,-Ttext"
TARGET_IMG_CFLAGS= TARGET_IMG_CFLAGS=
else else
TARGET_APPLE_LINKER=0 TARGET_APPLE_LINKER=0
@ -1236,7 +1468,6 @@ else
TARGET_IMG_LDSCRIPT= TARGET_IMG_LDSCRIPT=
TARGET_IMG_LDFLAGS='-Wl,-N' TARGET_IMG_LDFLAGS='-Wl,-N'
TARGET_IMG_LDFLAGS_AC='-Wl,-N' TARGET_IMG_LDFLAGS_AC='-Wl,-N'
TARGET_IMG_BASE_LDOPT="-Wl,-Ttext"
TARGET_IMG_CFLAGS= TARGET_IMG_CFLAGS=
fi fi
@ -1312,21 +1543,6 @@ AC_SUBST(TARGET_LDFLAGS_OLDMAGIC)
LDFLAGS="$TARGET_LDFLAGS" LDFLAGS="$TARGET_LDFLAGS"
if test "$target_cpu" = x86_64 || test "$target_cpu" = sparc64 || test "$target_cpu" = riscv64 ; then
# Use large model to support 4G memory
AC_CACHE_CHECK([whether option -mcmodel=large works], grub_cv_cc_mcmodel, [
CFLAGS="$TARGET_CFLAGS -mcmodel=large"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
[grub_cv_cc_mcmodel=yes],
[grub_cv_cc_mcmodel=no])
])
if test "x$grub_cv_cc_mcmodel" = xyes; then
TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=large"
elif test "$target_cpu" = sparc64 || test "$target_cpu" = riscv64; then
TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=medany"
fi
fi
if test "$target_cpu"-"$platform" = x86_64-efi; then if test "$target_cpu"-"$platform" = x86_64-efi; then
# EFI writes to stack below %rsp, we must not use the red zone # EFI writes to stack below %rsp, we must not use the red zone
AC_CACHE_CHECK([whether option -mno-red-zone works], grub_cv_cc_no_red_zone, [ AC_CACHE_CHECK([whether option -mno-red-zone works], grub_cv_cc_no_red_zone, [
@ -1435,6 +1651,21 @@ fi]
CFLAGS="$TARGET_CFLAGS" CFLAGS="$TARGET_CFLAGS"
if test "$target_cpu" = x86_64 || test "$target_cpu" = sparc64 || test "$target_cpu" = riscv64 ; then
# Use large model to support 4G memory
AC_CACHE_CHECK([whether option -mcmodel=large works], grub_cv_cc_mcmodel, [
CFLAGS="$TARGET_CFLAGS -mcmodel=large"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
[grub_cv_cc_mcmodel=yes],
[grub_cv_cc_mcmodel=no])
])
if test "x$grub_cv_cc_mcmodel" = xyes; then
TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=large"
elif test "$target_cpu" = sparc64 || test "$target_cpu" = riscv64; then
TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=medany"
fi
fi
# Stack smashing protector. # Stack smashing protector.
grub_CHECK_STACK_PROTECTOR grub_CHECK_STACK_PROTECTOR
AC_ARG_ENABLE([stack-protector], AC_ARG_ENABLE([stack-protector],
@ -1561,7 +1792,24 @@ LIBS=""
# Defined in acinclude.m4. # Defined in acinclude.m4.
grub_ASM_USCORE grub_ASM_USCORE
grub_PROG_TARGET_CC grub_PROG_TARGET_CC
# The error message produced by autoconf if autoconf-archive is not installed is
# quite misleading and not very helpful. So, try point people in the right direction.
m4_ifndef([AX_CHECK_LINK_FLAG], [m4_fatal([autoconf-archive is missing. You must install it to generate the configure script.])])
if test "x$TARGET_APPLE_LINKER" != x1 ; then if test "x$TARGET_APPLE_LINKER" != x1 ; then
AX_CHECK_LINK_FLAG([-Wl,--image-base,0x400000],
[TARGET_IMG_BASE_LDOPT="-Wl,--image-base"],
[TARGET_IMG_BASE_LDOPT="-Wl,-Ttext"],
[],
[AC_LANG_SOURCE([
asm (".globl start; start:");
asm (".globl _start; _start:");
asm (".globl __start; __start:");
void __main (void);
void __main (void) {}
int main (void);
])])
grub_PROG_OBJCOPY_ABSOLUTE grub_PROG_OBJCOPY_ABSOLUTE
fi fi
grub_PROG_LD_BUILD_ID_NONE grub_PROG_LD_BUILD_ID_NONE

View File

@ -77,7 +77,7 @@ This edition documents version @value{VERSION}.
* Coding style:: * Coding style::
* Finding your way around:: * Finding your way around::
* Contributing Changes:: * Contributing Changes::
* Setting up and running test suite:: * Tests::
* Updating External Code:: * Updating External Code::
* Debugging:: * Debugging::
* Porting:: * Porting::
@ -485,8 +485,17 @@ If your intention is to just get started, please do not submit a inclusion
request. Instead, please subscribe to the mailing list, and communicate first request. Instead, please subscribe to the mailing list, and communicate first
(e.g. sending a patch, asking a question, commenting on another message...). (e.g. sending a patch, asking a question, commenting on another message...).
@node Tests
@chapter Tests
@menu
* Setting up and running test suite::
* Writing new tests::
@end menu
@node Setting up and running test suite @node Setting up and running test suite
@chapter Setting up and running test suite @section Setting up and running test suite
GRUB is basically a tiny operating system with read support for many file GRUB is basically a tiny operating system with read support for many file
systems and which has been ported to a variety of architectures. As such, its systems and which has been ported to a variety of architectures. As such, its
@ -495,6 +504,47 @@ These dependencies are currently documented in the
@uref{https://git.savannah.gnu.org/cgit/grub.git/tree/INSTALL, INSTALL} @uref{https://git.savannah.gnu.org/cgit/grub.git/tree/INSTALL, INSTALL}
file in the source repository. Once installed, the test suite can be started file in the source repository. Once installed, the test suite can be started
by running the @command{make check} command from the GRUB build directory. by running the @command{make check} command from the GRUB build directory.
To properly run all the tests, the test suite must be run as the privileged
user, for instance to run the filesystem tests, which require mounting
filesystem images. Of course, virtualization or containers may be used, but
this requires extra configuration outside the scope of this document.
@node Writing new tests
@section Writing new tests
There are two kinds of tests in the GRUB test suite: native and non-native.
Native tests are those which run on the build architecture and non-native
run on the target architecture. The non-native tests are run in a QEMU
virtual machine using the grub-shell script in tests/util. When writing a
new test, first determine if it should run on the host or the target and
then look at the existing tests as examples of how to they should be written.
The GRUB test suite uses automake (@uref{https://www.gnu.org/software/automake/manual/automake.html#Tests, see documention here}). One thing of importance
to note is that tests have 4 classes of return codes: SKIP (77), HARD ERROR
(99), PASS (0), and FAIL (all other codes). A
@uref{https://www.gnu.org/software/automake/manual/automake.html#index-test-skip, SKIP return code}
should be returned when this test cannot be performed and thus should be
skipped. Typically this is because the target does not support the test,
such as the ohci USB test for the powerpc-ieee1275 target because there
are no native drivers for that target. A
@uref{https://www.gnu.org/software/automake/manual/automake.html#index-Distinction-between-errors-and-failures-in-testsuites, HARD ERROR return code}
should be returned when a failure in something other than what is intended
to be tested happens. This is commonly returned when the test cannot be
properly run because of deficiencies in the test environment, eg. when
testing the xfs filesystem, but the kernel has no support for mounting xfs
volumes. A SKIP should never be returned for a HARD ERROR condition
because at best the person running the test does not know if the test was
skipped because it doesn't apply to the target or because the tester failed
to setup the environment properly. At worst, the tester will believe that
everything is okay without realizing that the tests are not covering all
the code that it should.
Keep portability in mind while creating a new tests so that the tests can be
run on a variety of systems and shells. Do not use bashisms. Also try to avoid
using utilities that would unecessarily add software dependencies. Sometimes
this is unavoidable. Copy or adapt existing test implementations where feasible.
If the test is native and requires root, make sure to check that the test is
run with the root user and return HARD ERROR if it is not.
@node Updating External Code @node Updating External Code
@chapter Updating external code @chapter Updating external code
@ -900,26 +950,26 @@ is to be run in a GDB session running with the @file{gdb_grub} GDB script.
@node Porting @node Porting
@chapter Porting @chapter Porting
GRUB2 is designed to be easily portable accross platforms. But because of the GRUB2 is designed to be easily portable across platforms. But because of the
nature of bootloader every new port must be done separately. Here is how I did nature of bootloader every new port must be done separately. Here is how I did
MIPS (loongson and ARC) and Xen ports. Note than this is more of suggestions, MIPS (loongson and ARC) and Xen ports. Note that this is more of a suggestion,
not absolute truth. and not absolute truth.
First of all grab any architecture specifications you can find in public First of all, grab any architecture specifications you can find in the public
(please avoid NDA). domain (please avoid NDA).
First stage is ``Hello world''. I've done it outside of GRUB for simplicity. First stage is ``Hello world''. I've done it outside of GRUB for simplicity.
Your task is to have a small program which is loadable as bootloader and Your task is to have a small program which is loadable as bootloader and
clearly shows its presence to you. If you have easily accessible console clearly shows its presence to you. If you have an easily accessible console
you can just print a message. If you have a mapped framebuffer you know address you can just print a message. If you have a mapped framebuffer you know the address
of, you can draw a square. If you have a debug facility, just hanging without of, you can draw a square. If you have a debug facility, just hanging without
crashing might be enough. For the first stage you can choose to load the crashing might be enough. For the first stage, you can choose to load the
bootloader across the network since format for network image is often easier bootloader across the network since the format for a network image is often easier
than for local boot and it skips the need of small intermediary stages and than for local boot and it skips the need of small intermediary stages and
nvram handling. Additionally you can often have a good idea of the needed nvram handling. Additionally, you can often have a good idea of the needed
format by running ``file'' on any netbootable executable for given platform. format by running ``file'' on any netbootable executable for the given platform.
This program should probably have 2 parts: an assembler and C one. Assembler one This program should probably have 2 parts: an assembler and C one. The assembler one
handles BSS cleaning and other needed setup (on some platforms you may need handles BSS cleaning and other needed setup (on some platforms you may need
to switch modes or copy the executable to its definitive position). So your code to switch modes or copy the executable to its definitive position). So your code
may look like (x86 assembly for illustration purposes) may look like (x86 assembly for illustration purposes)
@ -961,12 +1011,12 @@ Sometimes you need a third file: assembly stubs for ABI-compatibility.
Once this file is functional it's time to move it into GRUB2. The startup Once this file is functional it's time to move it into GRUB2. The startup
assembly file goes to grub-core/kern/$cpu/$platform/startup.S. You should also assembly file goes to grub-core/kern/$cpu/$platform/startup.S. You should also
include grub/symbol.h and replace call to entry point with call to include grub/symbol.h and replace the call to entry point with call to
EXT_C(grub_main). The C file goes to grub-core/kern/$cpu/$platform/init.c EXT_C(grub_main). The C file goes to grub-core/kern/$cpu/$platform/init.c
and its entry point is renamed to void grub_machine_init (void). Keep final and its entry point is renamed to void grub_machine_init (void). Keep final
infinite loop for now. Stubs file if any goes to infinite loop for now. Stub files if any goes to
grub-core/kern/$cpu/$platform/callwrap.S. Sometimes either $cpu or $platform grub-core/kern/$cpu/$platform/callwrap.S. Sometimes either $cpu or $platform
is dropped if file is used on several cpus respectivelyplatforms. is dropped if file is used on several cpus respectively or platforms.
Check those locations if they already have what you're looking for. Check those locations if they already have what you're looking for.
Then modify in configure.ac the following parts: Then modify in configure.ac the following parts:
@ -984,10 +1034,10 @@ esac
@end example @end example
Sometimes CPU have additional architecture names which don't influence booting. Sometimes CPU have additional architecture names which don't influence booting.
You might want to have some canonical name to avoid having bunch of identical You might want to have some canonical name to avoid having a bunch of identical
platforms with different names. platforms with different names.
NOTE: it doesn't influence compile optimisations which depend solely on NOTE: It doesn't influence compile optimisations which depend solely on
chosen compiler and compile options. chosen compiler and compile options.
@example @example
@ -1049,7 +1099,7 @@ AM_CONDITIONAL([COND_powerpc_ieee1275], [test x$target_cpu = xpowerpc -a x$platf
@end example @end example
Next stop is gentpl.py. You need to add your platform to the list of supported Next stop is gentpl.py. You need to add your platform to the list of supported
ones (sorry that this list is duplicated): ones (unfortunately, this list is duplicated):
@example @example
GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot", GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot",
@ -1059,21 +1109,21 @@ GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot",
"mips_qemu_mips", "s390_mainframe" ] "mips_qemu_mips", "s390_mainframe" ]
@end example @end example
You may also want already to add new platform to one or several of available Now you may also want to add a new platform to one or several of available
groups. In particular we always have a group for each CPU even when only groups. In particular we always have a group for each CPU even when only
one platform for given CPU is available. one platform for given CPU is available.
Then comes grub-core/Makefile.core.def. In the block ``kernel'' you'll need Then comes grub-core/Makefile.core.def. In the block ``kernel'' you'll need
to define ldflags for your platform ($cpu_$platform_ldflags). You also need to to define ldflags for your platform ($cpu_$platform_ldflags). You also need to
declare startup asm file ($cpu_$platform_startup) as well as any other files declare a startup asm file ($cpu_$platform_startup) as well as any other files,
(e.g. init.c and callwrap.S) (e.g. $cpu_$platform = kern/$cpu/$platform/init.c). like init.c or callwrap.S (e.g. $cpu_$platform = kern/$cpu/$platform/init.c).
At this stage you will also need to add dummy dl.c and cache.S with functions At this stage, you will also need to add a dummy dl.c and cache.S with functions
grub_err_t grub_arch_dl_check_header (void *ehdr), grub_err_t grub_err_t grub_arch_dl_check_header (void *ehdr), grub_err_t
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c) and grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c) and
void grub_arch_sync_caches (void *address, grub_size_t len) (cache.S). They void grub_arch_sync_caches (void *address, grub_size_t len) (cache.S). They
won't be used for now. won't be used for now.
You will need to create directory include/$cpu/$platform and a file You will need to create a directory include/$cpu/$platform and a file
include/$cpu/types.h. The latter following this template: include/$cpu/types.h. The latter following this template:
@example @example
@ -1097,7 +1147,7 @@ include/$cpu/types.h. The latter following this template:
You will also need to add a dummy file to datetime and setjmp modules to You will also need to add a dummy file to datetime and setjmp modules to
avoid any of it having no files. It can be just completely empty at this stage. avoid any of it having no files. It can be just completely empty at this stage.
You'll need to make grub-mkimage.c (util/grub_mkimage.c) aware of the needed You'll need to make grub-mkimage (in util/grub_mkimage.c) aware of the needed
format. For most commonly used formats like ELF, PE, aout or raw the support format. For most commonly used formats like ELF, PE, aout or raw the support
is already present and you'll need to make it follow the existant code paths is already present and you'll need to make it follow the existant code paths
for your platform adding adjustments if necessary. When done compile: for your platform adding adjustments if necessary. When done compile:
@ -1108,47 +1158,47 @@ for your platform adding adjustments if necessary. When done compile:
make > /dev/null make > /dev/null
@end example @end example
And create image And create an image:
@example @example
./grub-mkimage -d grub-core -O $format_id -o test.img ./grub-mkimage -d grub-core -O $format_id -o test.img
@end example @end example
And it's time to test your test.img. And now it's time to test your test.img.
If it works next stage is to have heap, console and timer. If it works, the next stage is to have a heap, console and timer.
To have the heap working you need to determine which regions are suitable for To have the heap working you need to determine which regions are suitable for
heap usage, allocate them from firmware and map (if applicable). Then call heap usage, allocate them from the firmware and map them, if applicable.
grub_mm_init_region (void *start, grub_size_t s) for every of this region. Then call grub_mm_init_region (void *start, grub_size_t s) for each region.
As a shortcut for early port you can allocate right after _end or have As a shortcut for an early port, you can allocate right after _end or have
a big static array for heap. If you do you'll probably need to come back to a big static array for heap. If you do, you'll probably need to come back to
this later. As for output console you should distinguish between an array of this later. As for output console you should distinguish between an array of
text, terminfo or graphics-based console. Many of real-world examples don't text, terminfo or graphics-based console. Many real-world examples don't
fit perfectly into any of these categories but one of the models is easier fit perfectly into any of these categories but one of the models is easier
to be used as base. In second and third case you should add your platform to to be used as base. In the second and third case, you should add your platform to
terminfokernel respectively videoinkernel group. A good example of array of terminfokernel respectively videoinkernel group. A good example of array of
text is i386-pc (kern/i386/pc/init.c and term/i386/pc/console.c). text is i386-pc (kern/i386/pc/init.c and term/i386/pc/console.c),
Of terminfo is ieee1275 (kern/ieee1275/init.c and term/ieee1275/console.c). of terminfo is ieee1275 (kern/ieee1275/init.c and term/ieee1275/console.c),
Of video is loongson (kern/mips/loongson/init.c). Note that terminfo has and of video is loongson (kern/mips/loongson/init.c). Note that terminfo has
to be inited in 2 stages: one before (to get at least rudimentary console to be inited in 2 stages: one before (to get at least rudimentary console
as early as possible) and another after the heap (to get full-featured console). as early as possible) and another after the heap (to get full-featured console).
For the input there are string of keys, terminfo and direct hardware. For string For the input, there is a string of keys (eg. i386-pc, same files), terminfo
of keys look at i386-pc (same files), for terminfo ieee1275 (same files) and for (ieee1275, same files), and hardware (loongson, see kern/mips/loongson/init.c
hardware loongson (kern/mips/loongson/init.c and term/at_keyboard.c). and term/at_keyboard.c).
For the timer you'll need to call grub_install_get_time_ms (...) with as sole For the timer, you'll need to call grub_install_get_time_ms (...) with the
argument a function returning a grub_uint64_t of a number of milliseconds sole argument a function returning a grub_uint64_t number of milliseconds
elapsed since arbitrary point in the past. elapsed since arbitrary point in the past.
Once these steps accomplished you can remove the inifinite loop and you should Once these steps are accomplished, you can remove the inifinite loop and you should
be able to get to the minimal console. Next step is to have module loading be able to get to the minimal console. Next step is to have module loading
working. For this you'll need to fill kern/$cpu/dl.c and kern/$cpu/cache.S working. For this, you'll need to fill kern/$cpu/dl.c and kern/$cpu/cache.S
with real handling of relocations and respectively the real sync of I and D with real handling of relocations and respectively the real sync of I and D
caches. Also you'll need to decide where in the image to store the modules. caches. Also you'll need to decide where in the image to store the modules.
Usual way is to have it concatenated at the end. In this case you'll need to Usual way is to have it concatenated at the end. In this case you'll need to
modify startup.S to copy modules out of bss to let's say ALIGN_UP (_end, 8) modify startup.S to copy modules out of bss to let's say ALIGN_UP (_end, 8)
before cleaning out bss. You'll probably find useful to add total_module_size before cleaning out bss. You'll probably find it useful to add total_module_size
field to startup.S. In init.c you need to set grub_modbase to the address field to startup.S. In init.c you need to set grub_modbase to the address
where modules can be found. You may need grub_modules_get_end () to avoid where modules can be found. You may need grub_modules_get_end () to avoid
declaring the space occupied by modules as usable for heap. You can test modules declaring the space occupied by modules as usable for heap. You can test modules
@ -1164,9 +1214,9 @@ Once this works, you should think of implementing disk access. Look around
disk/ for examples. disk/ for examples.
Then, very importantly, you probably need to implement the actual loader Then, very importantly, you probably need to implement the actual loader
(examples available in loader/) (examples available in loader/).
Last step to have minimally usable port is to add support to grub-install to The last step to have a minimally usable port is to add support to grub-install to
put GRUB in a place where firmware or platform will pick it up. put GRUB in a place where firmware or platform will pick it up.
Next steps are: filling datetime.c, setjmp.S, network (net/drivers), Next steps are: filling datetime.c, setjmp.S, network (net/drivers),
@ -1175,15 +1225,15 @@ video (video/), halt (lib/), reboot (lib/).
Please add your platform to Platform limitations and Supported kernels chapter Please add your platform to Platform limitations and Supported kernels chapter
in user documentation and mention any steps you skipped which result in reduced in user documentation and mention any steps you skipped which result in reduced
features or performance. Here is the quick checklist of features. Some of them features or performance. Here is the quick checklist of features. Some of them
are less important than others and skipping them is completely ok, just needs are less important than others and skipping them is completely ok, it just needs
to be mentioned in user documentation. to be mentioned in user documentation.
Checklist: Checklist:
@itemize @itemize
@item Is heap big enough? @item Is the heap big enough?
@item Which charset is supported by console? @item Which charset is supported by the console?
@item Does platform have disk driver? @item Does the platform have disk driver?
@item Do you have network card support? @item Is there network card support?
@item Are you able to retrieve datetime (with date)? @item Are you able to retrieve datetime (with date)?
@item Are you able to set datetime (with date)? @item Are you able to set datetime (with date)?
@item Is serial supported? @item Is serial supported?
@ -1209,16 +1259,16 @@ GRUB?
@node Error Handling @node Error Handling
@chapter Error Handling @chapter Error Handling
Error handling in GRUB 2 is based on exception handling model. As C language Error handling in GRUB 2 is based on exception handling model. As the C language
doesn't directly support exceptions, exception handling behavior is emulated doesn't directly support exceptions, exception handling behavior is emulated
in software. in software.
When exception is raised, function must return to calling function. If calling When an exception is raised, the function must return to the calling function. If the calling
function does not provide handling of the exception it must return back to its function does not provide handling of the exception it must return back to its
calling function and so on, until exception is handled. If exception is not calling function and so on, until the exception is handled. If the exception is not
handled before prompt is displayed, error message will be shown to user. handled before a prompt is displayed, error message will be shown to user.
Exception information is stored on @code{grub_errno} global variable. If Exception information is stored in the @code{grub_errno} global variable. If
@code{grub_errno} variable contains value @code{GRUB_ERR_NONE}, there is no active @code{grub_errno} variable contains value @code{GRUB_ERR_NONE}, there is no active
exception and application can continue normal processing. When @code{grub_errno} has exception and application can continue normal processing. When @code{grub_errno} has
other value, it is required that application code either handles this error or other value, it is required that application code either handles this error or

File diff suppressed because it is too large Load Diff

View File

@ -246,6 +246,8 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/alloc.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/powerpc/ieee1275/ieee1275.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/powerpc/ieee1275/platform_keystore.h
endif endif
if COND_sparc64_ieee1275 if COND_sparc64_ieee1275

View File

@ -248,6 +248,7 @@ kernel = {
xen = term/xen/console.c; xen = term/xen/console.c;
xen = disk/xen/xendisk.c; xen = disk/xen/xendisk.c;
xen = commands/boot.c; xen = commands/boot.c;
xen = kern/xen/cmdline.c;
i386_xen_pvh = commands/boot.c; i386_xen_pvh = commands/boot.c;
i386_xen_pvh = disk/xen/xendisk.c; i386_xen_pvh = disk/xen/xendisk.c;
@ -255,6 +256,7 @@ kernel = {
i386_xen_pvh = kern/i386/xen/tsc.c; i386_xen_pvh = kern/i386/xen/tsc.c;
i386_xen_pvh = kern/i386/xen/pvh.c; i386_xen_pvh = kern/i386/xen/pvh.c;
i386_xen_pvh = kern/xen/init.c; i386_xen_pvh = kern/xen/init.c;
i386_xen_pvh = kern/xen/cmdline.c;
i386_xen_pvh = term/xen/console.c; i386_xen_pvh = term/xen/console.c;
ia64_efi = kern/ia64/efi/startup.S; ia64_efi = kern/ia64/efi/startup.S;
@ -331,6 +333,9 @@ kernel = {
powerpc_ieee1275 = kern/powerpc/cache.S; powerpc_ieee1275 = kern/powerpc/cache.S;
powerpc_ieee1275 = kern/powerpc/dl.c; powerpc_ieee1275 = kern/powerpc/dl.c;
powerpc_ieee1275 = kern/powerpc/compiler-rt.S; powerpc_ieee1275 = kern/powerpc/compiler-rt.S;
powerpc_ieee1275 = kern/lockdown.c;
powerpc_ieee1275 = kern/powerpc/ieee1275/ieee1275.c;
powerpc_ieee1275 = kern/powerpc/ieee1275/platform_keystore.c;
sparc64_ieee1275 = kern/sparc64/cache.S; sparc64_ieee1275 = kern/sparc64/cache.S;
sparc64_ieee1275 = kern/sparc64/dl.c; sparc64_ieee1275 = kern/sparc64/dl.c;
@ -367,6 +372,9 @@ kernel = {
emu = kern/emu/cache_s.S; emu = kern/emu/cache_s.S;
emu = kern/emu/hostdisk.c; emu = kern/emu/hostdisk.c;
emu = osdep/unix/hostdisk.c; emu = osdep/unix/hostdisk.c;
emu = osdep/relpath.c;
emu = osdep/getroot.c;
emu = osdep/unix/getroot.c;
emu = osdep/exec.c; emu = osdep/exec.c;
extra_dist = osdep/unix/exec.c; extra_dist = osdep/unix/exec.c;
emu = osdep/devmapper/hostdisk.c; emu = osdep/devmapper/hostdisk.c;
@ -845,6 +853,18 @@ module = {
common = commands/blocklist.c; common = commands/blocklist.c;
}; };
module = {
name = blsuki;
common = commands/blsuki.c;
common = lib/gnulib/filevercmp.c;
enable = powerpc_ieee1275;
enable = efi;
enable = i386_pc;
enable = emu;
cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)';
};
module = { module = {
name = boot; name = boot;
common = commands/boot.c; common = commands/boot.c;
@ -979,6 +999,21 @@ module = {
cppflags = '$(CPPFLAGS_GCRY)'; cppflags = '$(CPPFLAGS_GCRY)';
}; };
module = {
name = appendedsig;
common = commands/appendedsig/appendedsig.c;
common = commands/appendedsig/x509.c;
common = commands/appendedsig/pkcs7.c;
common = commands/appendedsig/asn1util.c;
common = commands/appendedsig/gnutls_asn1_tab.c;
common = commands/appendedsig/pkix_asn1_tab.c;
enable = emu;
enable = powerpc_ieee1275;
cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls';
cppflags = '$(CPPFLAGS_GCRY) -I$(srcdir)/lib/libtasn1-grub';
depends = crypto, gcry_rsa, gcry_sha256, gcry_sha512, mpi, asn1;
};
module = { module = {
name = hdparm; name = hdparm;
common = commands/hdparm.c; common = commands/hdparm.c;
@ -1685,6 +1720,8 @@ module = {
module = { module = {
name = crypto; name = crypto;
common = lib/crypto.c; common = lib/crypto.c;
common = lib/hwfeatures-gcry.c;
x86_64_efi = lib/x86_64/efi/hwfeatures-gcry.c;
extra_dist = lib/libgcrypt-grub/cipher/crypto.lst; extra_dist = lib/libgcrypt-grub/cipher/crypto.lst;
}; };
@ -1694,6 +1731,11 @@ module = {
common = lib/pbkdf2.c; common = lib/pbkdf2.c;
}; };
module = {
name = argon2;
common = lib/argon2.c;
};
module = { module = {
name = relocator; name = relocator;
common = lib/relocator.c; common = lib/relocator.c;
@ -2196,6 +2238,14 @@ module = {
cppflags = '$(CPPFLAGS_GCRY)'; cppflags = '$(CPPFLAGS_GCRY)';
}; };
module = {
name = appended_signature_test;
common = tests/appended_signature_test.c;
common = tests/appended_signatures.h;
enable = emu;
enable = powerpc_ieee1275;
};
module = { module = {
name = signature_test; name = signature_test;
common = tests/signature_test.c; common = tests/signature_test.c;
@ -2217,6 +2267,16 @@ module = {
common = tests/pbkdf2_test.c; common = tests/pbkdf2_test.c;
}; };
module = {
name = argon2_test;
common = tests/argon2_test.c;
};
module = {
name = crypto_cipher_mode_test;
common = tests/crypto_cipher_mode_test.c;
};
module = { module = {
name = legacy_password_test; name = legacy_password_test;
common = tests/legacy_password_test.c; common = tests/legacy_password_test.c;
@ -2469,6 +2529,13 @@ module = {
cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/minilzo -DMINILZO_HAVE_CONFIG_H'; cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/minilzo -DMINILZO_HAVE_CONFIG_H';
}; };
module = {
name = zstdio;
common = io/zstdio.c;
cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/zstd';
cflags='-Wno-unreachable-code';
};
module = { module = {
name = testload; name = testload;
common = commands/testload.c; common = commands/testload.c;

View File

@ -50,6 +50,12 @@ grub_memmove (void *dest, const void *src, grub_size_t n)
return dest; return dest;
} }
void *
grub_memcpy (void *dest, const void *src, grub_size_t n)
{
return grub_memmove (dest, src, n);
}
int int
grub_memcmp (const void *s1, const void *s2, grub_size_t n) grub_memcmp (const void *s1, const void *s2, grub_size_t n)
{ {

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,133 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2020, 2022 Free Software Foundation, Inc.
* Copyright (C) 2020, 2022, 2025 IBM Corporation
*
* 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/crypto.h>
#include <libtasn1.h>
extern asn1_node grub_gnutls_gnutls_asn;
extern asn1_node grub_gnutls_pkix_asn;
#define GRUB_MAX_OID_LEN 32
/* RSA public key. */
#define GRUB_MAX_MPI 2
#define GRUB_RSA_PK_MODULUS 0
#define GRUB_RSA_PK_EXPONENT 1
/* Certificate fingerprint. */
#define GRUB_MAX_FINGERPRINT 3
#define GRUB_FINGERPRINT_SHA256 0
#define GRUB_FINGERPRINT_SHA384 1
#define GRUB_FINGERPRINT_SHA512 2
/* Max size of hash data. */
#define GRUB_MAX_HASH_LEN 64
/*
* One or more x509 certificates. We do limited parsing:
* extracting only the version, serial, issuer, subject, RSA public key
* and key size.
* Also, hold the sha256, sha384, and sha512 fingerprint of the certificate.
*/
struct x509_certificate
{
struct x509_certificate *next;
grub_uint8_t version;
grub_uint8_t *serial;
grub_size_t serial_len;
char *issuer;
grub_size_t issuer_len;
char *subject;
grub_size_t subject_len;
/* We only support RSA public keys. This encodes [modulus, publicExponent]. */
gcry_mpi_t mpis[GRUB_MAX_MPI];
grub_int32_t modulus_size;
grub_uint8_t fingerprint[GRUB_MAX_FINGERPRINT][GRUB_MAX_HASH_LEN];
};
typedef struct x509_certificate grub_x509_cert_t;
/* A PKCS#7 signed data signer info. */
struct pkcs7_signer
{
const gcry_md_spec_t *hash;
gcry_mpi_t sig_mpi;
};
typedef struct pkcs7_signer grub_pkcs7_signer_t;
/*
* A PKCS#7 signed data message. We make no attempt to match intelligently, so
* we don't save any info about the signer.
*/
struct pkcs7_data
{
grub_int32_t signer_count;
grub_pkcs7_signer_t *signers;
};
typedef struct pkcs7_data grub_pkcs7_data_t;
/*
* Import a DER-encoded certificate at 'data', of size 'size'. Place the results
* into 'results', which must be already allocated.
*/
extern grub_err_t
grub_x509_cert_parse (const void *data, grub_size_t size, grub_x509_cert_t *results);
/*
* Release all the storage associated with the x509 certificate. If the caller
* dynamically allocated the certificate, it must free it. The caller is also
* responsible for maintenance of the linked list.
*/
extern void
grub_x509_cert_release (grub_x509_cert_t *cert);
/*
* Parse a PKCS#7 message, which must be a signed data message. The message must
* be in 'sigbuf' and of size 'data_size'. The result is placed in 'msg', which
* must already be allocated.
*/
extern grub_err_t
grub_pkcs7_data_parse (const void *sigbuf, grub_size_t data_size, grub_pkcs7_data_t *msg);
/*
* Release all the storage associated with the PKCS#7 message. If the caller
* dynamically allocated the message, it must free it.
*/
extern void
grub_pkcs7_data_release (grub_pkcs7_data_t *msg);
/* Do libtasn1 init. */
extern int
grub_asn1_init (void);
/*
* Read a value from an ASN1 node, allocating memory to store it. It will work
* for anything where the size libtasn1 returns is right:
* - Integers
* - Octet strings
* - DER encoding of other structures
*
* It will _not_ work for things where libtasn1 size requires adjustment:
* - Strings that require an extra null byte at the end
* - Bit strings because libtasn1 returns the length in bits, not bytes.
*
* If the function returns a non-NULL value, the caller must free it.
*/
extern void *
grub_asn1_allocate_and_read (asn1_node node, const char *name, const char *friendly_name,
grub_int32_t *content_size);

View File

@ -0,0 +1,99 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2020, 2022 Free Software Foundation, Inc.
* Copyright (C) 2020, 2022, 2025 IBM Corporation
*
* 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 <libtasn1.h>
#include <grub/types.h>
#include <grub/err.h>
#include <grub/mm.h>
#include <grub/crypto.h>
#include <grub/misc.h>
#include <grub/gcrypt/gcrypt.h>
#include "appendedsig.h"
asn1_node grub_gnutls_gnutls_asn = NULL;
asn1_node grub_gnutls_pkix_asn = NULL;
extern const asn1_static_node grub_gnutls_asn1_tab[];
extern const asn1_static_node grub_pkix_asn1_tab[];
/*
* Read a value from an ASN1 node, allocating memory to store it. It will work
* for anything where the size libtasn1 returns is right:
* - Integers
* - Octet strings
* - DER encoding of other structures
*
* It will _not_ work for things where libtasn1 size requires adjustment:
* - Strings that require an extra NULL byte at the end
* - Bit strings because libtasn1 returns the length in bits, not bytes.
*
* If the function returns a non-NULL value, the caller must free it.
*/
void *
grub_asn1_allocate_and_read (asn1_node node, const char *name, const char *friendly_name,
grub_int32_t *content_size)
{
grub_int32_t result;
grub_uint8_t *tmpstr = NULL;
grub_int32_t tmpstr_size = 0;
result = asn1_read_value (node, name, NULL, &tmpstr_size);
if (result != ASN1_MEM_ERROR)
{
grub_error (GRUB_ERR_BAD_FILE_TYPE, "reading size of %s did not return expected status: %s",
friendly_name, asn1_strerror (result)) ;
return NULL;
}
tmpstr = grub_malloc (tmpstr_size);
if (tmpstr == NULL)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY, "could not allocate memory to store %s",
friendly_name) ;
return NULL;
}
result = asn1_read_value (node, name, tmpstr, &tmpstr_size);
if (result != ASN1_SUCCESS)
{
grub_free (tmpstr);
grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading %s: %s", friendly_name,
asn1_strerror (result)) ;
return NULL;
}
*content_size = tmpstr_size;
return tmpstr;
}
int
grub_asn1_init (void)
{
int res;
res = asn1_array2tree (grub_gnutls_asn1_tab, &grub_gnutls_gnutls_asn, NULL);
if (res != ASN1_SUCCESS)
return res;
res = asn1_array2tree (grub_pkix_asn1_tab, &grub_gnutls_pkix_asn, NULL);
return res;
}

View File

@ -0,0 +1,148 @@
#include <grub/mm.h>
#include <libtasn1.h>
/*
* Imported from gnutls.asn.
* https://github.com/gnutls/gnutls/blob/master/lib/gnutls.asn
*/
const asn1_static_node grub_gnutls_asn1_tab[] = {
{ "GNUTLS", 536872976, NULL },
{ NULL, 1073741836, NULL },
{ "RSAPublicKey", 1610612741, NULL },
{ "modulus", 1073741827, NULL },
{ "publicExponent", 3, NULL },
{ "RSAPrivateKey", 1610612741, NULL },
{ "version", 1073741827, NULL },
{ "modulus", 1073741827, NULL },
{ "publicExponent", 1073741827, NULL },
{ "privateExponent", 1073741827, NULL },
{ "prime1", 1073741827, NULL },
{ "prime2", 1073741827, NULL },
{ "exponent1", 1073741827, NULL },
{ "exponent2", 1073741827, NULL },
{ "coefficient", 1073741827, NULL },
{ "otherPrimeInfos", 16386, "OtherPrimeInfos"},
{ "ProvableSeed", 1610612741, NULL },
{ "algorithm", 1073741836, NULL },
{ "seed", 7, NULL },
{ "OtherPrimeInfos", 1612709899, NULL },
{ "MAX", 1074266122, "1"},
{ NULL, 2, "OtherPrimeInfo"},
{ "OtherPrimeInfo", 1610612741, NULL },
{ "prime", 1073741827, NULL },
{ "exponent", 1073741827, NULL },
{ "coefficient", 3, NULL },
{ "AlgorithmIdentifier", 1610612741, NULL },
{ "algorithm", 1073741836, NULL },
{ "parameters", 541081613, NULL },
{ "algorithm", 1, NULL },
{ "DigestInfo", 1610612741, NULL },
{ "digestAlgorithm", 1073741826, "DigestAlgorithmIdentifier"},
{ "digest", 7, NULL },
{ "DigestAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"},
{ "DSAPublicKey", 1073741827, NULL },
{ "DSAParameters", 1610612741, NULL },
{ "p", 1073741827, NULL },
{ "q", 1073741827, NULL },
{ "g", 3, NULL },
{ "DSASignatureValue", 1610612741, NULL },
{ "r", 1073741827, NULL },
{ "s", 3, NULL },
{ "DSAPrivateKey", 1610612741, NULL },
{ "version", 1073741827, NULL },
{ "p", 1073741827, NULL },
{ "q", 1073741827, NULL },
{ "g", 1073741827, NULL },
{ "Y", 1073741827, NULL },
{ "priv", 3, NULL },
{ "DHParameter", 1610612741, NULL },
{ "prime", 1073741827, NULL },
{ "base", 1073741827, NULL },
{ "privateValueLength", 16387, NULL },
{ "pkcs-11-ec-Parameters", 1610612754, NULL },
{ "oId", 1073741836, NULL },
{ "curveName", 31, NULL },
{ "ECParameters", 1610612754, NULL },
{ "namedCurve", 12, NULL },
{ "ECPrivateKey", 1610612741, NULL },
{ "Version", 1073741827, NULL },
{ "privateKey", 1073741831, NULL },
{ "parameters", 1610637314, "ECParameters"},
{ NULL, 2056, "0"},
{ "publicKey", 536895494, NULL },
{ NULL, 2056, "1"},
{ "PrincipalName", 1610612741, NULL },
{ "name-type", 1610620931, NULL },
{ NULL, 2056, "0"},
{ "name-string", 536879115, NULL },
{ NULL, 1073743880, "1"},
{ NULL, 27, NULL },
{ "KRB5PrincipalName", 1610612741, NULL },
{ "realm", 1610620955, NULL },
{ NULL, 2056, "0"},
{ "principalName", 536879106, "PrincipalName"},
{ NULL, 2056, "1"},
{ "RSAPSSParameters", 1610612741, NULL },
{ "hashAlgorithm", 1610637314, "AlgorithmIdentifier"},
{ NULL, 2056, "0"},
{ "maskGenAlgorithm", 1610637314, "AlgorithmIdentifier"},
{ NULL, 2056, "1"},
{ "saltLength", 1610653699, NULL },
{ NULL, 1073741833, "20"},
{ NULL, 2056, "2"},
{ "trailerField", 536911875, NULL },
{ NULL, 1073741833, "1"},
{ NULL, 2056, "3"},
{ "RSAOAEPParameters", 1610612741, NULL },
{ "hashAlgorithm", 1610637314, "AlgorithmIdentifier"},
{ NULL, 2056, "0"},
{ "maskGenAlgorithm", 1610637314, "AlgorithmIdentifier"},
{ NULL, 2056, "1"},
{ "pSourceFunc", 536895490, "AlgorithmIdentifier"},
{ NULL, 2056, "2"},
{ "GOSTParameters", 1610612741, NULL },
{ "publicKeyParamSet", 1073741836, NULL },
{ "digestParamSet", 16396, NULL },
{ "GOSTParametersOld", 1610612741, NULL },
{ "publicKeyParamSet", 1073741836, NULL },
{ "digestParamSet", 1073741836, NULL },
{ "encryptionParamSet", 16396, NULL },
{ "GOSTPrivateKey", 1073741831, NULL },
{ "GOSTPrivateKeyOld", 1073741827, NULL },
{ "IssuerSignTool", 1610612741, NULL },
{ "signTool", 1073741858, NULL },
{ "cATool", 1073741858, NULL },
{ "signToolCert", 1073741858, NULL },
{ "cAToolCert", 34, NULL },
{ "Gost28147-89-EncryptedKey", 1610612741, NULL },
{ "encryptedKey", 1073741831, NULL },
{ "maskKey", 1610637319, NULL },
{ NULL, 4104, "0"},
{ "macKey", 7, NULL },
{ "SubjectPublicKeyInfo", 1610612741, NULL },
{ "algorithm", 1073741826, "AlgorithmIdentifier"},
{ "subjectPublicKey", 6, NULL },
{ "GostR3410-TransportParameters", 1610612741, NULL },
{ "encryptionParamSet", 1073741836, NULL },
{ "ephemeralPublicKey", 1610637314, "SubjectPublicKeyInfo"},
{ NULL, 4104, "0"},
{ "ukm", 7, NULL },
{ "GostR3410-KeyTransport", 1610612741, NULL },
{ "sessionEncryptedKey", 1073741826, "Gost28147-89-EncryptedKey"},
{ "transportParameters", 536895490, "GostR3410-TransportParameters"},
{ NULL, 4104, "0"},
{ "TPMKey", 1610612741, NULL },
{ "type", 1073741836, NULL },
{ "emptyAuth", 1610637316, NULL },
{ NULL, 2056, "0"},
{ "parent", 1073741827, NULL },
{ "pubkey", 1073741831, NULL },
{ "privkey", 7, NULL },
{ "MLDSAPrivateKey", 536870917, NULL },
{ "version", 1073741827, NULL },
{ "privateKeyAlgorithm", 1073741826, "AlgorithmIdentifier"},
{ "privateKey", 1073741831, NULL },
{ "publicKey", 536895495, NULL },
{ NULL, 2056, "1"},
{ NULL, 0, NULL }
};

View File

@ -0,0 +1,452 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2020, 2022 Free Software Foundation, Inc.
* Copyright (C) 2020, 2022, 2025 IBM Corporation
*
* 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 "appendedsig.h"
#include <grub/misc.h>
#include <grub/crypto.h>
#include <grub/gcrypt/gcrypt.h>
#include <sys/types.h>
static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
/* RFC 5652 s 5.1. */
static const char *signedData_oid = "1.2.840.113549.1.7.2";
/* RFC 4055 s 2.1. */
static const char *sha256_oid = "2.16.840.1.101.3.4.2.1";
static const char *sha512_oid = "2.16.840.1.101.3.4.2.3";
static grub_err_t
process_content (grub_uint8_t *content, grub_int32_t size, grub_pkcs7_data_t *msg)
{
grub_int32_t res;
asn1_node signed_part;
grub_err_t err = GRUB_ERR_NONE;
char algo_oid[GRUB_MAX_OID_LEN];
grub_int32_t algo_oid_size;
grub_int32_t algo_count;
grub_int32_t signer_count;
grub_int32_t i;
char version;
grub_int32_t version_size = sizeof (version);
grub_uint8_t *result_buf;
grub_int32_t result_size = 0;
grub_int32_t crls_size = 0;
gcry_error_t gcry_err;
bool sha256_in_da, sha256_in_si, sha512_in_da, sha512_in_si;
char *da_path;
char *si_sig_path;
char *si_da_path;
res = asn1_create_element (grub_gnutls_pkix_asn, "PKIX1.pkcs-7-SignedData", &signed_part);
if (res != ASN1_SUCCESS)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
"could not create ASN.1 structure for PKCS#7 signed part");
res = asn1_der_decoding2 (&signed_part, content, &size,
ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
if (res != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
"error reading PKCS#7 signed data: %s", asn1_error);
goto cleanup_signed_part;
}
/*
* SignedData ::= SEQUENCE {
* version CMSVersion,
* digestAlgorithms DigestAlgorithmIdentifiers,
* encapContentInfo EncapsulatedContentInfo,
* certificates [0] IMPLICIT CertificateSet OPTIONAL,
* crls [1] IMPLICIT RevocationInfoChoices OPTIONAL,
* signerInfos SignerInfos }
*/
res = asn1_read_value (signed_part, "version", &version, &version_size);
if (res != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_SIGNATURE, "error reading signedData version: %s",
asn1_strerror (res));
goto cleanup_signed_part;
}
/* Signature version must be 1 because appended signature only support v1. */
if (version != 1)
{
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
"unexpected signature version v%d, only v1 supported", version);
goto cleanup_signed_part;
}
/*
* digestAlgorithms DigestAlgorithmIdentifiers
*
* DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
* DigestAlgorithmIdentifer is an X.509 AlgorithmIdentifier (10.1.1)
*
* RFC 4055 s 2.1:
* sha256Identifier AlgorithmIdentifier ::= { id-sha256, NULL }
* sha512Identifier AlgorithmIdentifier ::= { id-sha512, NULL }
*
* We only support 1 element in the set, and we do not check parameters atm.
*/
res = asn1_number_of_elements (signed_part, "digestAlgorithms", &algo_count);
if (res != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_SIGNATURE, "error counting number of digest algorithms: %s",
asn1_strerror (res));
goto cleanup_signed_part;
}
if (algo_count <= 0)
{
err = grub_error (GRUB_ERR_BAD_SIGNATURE, "a minimum of 1 digest algorithm is required");
goto cleanup_signed_part;
}
if (algo_count > 2)
{
err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "a maximum of 2 digest algorithms is supported");
goto cleanup_signed_part;
}
sha256_in_da = false;
sha512_in_da = false;
for (i = 0; i < algo_count; i++)
{
da_path = grub_xasprintf ("digestAlgorithms.?%d.algorithm", i + 1);
if (da_path == NULL)
{
err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
"could not allocate path for digest algorithm parsing path");
goto cleanup_signed_part;
}
algo_oid_size = sizeof (algo_oid);
res = asn1_read_value (signed_part, da_path, algo_oid, &algo_oid_size);
if (res != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_SIGNATURE, "error reading digest algorithm: %s",
asn1_strerror (res));
grub_free (da_path);
goto cleanup_signed_part;
}
if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
{
if (sha512_in_da == false)
sha512_in_da = true;
else
{
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
"SHA-512 specified twice in digest algorithm list");
grub_free (da_path);
goto cleanup_signed_part;
}
}
else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0)
{
if (sha256_in_da == false)
sha256_in_da = true;
else
{
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
"SHA-256 specified twice in digest algorithm list");
grub_free (da_path);
goto cleanup_signed_part;
}
}
else
{
err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"only SHA-256 and SHA-512 hashes are supported, found OID %s",
algo_oid);
grub_free (da_path);
goto cleanup_signed_part;
}
grub_free (da_path);
}
/* At this point, at least one of sha{256,512}_in_da must be true. */
/*
* We ignore the certificates, but we don't permit CRLs. A CRL entry might be
* revoking the certificate we're using, and we have no way of dealing with
* that at the moment.
*/
res = asn1_read_value (signed_part, "crls", NULL, &crls_size);
if (res != ASN1_ELEMENT_NOT_FOUND)
{
err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"PKCS#7 messages with embedded CRLs are not supported");
goto cleanup_signed_part;
}
/* Read the signatures */
res = asn1_number_of_elements (signed_part, "signerInfos", &signer_count);
if (res != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_SIGNATURE, "error counting number of signers: %s",
asn1_strerror (res));
goto cleanup_signed_part;
}
if (signer_count <= 0)
{
err = grub_error (GRUB_ERR_BAD_SIGNATURE, "a minimum of 1 signer is required");
goto cleanup_signed_part;
}
msg->signers = grub_calloc (signer_count, sizeof (grub_pkcs7_signer_t));
if (msg->signers == NULL)
{
err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
"could not allocate space for %d signers", signer_count);
goto cleanup_signed_part;
}
msg->signer_count = 0;
for (i = 0; i < signer_count; i++)
{
si_da_path = grub_xasprintf ("signerInfos.?%d.digestAlgorithm.algorithm", i + 1);
if (si_da_path == NULL)
{
err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
"could not allocate path for signer %d's digest algorithm parsing path",
i);
goto cleanup_signerInfos;
}
algo_oid_size = sizeof (algo_oid);
res = asn1_read_value (signed_part, si_da_path, algo_oid, &algo_oid_size);
if (res != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
"error reading signer %d's digest algorithm: %s", i, asn1_strerror (res));
grub_free (si_da_path);
goto cleanup_signerInfos;
}
grub_free (si_da_path);
if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
{
if (sha512_in_da == false)
{
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
"signer %d claims a SHA-512 signature which was not "
"specified in the outer DigestAlgorithms", i);
goto cleanup_signerInfos;
}
else
{
sha512_in_si = true;
msg->signers[i].hash = grub_crypto_lookup_md_by_name ("sha512");
}
}
else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0)
{
if (sha256_in_da == false)
{
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
"signer %d claims a SHA-256 signature which was not "
"specified in the outer DigestAlgorithms", i);
goto cleanup_signerInfos;
}
else
{
sha256_in_si = true;
msg->signers[i].hash = grub_crypto_lookup_md_by_name ("sha256");
}
}
else
{
err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"only SHA-256 and SHA-512 hashes are supported, found OID %s",
algo_oid);
goto cleanup_signerInfos;
}
if (msg->signers[i].hash == NULL)
{
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
"Hash algorithm for signer %d (OID %s) not loaded", i, algo_oid);
goto cleanup_signerInfos;
}
si_sig_path = grub_xasprintf ("signerInfos.?%d.signature", i + 1);
if (si_sig_path == NULL)
{
err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
"could not allocate path for signer %d's signature parsing path", i);
goto cleanup_signerInfos;
}
result_buf = grub_asn1_allocate_and_read (signed_part, si_sig_path, "signature data", &result_size);
grub_free (si_sig_path);
if (result_buf == NULL)
{
err = grub_errno;
goto cleanup_signerInfos;
}
gcry_err = _gcry_mpi_scan (&(msg->signers[i].sig_mpi), GCRYMPI_FMT_USG,
result_buf, result_size, NULL);
grub_free (result_buf);
if (gcry_err != GPG_ERR_NO_ERROR)
{
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
"error loading signature %d into MPI structure: %d",
i, gcry_err);
goto cleanup_signerInfos;
}
/*
* Use msg->signer_count to track fully populated signerInfos so we know
* how many we need to clean up.
*/
msg->signer_count++;
}
/*
* Final consistency check of signerInfo.*.digestAlgorithm vs digestAlgorithms
* .*.algorithm. An algorithm must be present in both digestAlgorithms and
* signerInfo or in neither. We have already checked for an algorithm in
* signerInfo that is not in digestAlgorithms, here we check for algorithms in
* digestAlgorithms but not in signerInfos.
*/
if (sha512_in_da == true && sha512_in_si == false)
{
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
"SHA-512 specified in DigestAlgorithms but did not appear in SignerInfos");
goto cleanup_signerInfos;
}
if (sha256_in_da == true && sha256_in_si == false)
{
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
"SHA-256 specified in DigestAlgorithms but did not appear in SignerInfos");
goto cleanup_signerInfos;
}
asn1_delete_structure (&signed_part);
return GRUB_ERR_NONE;
cleanup_signerInfos:
for (i = 0; i < msg->signer_count; i++)
_gcry_mpi_release (msg->signers[i].sig_mpi);
grub_free (msg->signers);
cleanup_signed_part:
asn1_delete_structure (&signed_part);
return err;
}
grub_err_t
grub_pkcs7_data_parse (const void *sigbuf, grub_size_t data_size, grub_pkcs7_data_t *msg)
{
grub_int32_t res;
asn1_node content_info;
grub_err_t err = GRUB_ERR_NONE;
char content_oid[GRUB_MAX_OID_LEN];
grub_uint8_t *content;
grub_int32_t content_size;
grub_int32_t content_oid_size = sizeof (content_oid);
grub_int32_t size = (grub_int32_t) data_size;
if (data_size > GRUB_UINT_MAX)
return grub_error (GRUB_ERR_OUT_OF_RANGE,
"cannot parse a PKCS#7 message where data size > GRUB_UINT_MAX");
res = asn1_create_element (grub_gnutls_pkix_asn, "PKIX1.pkcs-7-ContentInfo", &content_info);
if (res != ASN1_SUCCESS)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
"could not create ASN.1 structure for PKCS#7 data: %s",
asn1_strerror (res));
res = asn1_der_decoding2 (&content_info, sigbuf, &size,
ASN1_DECODE_FLAG_STRICT_DER | ASN1_DECODE_FLAG_ALLOW_PADDING,
asn1_error);
if (res != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
"error decoding PKCS#7 message DER: %s", asn1_error);
goto cleanup;
}
/*
* ContentInfo ::= SEQUENCE {
* contentType ContentType,
* content [0] EXPLICIT ANY DEFINED BY contentType }
*
* ContentType ::= OBJECT IDENTIFIER
*/
res = asn1_read_value (content_info, "contentType", content_oid, &content_oid_size);
if (res != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_SIGNATURE, "error reading PKCS#7 content type: %s",
asn1_strerror (res));
goto cleanup;
}
/* OID for SignedData defined in 5.1. */
if (grub_strncmp (signedData_oid, content_oid, content_oid_size) != 0)
{
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
"unexpected content type in PKCS#7 message: OID %s", content_oid);
goto cleanup;
}
content = grub_asn1_allocate_and_read (content_info, "content", "PKCS#7 message content", &content_size);
if (content == NULL)
{
err = grub_errno;
goto cleanup;
}
err = process_content (content, content_size, msg);
grub_free (content);
cleanup:
asn1_delete_structure (&content_info);
return err;
}
/*
* Release all the storage associated with the PKCS#7 message. If the caller
* dynamically allocated the message, it must free it.
*/
void
grub_pkcs7_data_release (grub_pkcs7_data_t *msg)
{
grub_int32_t i;
for (i = 0; i < msg->signer_count; i++)
_gcry_mpi_release (msg->signers[i].sig_mpi);
grub_free (msg->signers);
}

View File

@ -0,0 +1,485 @@
#include <grub/mm.h>
#include <libtasn1.h>
/*
* Imported from pkix.asn.
* https://github.com/gnutls/gnutls/blob/master/lib/pkix.asn
*/
const asn1_static_node grub_pkix_asn1_tab[] = {
{ "PKIX1", 536875024, NULL },
{ NULL, 1073741836, NULL },
{ "PrivateKeyUsagePeriod", 1610612741, NULL },
{ "notBefore", 1610637349, NULL },
{ NULL, 4104, "0"},
{ "notAfter", 536895525, NULL },
{ NULL, 4104, "1"},
{ "AuthorityKeyIdentifier", 1610612741, NULL },
{ "keyIdentifier", 1610637319, NULL },
{ NULL, 4104, "0"},
{ "authorityCertIssuer", 1610637314, "GeneralNames"},
{ NULL, 4104, "1"},
{ "authorityCertSerialNumber", 536895490, "CertificateSerialNumber"},
{ NULL, 4104, "2"},
{ "SubjectKeyIdentifier", 1073741831, NULL },
{ "KeyUsage", 1073741830, NULL },
{ "DirectoryString", 1610612754, NULL },
{ "teletexString", 1612709918, NULL },
{ "MAX", 524298, "1"},
{ "printableString", 1612709919, NULL },
{ "MAX", 524298, "1"},
{ "universalString", 1612709920, NULL },
{ "MAX", 524298, "1"},
{ "utf8String", 1612709922, NULL },
{ "MAX", 524298, "1"},
{ "bmpString", 538968097, NULL },
{ "MAX", 524298, "1"},
{ "SubjectAltName", 1073741826, "GeneralNames"},
{ "GeneralNames", 1612709899, NULL },
{ "MAX", 1074266122, "1"},
{ NULL, 2, "GeneralName"},
{ "GeneralName", 1610612754, NULL },
{ "otherName", 1610620930, "AnotherName"},
{ NULL, 4104, "0"},
{ "rfc822Name", 1610620957, NULL },
{ NULL, 4104, "1"},
{ "dNSName", 1610620957, NULL },
{ NULL, 4104, "2"},
{ "x400Address", 1610620941, NULL },
{ NULL, 4104, "3"},
{ "directoryName", 1610620939, NULL },
{ NULL, 1073743880, "4"},
{ NULL, 2, "RelativeDistinguishedName"},
{ "ediPartyName", 1610620941, NULL },
{ NULL, 4104, "5"},
{ "uniformResourceIdentifier", 1610620957, NULL },
{ NULL, 4104, "6"},
{ "iPAddress", 1610620935, NULL },
{ NULL, 4104, "7"},
{ "registeredID", 536879116, NULL },
{ NULL, 4104, "8"},
{ "AnotherName", 1610612741, NULL },
{ "type-id", 1073741836, NULL },
{ "value", 541073421, NULL },
{ NULL, 1073743880, "0"},
{ "type-id", 1, NULL },
{ "IssuerAltName", 1073741826, "GeneralNames"},
{ "BasicConstraints", 1610612741, NULL },
{ "cA", 1610645508, NULL },
{ NULL, 131081, NULL },
{ "pathLenConstraint", 16387, NULL },
{ "CRLDistributionPoints", 1612709899, NULL },
{ "MAX", 1074266122, "1"},
{ NULL, 2, "DistributionPoint"},
{ "DistributionPoint", 1610612741, NULL },
{ "distributionPoint", 1610637314, "DistributionPointName"},
{ NULL, 2056, "0"},
{ "reasons", 1610637314, "ReasonFlags"},
{ NULL, 4104, "1"},
{ "cRLIssuer", 536895490, "GeneralNames"},
{ NULL, 4104, "2"},
{ "DistributionPointName", 1610612754, NULL },
{ "fullName", 1610620930, "GeneralNames"},
{ NULL, 4104, "0"},
{ "nameRelativeToCRLIssuer", 536879106, "RelativeDistinguishedName"},
{ NULL, 4104, "1"},
{ "ReasonFlags", 1073741830, NULL },
{ "ExtKeyUsageSyntax", 1612709899, NULL },
{ "MAX", 1074266122, "1"},
{ NULL, 12, NULL },
{ "AuthorityInfoAccessSyntax", 1612709899, NULL },
{ "MAX", 1074266122, "1"},
{ NULL, 2, "AccessDescription"},
{ "AccessDescription", 1610612741, NULL },
{ "accessMethod", 1073741836, NULL },
{ "accessLocation", 2, "GeneralName"},
{ "Attribute", 1610612741, NULL },
{ "type", 1073741836, NULL },
{ "values", 536870927, NULL },
{ NULL, 13, NULL },
{ "AttributeTypeAndValue", 1610612741, NULL },
{ "type", 1073741836, NULL },
{ "value", 13, NULL },
{ "Name", 1610612754, NULL },
{ "rdnSequence", 536870923, NULL },
{ NULL, 2, "RelativeDistinguishedName"},
{ "DistinguishedName", 1610612747, NULL },
{ NULL, 2, "RelativeDistinguishedName"},
{ "RelativeDistinguishedName", 1612709903, NULL },
{ "MAX", 1074266122, "1"},
{ NULL, 2, "AttributeTypeAndValue"},
{ "Certificate", 1610612741, NULL },
{ "tbsCertificate", 1073741826, "TBSCertificate"},
{ "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
{ "signature", 6, NULL },
{ "TBSCertificate", 1610612741, NULL },
{ "version", 1610653699, NULL },
{ NULL, 1073741833, "0"},
{ NULL, 2056, "0"},
{ "serialNumber", 1073741826, "CertificateSerialNumber"},
{ "signature", 1073741826, "AlgorithmIdentifier"},
{ "issuer", 1073741826, "Name"},
{ "validity", 1073741826, "Validity"},
{ "subject", 1073741826, "Name"},
{ "subjectPublicKeyInfo", 1073741826, "SubjectPublicKeyInfo"},
{ "issuerUniqueID", 1610637314, "UniqueIdentifier"},
{ NULL, 4104, "1"},
{ "subjectUniqueID", 1610637314, "UniqueIdentifier"},
{ NULL, 4104, "2"},
{ "extensions", 536895490, "Extensions"},
{ NULL, 2056, "3"},
{ "CertificateSerialNumber", 1073741827, NULL },
{ "Validity", 1610612741, NULL },
{ "notBefore", 1073741826, "Time"},
{ "notAfter", 2, "Time"},
{ "Time", 1610612754, NULL },
{ "utcTime", 1073741860, NULL },
{ "generalTime", 37, NULL },
{ "UniqueIdentifier", 1073741830, NULL },
{ "SubjectPublicKeyInfo", 1610612741, NULL },
{ "algorithm", 1073741826, "AlgorithmIdentifier"},
{ "subjectPublicKey", 6, NULL },
{ "Extensions", 1612709899, NULL },
{ "MAX", 1074266122, "1"},
{ NULL, 2, "Extension"},
{ "Extension", 1610612741, NULL },
{ "extnID", 1073741836, NULL },
{ "critical", 1610645508, NULL },
{ NULL, 131081, NULL },
{ "extnValue", 7, NULL },
{ "CertificateList", 1610612741, NULL },
{ "tbsCertList", 1073741826, "TBSCertList"},
{ "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
{ "signature", 6, NULL },
{ "TBSCertList", 1610612741, NULL },
{ "version", 1073758211, NULL },
{ "signature", 1073741826, "AlgorithmIdentifier"},
{ "issuer", 1073741826, "Name"},
{ "thisUpdate", 1073741826, "Time"},
{ "nextUpdate", 1073758210, "Time"},
{ "revokedCertificates", 1610629131, NULL },
{ NULL, 536870917, NULL },
{ "userCertificate", 1073741826, "CertificateSerialNumber"},
{ "revocationDate", 1073741826, "Time"},
{ "crlEntryExtensions", 16386, "Extensions"},
{ "crlExtensions", 536895490, "Extensions"},
{ NULL, 2056, "0"},
{ "AlgorithmIdentifier", 1610612741, NULL },
{ "algorithm", 1073741836, NULL },
{ "parameters", 541081613, NULL },
{ "algorithm", 1, NULL },
{ "Dss-Sig-Value", 1610612741, NULL },
{ "r", 1073741827, NULL },
{ "s", 3, NULL },
{ "Dss-Parms", 1610612741, NULL },
{ "p", 1073741827, NULL },
{ "q", 1073741827, NULL },
{ "g", 3, NULL },
{ "pkcs-7-ContentInfo", 1610612741, NULL },
{ "contentType", 1073741836, NULL },
{ "content", 541073421, NULL },
{ NULL, 1073743880, "0"},
{ "contentType", 1, NULL },
{ "pkcs-7-DigestInfo", 1610612741, NULL },
{ "digestAlgorithm", 1073741826, "AlgorithmIdentifier"},
{ "digest", 7, NULL },
{ "pkcs-7-SignedData", 1610612741, NULL },
{ "version", 1073741827, NULL },
{ "digestAlgorithms", 1073741826, "pkcs-7-DigestAlgorithmIdentifiers"},
{ "encapContentInfo", 1073741826, "pkcs-7-EncapsulatedContentInfo"},
{ "certificates", 1610637314, "pkcs-7-CertificateSet"},
{ NULL, 4104, "0"},
{ "crls", 1610637314, "pkcs-7-CertificateRevocationLists"},
{ NULL, 4104, "1"},
{ "signerInfos", 2, "pkcs-7-SignerInfos"},
{ "pkcs-7-DigestAlgorithmIdentifiers", 1610612751, NULL },
{ NULL, 2, "AlgorithmIdentifier"},
{ "pkcs-7-EncapsulatedContentInfo", 1610612741, NULL },
{ "eContentType", 1073741836, NULL },
{ "eContent", 536895501, NULL },
{ NULL, 2056, "0"},
{ "pkcs-7-CertificateRevocationLists", 1610612751, NULL },
{ NULL, 13, NULL },
{ "pkcs-7-CertificateChoices", 1610612754, NULL },
{ "certificate", 13, NULL },
{ "pkcs-7-CertificateSet", 1610612751, NULL },
{ NULL, 2, "pkcs-7-CertificateChoices"},
{ "IssuerAndSerialNumber", 1610612741, NULL },
{ "issuer", 1073741826, "Name"},
{ "serialNumber", 2, "CertificateSerialNumber"},
{ "pkcs-7-SignerInfo", 1610612741, NULL },
{ "version", 1073741827, NULL },
{ "sid", 1073741826, "SignerIdentifier"},
{ "digestAlgorithm", 1073741826, "AlgorithmIdentifier"},
{ "signedAttrs", 1610637314, "SignedAttributes"},
{ NULL, 4104, "0"},
{ "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
{ "signature", 1073741831, NULL },
{ "unsignedAttrs", 536895490, "SignedAttributes"},
{ NULL, 4104, "1"},
{ "SignedAttributes", 1612709903, NULL },
{ "MAX", 1074266122, "1"},
{ NULL, 2, "Attribute"},
{ "SignerIdentifier", 1610612754, NULL },
{ "issuerAndSerialNumber", 1073741826, "IssuerAndSerialNumber"},
{ "subjectKeyIdentifier", 536879111, NULL },
{ NULL, 4104, "0"},
{ "pkcs-7-SignerInfos", 1610612751, NULL },
{ NULL, 2, "pkcs-7-SignerInfo"},
{ "pkcs-10-CertificationRequestInfo", 1610612741, NULL },
{ "version", 1073741827, NULL },
{ "subject", 1073741826, "Name"},
{ "subjectPKInfo", 1073741826, "SubjectPublicKeyInfo"},
{ "attributes", 536879106, "Attributes"},
{ NULL, 4104, "0"},
{ "Attributes", 1610612751, NULL },
{ NULL, 2, "Attribute"},
{ "pkcs-10-CertificationRequest", 1610612741, NULL },
{ "certificationRequestInfo", 1073741826, "pkcs-10-CertificationRequestInfo"},
{ "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
{ "signature", 6, NULL },
{ "pkcs-9-at-challengePassword", 1879048204, NULL },
{ "iso", 1073741825, "1"},
{ "member-body", 1073741825, "2"},
{ "us", 1073741825, "840"},
{ "rsadsi", 1073741825, "113549"},
{ "pkcs", 1073741825, "1"},
{ NULL, 1073741825, "9"},
{ NULL, 1, "7"},
{ "pkcs-9-challengePassword", 1610612754, NULL },
{ "printableString", 1073741855, NULL },
{ "utf8String", 34, NULL },
{ "pkcs-9-localKeyId", 1073741831, NULL },
{ "pkcs-8-PrivateKeyInfo", 1610612741, NULL },
{ "version", 1073741827, NULL },
{ "privateKeyAlgorithm", 1073741826, "AlgorithmIdentifier"},
{ "privateKey", 1073741831, NULL },
{ "attributes", 536895490, "Attributes"},
{ NULL, 4104, "0"},
{ "pkcs-8-EncryptedPrivateKeyInfo", 1610612741, NULL },
{ "encryptionAlgorithm", 1073741826, "AlgorithmIdentifier"},
{ "encryptedData", 2, "pkcs-8-EncryptedData"},
{ "pkcs-8-EncryptedData", 1073741831, NULL },
{ "pkcs-5-des-CBC-params", 1612709895, NULL },
{ NULL, 1048586, "8"},
{ "pkcs-5-des-EDE3-CBC-params", 1612709895, NULL },
{ NULL, 1048586, "8"},
{ "pkcs-5-aes128-CBC-params", 1612709895, NULL },
{ NULL, 1048586, "16"},
{ "pkcs-5-aes192-CBC-params", 1612709895, NULL },
{ NULL, 1048586, "16"},
{ "pkcs-5-aes256-CBC-params", 1612709895, NULL },
{ NULL, 1048586, "16"},
{ "Gost28147-89-Parameters", 1610612741, NULL },
{ "iv", 1073741831, NULL },
{ "encryptionParamSet", 12, NULL },
{ "pkcs-5-PBE-params", 1610612741, NULL },
{ "salt", 1073741831, NULL },
{ "iterationCount", 3, NULL },
{ "pkcs-5-PBES2-params", 1610612741, NULL },
{ "keyDerivationFunc", 1073741826, "AlgorithmIdentifier"},
{ "encryptionScheme", 2, "AlgorithmIdentifier"},
{ "pkcs-5-PBMAC1-params", 1610612741, NULL },
{ "keyDerivationFunc", 1073741826, "AlgorithmIdentifier"},
{ "messageAuthScheme", 2, "AlgorithmIdentifier"},
{ "pkcs-5-PBKDF2-params", 1610612741, NULL },
{ "salt", 1610612754, NULL },
{ "specified", 1073741831, NULL },
{ "otherSource", 2, "AlgorithmIdentifier"},
{ "iterationCount", 1073741827, NULL },
{ "keyLength", 1073758211, NULL },
{ "prf", 16386, "AlgorithmIdentifier"},
{ "pkcs-12-PFX", 1610612741, NULL },
{ "version", 1610874883, NULL },
{ "v3", 1, "3"},
{ "authSafe", 1073741826, "pkcs-7-ContentInfo"},
{ "macData", 16386, "pkcs-12-MacData"},
{ "pkcs-12-PbeParams", 1610612741, NULL },
{ "salt", 1073741831, NULL },
{ "iterations", 3, NULL },
{ "pkcs-12-MacData", 1610612741, NULL },
{ "mac", 1073741826, "pkcs-7-DigestInfo"},
{ "macSalt", 1073741831, NULL },
{ "iterations", 536903683, NULL },
{ NULL, 9, "1"},
{ "pkcs-12-AuthenticatedSafe", 1610612747, NULL },
{ NULL, 2, "pkcs-7-ContentInfo"},
{ "pkcs-12-SafeContents", 1610612747, NULL },
{ NULL, 2, "pkcs-12-SafeBag"},
{ "pkcs-12-SafeBag", 1610612741, NULL },
{ "bagId", 1073741836, NULL },
{ "bagValue", 1614815245, NULL },
{ NULL, 1073743880, "0"},
{ "badId", 1, NULL },
{ "bagAttributes", 536887311, NULL },
{ NULL, 2, "Attribute"},
{ "pkcs-12-CertBag", 1610612741, NULL },
{ "certId", 1073741836, NULL },
{ "certValue", 541073421, NULL },
{ NULL, 1073743880, "0"},
{ "certId", 1, NULL },
{ "pkcs-12-CRLBag", 1610612741, NULL },
{ "crlId", 1073741836, NULL },
{ "crlValue", 541073421, NULL },
{ NULL, 1073743880, "0"},
{ "crlId", 1, NULL },
{ "pkcs-12-SecretBag", 1610612741, NULL },
{ "secretTypeId", 1073741836, NULL },
{ "secretValue", 541073421, NULL },
{ NULL, 1073743880, "0"},
{ "secretTypeId", 1, NULL },
{ "pkcs-7-Data", 1073741831, NULL },
{ "pkcs-7-EncryptedData", 1610612741, NULL },
{ "version", 1073741827, NULL },
{ "encryptedContentInfo", 1073741826, "pkcs-7-EncryptedContentInfo"},
{ "unprotectedAttrs", 536895490, "pkcs-7-UnprotectedAttributes"},
{ NULL, 4104, "1"},
{ "pkcs-7-EncryptedContentInfo", 1610612741, NULL },
{ "contentType", 1073741836, NULL },
{ "contentEncryptionAlgorithm", 1073741826, "pkcs-7-ContentEncryptionAlgorithmIdentifier"},
{ "encryptedContent", 536895495, NULL },
{ NULL, 4104, "0"},
{ "pkcs-7-ContentEncryptionAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"},
{ "pkcs-7-UnprotectedAttributes", 1612709903, NULL },
{ "MAX", 1074266122, "1"},
{ NULL, 2, "Attribute"},
{ "ProxyCertInfo", 1610612741, NULL },
{ "pCPathLenConstraint", 1073758211, NULL },
{ "proxyPolicy", 2, "ProxyPolicy"},
{ "ProxyPolicy", 1610612741, NULL },
{ "policyLanguage", 1073741836, NULL },
{ "policy", 16391, NULL },
{ "certificatePolicies", 1612709899, NULL },
{ "MAX", 1074266122, "1"},
{ NULL, 2, "PolicyInformation"},
{ "PolicyInformation", 1610612741, NULL },
{ "policyIdentifier", 1073741836, NULL },
{ "policyQualifiers", 538984459, NULL },
{ "MAX", 1074266122, "1"},
{ NULL, 2, "PolicyQualifierInfo"},
{ "PolicyQualifierInfo", 1610612741, NULL },
{ "policyQualifierId", 1073741836, NULL },
{ "qualifier", 541065229, NULL },
{ "policyQualifierId", 1, NULL },
{ "CPSuri", 1073741853, NULL },
{ "UserNotice", 1610612741, NULL },
{ "noticeRef", 1073758210, "NoticeReference"},
{ "explicitText", 16386, "DisplayText"},
{ "NoticeReference", 1610612741, NULL },
{ "organization", 1073741826, "DisplayText"},
{ "noticeNumbers", 536870923, NULL },
{ NULL, 3, NULL },
{ "DisplayText", 1610612754, NULL },
{ "ia5String", 1612709917, NULL },
{ "200", 524298, "1"},
{ "visibleString", 1612709923, NULL },
{ "200", 524298, "1"},
{ "bmpString", 1612709921, NULL },
{ "200", 524298, "1"},
{ "utf8String", 538968098, NULL },
{ "200", 524298, "1"},
{ "OCSPRequest", 1610612741, NULL },
{ "tbsRequest", 1073741826, "TBSRequest"},
{ "optionalSignature", 536895490, "Signature"},
{ NULL, 2056, "0"},
{ "TBSRequest", 1610612741, NULL },
{ "version", 1610653699, NULL },
{ NULL, 1073741833, "0"},
{ NULL, 2056, "0"},
{ "requestorName", 1610637314, "GeneralName"},
{ NULL, 2056, "1"},
{ "requestList", 1610612747, NULL },
{ NULL, 2, "Request"},
{ "requestExtensions", 536895490, "Extensions"},
{ NULL, 2056, "2"},
{ "Signature", 1610612741, NULL },
{ "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
{ "signature", 1073741830, NULL },
{ "certs", 536895499, NULL },
{ NULL, 1073743880, "0"},
{ NULL, 2, "Certificate"},
{ "Request", 1610612741, NULL },
{ "reqCert", 1073741826, "CertID"},
{ "singleRequestExtensions", 536895490, "Extensions"},
{ NULL, 2056, "0"},
{ "CertID", 1610612741, NULL },
{ "hashAlgorithm", 1073741826, "AlgorithmIdentifier"},
{ "issuerNameHash", 1073741831, NULL },
{ "issuerKeyHash", 1073741831, NULL },
{ "serialNumber", 2, "CertificateSerialNumber"},
{ "OCSPResponse", 1610612741, NULL },
{ "responseStatus", 1073741826, "OCSPResponseStatus"},
{ "responseBytes", 536895490, "ResponseBytes"},
{ NULL, 2056, "0"},
{ "OCSPResponseStatus", 1610874901, NULL },
{ "successful", 1073741825, "0"},
{ "malformedRequest", 1073741825, "1"},
{ "internalError", 1073741825, "2"},
{ "tryLater", 1073741825, "3"},
{ "sigRequired", 1073741825, "5"},
{ "unauthorized", 1, "6"},
{ "ResponseBytes", 1610612741, NULL },
{ "responseType", 1073741836, NULL },
{ "response", 7, NULL },
{ "BasicOCSPResponse", 1610612741, NULL },
{ "tbsResponseData", 1073741826, "ResponseData"},
{ "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
{ "signature", 1073741830, NULL },
{ "certs", 536895499, NULL },
{ NULL, 1073743880, "0"},
{ NULL, 2, "Certificate"},
{ "ResponseData", 1610612741, NULL },
{ "version", 1610653699, NULL },
{ NULL, 1073741833, "0"},
{ NULL, 2056, "0"},
{ "responderID", 1073741826, "ResponderID"},
{ "producedAt", 1073741861, NULL },
{ "responses", 1610612747, NULL },
{ NULL, 2, "SingleResponse"},
{ "responseExtensions", 536895490, "Extensions"},
{ NULL, 2056, "1"},
{ "ResponderID", 1610612754, NULL },
{ "byName", 1610620939, NULL },
{ NULL, 1073743880, "1"},
{ NULL, 2, "RelativeDistinguishedName"},
{ "byKey", 536879111, NULL },
{ NULL, 2056, "2"},
{ "SingleResponse", 1610612741, NULL },
{ "certID", 1073741826, "CertID"},
{ "certStatus", 1073741826, "CertStatus"},
{ "thisUpdate", 1073741861, NULL },
{ "nextUpdate", 1610637349, NULL },
{ NULL, 2056, "0"},
{ "singleExtensions", 536895490, "Extensions"},
{ NULL, 2056, "1"},
{ "CertStatus", 1610612754, NULL },
{ "good", 1610620948, NULL },
{ NULL, 4104, "0"},
{ "revoked", 1610620930, "RevokedInfo"},
{ NULL, 4104, "1"},
{ "unknown", 536879106, "UnknownInfo"},
{ NULL, 4104, "2"},
{ "RevokedInfo", 1610612741, NULL },
{ "revocationTime", 1073741861, NULL },
{ "revocationReason", 537157653, NULL },
{ NULL, 1073743880, "0"},
{ "unspecified", 1, "0"},
{ "UnknownInfo", 1073741844, NULL },
{ "NameConstraints", 1610612741, NULL },
{ "permittedSubtrees", 1610637314, "GeneralSubtrees"},
{ NULL, 4104, "0"},
{ "excludedSubtrees", 536895490, "GeneralSubtrees"},
{ NULL, 4104, "1"},
{ "GeneralSubtrees", 1612709899, NULL },
{ "MAX", 1074266122, "1"},
{ NULL, 2, "GeneralSubtree"},
{ "GeneralSubtree", 1610612741, NULL },
{ "base", 1073741826, "GeneralName"},
{ "minimum", 1610653699, NULL },
{ NULL, 1073741833, "0"},
{ NULL, 4104, "0"},
{ "maximum", 536895491, NULL },
{ NULL, 4104, "1"},
{ "TlsFeatures", 536870923, NULL },
{ NULL, 3, NULL },
{ NULL, 0, NULL }
};

View File

@ -0,0 +1,970 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2020, 2022 Free Software Foundation, Inc.
* Copyright (C) 2020, 2022, 2025 IBM Corporation
*
* 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 <libtasn1.h>
#include <grub/types.h>
#include <grub/err.h>
#include <grub/mm.h>
#include <grub/crypto.h>
#include <grub/misc.h>
#include <grub/gcrypt/gcrypt.h>
#include "appendedsig.h"
static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
/* RFC 3279 2.3.1 RSA Keys. */
static const char *rsaEncryption_oid = "1.2.840.113549.1.1.1";
/* RFC 5280 Appendix A. */
static const char *commonName_oid = "2.5.4.3";
/* RFC 5280 4.2.1.3 Key Usage. */
static const char *keyUsage_oid = "2.5.29.15";
static const grub_uint8_t digitalSignatureUsage = 0x80;
/* RFC 5280 4.2.1.9 Basic Constraints. */
static const char *basicConstraints_oid = "2.5.29.19";
/* RFC 5280 4.2.1.12 Extended Key Usage. */
static const char *extendedKeyUsage_oid = "2.5.29.37";
static const char *codeSigningUsage_oid = "1.3.6.1.5.5.7.3.3";
/*
* RFC 3279 2.3.1
*
* The RSA public key MUST be encoded using the ASN.1 type RSAPublicKey:
*
* RSAPublicKey ::= SEQUENCE {
* modulus INTEGER, -- n
* publicExponent INTEGER } -- e
*
* where modulus is the modulus n, and publicExponent is the public exponent e.
*/
static grub_err_t
grub_parse_rsa_pubkey (grub_uint8_t *der, grub_int32_t dersize, grub_x509_cert_t *certificate)
{
grub_int32_t result;
asn1_node spk = NULL;
grub_uint8_t *m_data, *e_data;
grub_int32_t m_size, e_size;
grub_err_t err = GRUB_ERR_NONE;
gcry_error_t gcry_err;
result = asn1_create_element (grub_gnutls_gnutls_asn, "GNUTLS.RSAPublicKey", &spk);
if (result != ASN1_SUCCESS)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
"cannot create storage for public key ASN.1 data");
result = asn1_der_decoding2 (&spk, der, &dersize, ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
if (result != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
"cannot decode certificate public key DER: %s", asn1_error);
goto cleanup;
}
m_data = grub_asn1_allocate_and_read (spk, "modulus", "RSA modulus", &m_size);
if (m_data == NULL)
{
err = grub_errno;
goto cleanup;
}
e_data = grub_asn1_allocate_and_read (spk, "publicExponent", "RSA public exponent", &e_size);
if (e_data == NULL)
{
err = grub_errno;
goto cleanup_m_data;
}
/*
* Convert m, e to mpi
*
* nscanned is not set for FMT_USG, it's only set for FMT_PGP, so we can't
* verify it.
*/
gcry_err = _gcry_mpi_scan (&certificate->mpis[0], GCRYMPI_FMT_USG, m_data, m_size, NULL);
if (gcry_err != GPG_ERR_NO_ERROR)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
"error loading RSA modulus into MPI structure: %d", gcry_err);
goto cleanup_e_data;
}
gcry_err = _gcry_mpi_scan (&certificate->mpis[1], GCRYMPI_FMT_USG, e_data, e_size, NULL);
if (gcry_err != GPG_ERR_NO_ERROR)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
"error loading RSA exponent into MPI structure: %d", gcry_err);
goto cleanup_m_mpi;
}
/* RSA key size in bits. */
certificate->modulus_size = (m_size * 8) - 8;
grub_free (e_data);
grub_free (m_data);
asn1_delete_structure (&spk);
return GRUB_ERR_NONE;
cleanup_m_mpi:
_gcry_mpi_release (certificate->mpis[0]);
cleanup_e_data:
grub_free (e_data);
cleanup_m_data:
grub_free (m_data);
cleanup:
asn1_delete_structure (&spk);
return err;
}
/*
* RFC 5280:
* SubjectPublicKeyInfo ::= SEQUENCE {
* algorithm AlgorithmIdentifier,
* subjectPublicKey BIT STRING }
*
* AlgorithmIdentifiers come from RFC 3279, we are not strictly compilant as we
* only support RSA Encryption.
*/
static grub_err_t
grub_x509_read_subject_public_key (asn1_node asn, grub_x509_cert_t *results)
{
grub_int32_t result;
grub_err_t err;
const char *algo_name = "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm";
const char *params_name = "tbsCertificate.subjectPublicKeyInfo.algorithm.parameters";
const char *pk_name = "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey";
char algo_oid[GRUB_MAX_OID_LEN];
grub_int32_t algo_size = sizeof (algo_oid);
char params_value[2];
grub_int32_t params_size = sizeof (params_value);
grub_uint8_t *key_data = NULL;
grub_int32_t key_size = 0;
grub_uint32_t key_type;
/* Algorithm: see notes for rsaEncryption_oid. */
result = asn1_read_value (asn, algo_name, algo_oid, &algo_size);
if (result != ASN1_SUCCESS)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading x509 public key algorithm: %s",
asn1_strerror (result));
if (grub_strncmp (algo_oid, rsaEncryption_oid, sizeof (rsaEncryption_oid)) != 0)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"unsupported x509 public key algorithm: %s", algo_oid);
/*
* RFC 3279 2.3.1 : The rsaEncryption OID is intended to be used in the
* algorithm field of a value of type AlgorithmIdentifier. The parameters
* field MUST have ASN.1 type NULL for this algorithm identifier.
*/
result = asn1_read_value (asn, params_name, params_value, &params_size);
if (result != ASN1_SUCCESS)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading x509 public key parameters: %s",
asn1_strerror (result));
if (params_value[0] != ASN1_TAG_NULL)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"invalid x509 public key parameters: expected NULL");
/*
* RFC 3279 2.3.1: The DER encoded RSAPublicKey is the value of the BIT
* STRING subjectPublicKey.
*/
result = asn1_read_value_type (asn, pk_name, NULL, &key_size, &key_type);
if (result != ASN1_MEM_ERROR)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading size of x509 public key: %s",
asn1_strerror (result));
if (key_type != ASN1_ETYPE_BIT_STRING)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "unexpected ASN.1 type when reading x509 public key: %x",
key_type);
/* Length is in bits. */
key_size = (key_size + 7) / 8;
key_data = grub_malloc (key_size);
if (key_data == NULL)
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory for x509 public key");
result = asn1_read_value (asn, pk_name, key_data, &key_size);
if (result != ASN1_SUCCESS)
{
grub_free (key_data);
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading public key data");
}
key_size = (key_size + 7) / 8;
err = grub_parse_rsa_pubkey (key_data, key_size, results);
grub_free (key_data);
return err;
}
/* Decode a string as defined in Appendix A. */
static grub_err_t
decode_string (char *der, grub_int32_t der_size, char **string, grub_size_t *string_size)
{
asn1_node strasn;
grub_int32_t result;
char *choice;
grub_int32_t choice_size = 0;
grub_int32_t tmp_size = 0;
grub_err_t err = GRUB_ERR_NONE;
result = asn1_create_element (grub_gnutls_pkix_asn, "PKIX1.DirectoryString", &strasn);
if (result != ASN1_SUCCESS)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
"could not create ASN.1 structure for certificate: %s",
asn1_strerror (result));
result = asn1_der_decoding2 (&strasn, der, &der_size, ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
if (result != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
"could not parse DER for DirectoryString: %s", asn1_error);
goto cleanup;
}
choice = grub_asn1_allocate_and_read (strasn, "", "DirectoryString choice", &choice_size);
if (choice == NULL)
{
err = grub_errno;
goto cleanup;
}
if (grub_strncmp ("utf8String", choice, choice_size) == 0)
{
result = asn1_read_value (strasn, "utf8String", NULL, &tmp_size);
if (result != ASN1_MEM_ERROR)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading size of UTF-8 string: %s",
asn1_strerror (result));
goto cleanup_choice;
}
}
else if (grub_strncmp ("printableString", choice, choice_size) == 0)
{
result = asn1_read_value (strasn, "printableString", NULL, &tmp_size);
if (result != ASN1_MEM_ERROR)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading size of printableString: %s",
asn1_strerror (result));
goto cleanup_choice;
}
}
else
{
err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"only UTF-8 and printable DirectoryStrings are supported, got %s",
choice);
goto cleanup_choice;
}
/* Read size does not include trailing NUL. */
tmp_size++;
*string = grub_malloc (tmp_size);
if (*string == NULL)
{
err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
"cannot allocate memory for DirectoryString contents");
goto cleanup_choice;
}
result = asn1_read_value (strasn, choice, *string, &tmp_size);
if (result != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading out %s in DirectoryString: %s",
choice, asn1_strerror (result));
grub_free (*string);
*string = NULL;
goto cleanup_choice;
}
*string_size = tmp_size + 1;
(*string)[tmp_size] = '\0';
cleanup_choice:
grub_free (choice);
cleanup:
asn1_delete_structure (&strasn);
return err;
}
/*
* TBSCertificate ::= SEQUENCE {
* version [0] EXPLICIT Version DEFAULT v1,
* ...
*
* Version ::= INTEGER { v1(0), v2(1), v3(2) }
*/
static grub_err_t
check_version (asn1_node certificate, grub_x509_cert_t *results)
{
grub_int32_t rc;
const char *name = "tbsCertificate.version";
grub_uint8_t version;
grub_int32_t len = sizeof (version);
rc = asn1_read_value (certificate, name, &version, &len);
/* Require version 3. */
if (rc != ASN1_SUCCESS || len != 1)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading certificate version");
if (version != 0x02)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"invalid x509 certificate version, expected v3 (0x02), got 0x%02x.",
version);
results->version = version;
return GRUB_ERR_NONE;
}
/* we extract only the CN and issuer. */
static grub_err_t
read_name (asn1_node asn, const char *name_path, char **name, grub_size_t *name_size)
{
grub_int32_t seq_components, set_components;
grub_int32_t result;
grub_int32_t i, j;
char *top_path, *set_path, *type_path, *val_path;
char type[GRUB_MAX_OID_LEN];
grub_int32_t type_len = sizeof (type);
grub_int32_t string_size = 0;
char *string_der;
grub_err_t err;
*name = NULL;
top_path = grub_xasprintf ("%s.rdnSequence", name_path);
if (top_path == NULL)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
"could not allocate memory for %s name parsing path", name_path);
result = asn1_number_of_elements (asn, top_path, &seq_components);
if (result != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error counting name components: %s",
asn1_strerror (result));
goto cleanup;
}
for (i = 1; i <= seq_components; i++)
{
set_path = grub_xasprintf ("%s.?%d", top_path, i);
if (set_path == NULL)
{
err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
"could not allocate memory for %s name set parsing path",
name_path);
goto cleanup_set;
}
/* This brings us, hopefully, to a set. */
result = asn1_number_of_elements (asn, set_path, &set_components);
if (result != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
"error counting name sub-components components (element %d): %s",
i, asn1_strerror (result));
goto cleanup_set;
}
for (j = 1; j <= set_components; j++)
{
type_path = grub_xasprintf ("%s.?%d.?%d.type", top_path, i, j);
if (type_path == NULL)
{
err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
"could not allocate memory for %s name component type path",
name_path);
goto cleanup_set;
}
type_len = sizeof (type);
result = asn1_read_value (asn, type_path, type, &type_len);
if (result != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading %s name component type: %s",
name_path, asn1_strerror (result));
goto cleanup_type;
}
if (grub_strncmp (type, commonName_oid, type_len) != 0)
{
grub_free (type_path);
continue;
}
val_path = grub_xasprintf ("%s.?%d.?%d.value", top_path, i, j);
if (val_path == NULL)
{
err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
"could not allocate memory for %s name component value path",
name_path);
goto cleanup_type;
}
string_der = grub_asn1_allocate_and_read (asn, val_path, name_path, &string_size);
if (string_der == NULL)
{
err = grub_errno;
goto cleanup_val_path;
}
err = decode_string (string_der, string_size, name, name_size);
if (err)
goto cleanup_string;
grub_free (string_der);
grub_free (type_path);
grub_free (val_path);
break;
}
grub_free (set_path);
if (*name)
break;
}
grub_free (top_path);
return GRUB_ERR_NONE;
cleanup_string:
grub_free (string_der);
cleanup_val_path:
grub_free (val_path);
cleanup_type:
grub_free (type_path);
cleanup_set:
grub_free (set_path);
cleanup:
grub_free (top_path);
return err;
}
/* Verify the Key Usage extension. We require the Digital Signature usage. */
static grub_err_t
verify_key_usage (grub_uint8_t *value, grub_int32_t value_size)
{
asn1_node usageasn;
grub_int32_t result;
grub_err_t err = GRUB_ERR_NONE;
grub_uint8_t usage = 0xff;
grub_int32_t usage_size = sizeof (usage_size);
result = asn1_create_element (grub_gnutls_pkix_asn, "PKIX1.KeyUsage", &usageasn);
if (result != ASN1_SUCCESS)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
"could not create ASN.1 structure for key usage");
result = asn1_der_decoding2 (&usageasn, value, &value_size,
ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
if (result != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
"error parsing DER for Key Usage: %s", asn1_error);
goto cleanup;
}
result = asn1_read_value (usageasn, "", &usage, &usage_size);
if (result != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading Key Usage value: %s",
asn1_strerror (result));
goto cleanup;
}
if (!(usage & digitalSignatureUsage))
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
"key usage (0x%x) missing Digital Signature usage", usage);
goto cleanup;
}
cleanup:
asn1_delete_structure (&usageasn);
return err;
}
/*
* BasicConstraints ::= SEQUENCE {
* cA BOOLEAN DEFAULT FALSE,
* pathLenConstraint INTEGER (0..MAX) OPTIONAL }
*/
static grub_err_t
verify_basic_constraints (grub_uint8_t *value, grub_int32_t value_size)
{
asn1_node basicasn;
grub_int32_t result;
grub_err_t err = GRUB_ERR_NONE;
char cA[6]; /* FALSE or TRUE. */
grub_int32_t cA_size = sizeof (cA);
result = asn1_create_element (grub_gnutls_pkix_asn, "PKIX1.BasicConstraints", &basicasn);
if (result != ASN1_SUCCESS)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
"could not create ASN.1 structure for Basic Constraints");
result = asn1_der_decoding2 (&basicasn, value, &value_size,
ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
if (result != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
"error parsing DER for Basic Constraints: %s", asn1_error);
goto cleanup;
}
result = asn1_read_value (basicasn, "cA", cA, &cA_size);
if (result == ASN1_ELEMENT_NOT_FOUND)
{
/* Not present, default is False, so this is OK. */
err = GRUB_ERR_NONE;
goto cleanup;
}
else if (result != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading Basic Constraints cA value: %s",
asn1_strerror (result));
goto cleanup;
}
/* The certificate must not be a CA certificate. */
if (grub_strncmp ("FALSE", cA, cA_size) != 0)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "unexpected CA value: %s", cA);
goto cleanup;
}
cleanup:
asn1_delete_structure (&basicasn);
return err;
}
/*
* Verify the Extended Key Usage extension. We require the Code Signing usage.
*
* ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
*
* KeyPurposeId ::= OBJECT IDENTIFIER
*/
static grub_err_t
verify_extended_key_usage (grub_uint8_t *value, grub_int32_t value_size)
{
asn1_node extendedasn;
grub_int32_t result, count, i = 0;
grub_err_t err = GRUB_ERR_NONE;
char usage[GRUB_MAX_OID_LEN], name[3];
grub_int32_t usage_size = sizeof (usage);
result = asn1_create_element (grub_gnutls_pkix_asn, "PKIX1.ExtKeyUsageSyntax", &extendedasn);
if (result != ASN1_SUCCESS)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
"could not create ASN.1 structure for Extended Key Usage");
result = asn1_der_decoding2 (&extendedasn, value, &value_size,
ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
if (result != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
"error parsing DER for Extended Key Usage: %s", asn1_error);
goto cleanup;
}
/* If EKUs are present, it checks the presents of Code Signing usage. */
result = asn1_number_of_elements (extendedasn, "", &count);
if (result != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error counting number of Extended Key Usages: %s",
asn1_strerror (result));
goto cleanup;
}
for (i = 1; i < count + 1; i++)
{
grub_memset (name, 0, sizeof (name));
grub_snprintf (name, sizeof (name), "?%d", i);
result = asn1_read_value (extendedasn, name, usage, &usage_size);
if (result != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading Extended Key Usage: %s",
asn1_strerror (result));
goto cleanup;
}
if (grub_strncmp (codeSigningUsage_oid, usage, usage_size) == 0)
goto cleanup;
}
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "extended key usage missing Code Signing usage");
cleanup:
asn1_delete_structure (&extendedasn);
return err;
}
/*
* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
*
* Extension ::= SEQUENCE {
* extnID OBJECT IDENTIFIER,
* critical BOOLEAN DEFAULT FALSE,
* extnValue OCTET STRING
* -- contains the DER encoding of an ASN.1 value
* -- corresponding to the extension type identified
* -- by extnID
* }
*
* A certificate must:
* - contain the Digital Signature usage
* - not be a CA
* - contain no extended usages, or contain the Code Signing extended usage
* - not contain any other critical extensions (RFC 5280 s 4.2)
*/
static grub_err_t
verify_extensions (asn1_node cert)
{
grub_int32_t result;
grub_int32_t ext, num_extensions = 0;
grub_int32_t usage_present = 0, constraints_present = 0, extended_usage_present = 0;
char *oid_path, *critical_path, *value_path;
char extnID[GRUB_MAX_OID_LEN];
grub_int32_t extnID_size;
grub_err_t err;
char critical[6]; /* We get either "TRUE" or "FALSE". */
grub_int32_t critical_size;
grub_uint8_t *value;
grub_int32_t value_size;
result = asn1_number_of_elements (cert, "tbsCertificate.extensions", &num_extensions);
if (result != ASN1_SUCCESS)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "error counting number of extensions: %s",
asn1_strerror (result));
if (num_extensions < 2)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"insufficient number of extensions for certificate, need at least 2, got %d",
num_extensions);
for (ext = 1; ext <= num_extensions; ext++)
{
oid_path = grub_xasprintf ("tbsCertificate.extensions.?%d.extnID", ext);
if (oid_path == NULL)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error extension OID path is empty");
return err;
}
extnID_size = sizeof (extnID);
result = asn1_read_value (cert, oid_path, extnID, &extnID_size);
if (result != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading extension OID: %s",
asn1_strerror (result));
goto cleanup_oid_path;
}
critical_path = grub_xasprintf ("tbsCertificate.extensions.?%d.critical", ext);
if (critical_path == NULL)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error critical path is empty");
goto cleanup_oid_path;
}
critical_size = sizeof (critical);
result = asn1_read_value (cert, critical_path, critical, &critical_size);
if (result == ASN1_ELEMENT_NOT_FOUND)
critical[0] = '\0';
else if (result != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading extension criticality: %s",
asn1_strerror (result));
goto cleanup_critical_path;
}
value_path = grub_xasprintf ("tbsCertificate.extensions.?%d.extnValue", ext);
if (value_path == NULL)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error extnValue path is empty");
goto cleanup_critical_path;
}
value = grub_asn1_allocate_and_read (cert, value_path,
"certificate extension value", &value_size);
if (value == NULL)
{
err = grub_errno;
goto cleanup_value_path;
}
/*
* Now we must see if we recognise the OID. If we have an unrecognised
* critical extension we MUST bail.
*/
if (grub_strncmp (keyUsage_oid, extnID, extnID_size) == 0)
{
err = verify_key_usage (value, value_size);
if (err != GRUB_ERR_NONE)
goto cleanup_value;
usage_present++;
}
else if (grub_strncmp (basicConstraints_oid, extnID, extnID_size) == 0)
{
err = verify_basic_constraints (value, value_size);
if (err != GRUB_ERR_NONE)
goto cleanup_value;
constraints_present++;
}
else if (grub_strncmp (extendedKeyUsage_oid, extnID, extnID_size) == 0)
{
err = verify_extended_key_usage (value, value_size);
if (err != GRUB_ERR_NONE)
goto cleanup_value;
extended_usage_present++;
}
else if (grub_strncmp ("TRUE", critical, critical_size) == 0)
{
/*
* Per the RFC, we must not process a certificate with a critical
* extension we do not understand.
*/
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
"unhandled critical x509 extension with OID %s", extnID);
goto cleanup_value;
}
grub_free (value);
grub_free (value_path);
grub_free (critical_path);
grub_free (oid_path);
}
if (usage_present != 1)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"unexpected number of Key Usage extensions - expected 1, got %d",
usage_present);
if (constraints_present != 1)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"unexpected number of basic constraints extensions - expected 1, got %d",
constraints_present);
if (extended_usage_present > 1)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"unexpected number of Extended Key Usage extensions - expected 0 or 1, got %d",
extended_usage_present);
return GRUB_ERR_NONE;
cleanup_value:
grub_free (value);
cleanup_value_path:
grub_free (value_path);
cleanup_critical_path:
grub_free (critical_path);
cleanup_oid_path:
grub_free (oid_path);
return err;
}
static void
add_cert_fingerprint (const void *data, const grub_size_t data_size,
grub_x509_cert_t *const cert)
{
/* Add SHA256 hash of certificate. */
grub_crypto_hash ((gcry_md_spec_t *) &_gcry_digest_spec_sha256,
&cert->fingerprint[GRUB_FINGERPRINT_SHA256], data, data_size);
/* Add SHA384 hash of certificate. */
grub_crypto_hash ((gcry_md_spec_t *) &_gcry_digest_spec_sha384,
&cert->fingerprint[GRUB_FINGERPRINT_SHA384], data, data_size);
/* Add SHA512 hash of certificate. */
grub_crypto_hash ((gcry_md_spec_t *) &_gcry_digest_spec_sha512,
&cert->fingerprint[GRUB_FINGERPRINT_SHA512], data, data_size);
}
/*
* Parse a certificate whose DER-encoded form is in @data, of size @data_size.
* Return the results in @results, which must point to an allocated x509
* certificate.
*/
grub_err_t
grub_x509_cert_parse (const void *data, grub_size_t data_size, grub_x509_cert_t *results)
{
grub_int32_t result = 0;
asn1_node cert;
grub_err_t err;
grub_int32_t tmp_size;
grub_int32_t size = (grub_int32_t) data_size;
if (data_size > GRUB_UINT_MAX)
return grub_error (GRUB_ERR_OUT_OF_RANGE,
"cannot parse a certificate where data size > GRUB_UINT_MAX");
result = asn1_create_element (grub_gnutls_pkix_asn, "PKIX1.Certificate", &cert);
if (result != ASN1_SUCCESS)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
"could not create ASN.1 structure for certificate: %s",
asn1_strerror (result));
result = asn1_der_decoding2 (&cert, data, &size, ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
if (result != ASN1_SUCCESS)
{
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
"could not parse DER for certificate: %s", asn1_error);
goto cleanup;
}
/*
* TBSCertificate ::= SEQUENCE {
* version [0] EXPLICIT Version DEFAULT v1
*/
err = check_version (cert, results);
if (err != GRUB_ERR_NONE)
goto cleanup;
/*
* serialNumber CertificateSerialNumber,
*
* CertificateSerialNumber ::= INTEGER
*/
results->serial = grub_asn1_allocate_and_read (cert, "tbsCertificate.serialNumber",
"certificate serial number", &tmp_size);
if (results->serial == NULL)
{
err = grub_errno;
goto cleanup;
}
/*
* It's safe to cast the signed int to an unsigned here, we know
* length is non-negative.
*/
results->serial_len = tmp_size;
/*
* signature AlgorithmIdentifier,
*
* We don't load the signature or issuer at the moment,
* as we don't attempt x509 verification.
*/
/*
* validity Validity,
*
* Validity ::= SEQUENCE {
* notBefore Time,
* notAfter Time }
*
* We can't validate this reasonably, we have no true time source on several
* platforms. For now we do not parse them.
*/
/*
* issuer Name,
*
* This is an X501 name, we parse out just the issuer.
*/
err = read_name (cert, "tbsCertificate.issuer", &results->issuer, &results->issuer_len);
if (err != GRUB_ERR_NONE)
goto cleanup_serial;
/*
* subject Name,
*
* This is an X501 name, we parse out just the CN.
*/
err = read_name (cert, "tbsCertificate.subject", &results->subject, &results->subject_len);
if (err != GRUB_ERR_NONE)
goto cleanup_issuer;
/*
* TBSCertificate ::= SEQUENCE {
* ...
* subjectPublicKeyInfo SubjectPublicKeyInfo,
* ...
*/
err = grub_x509_read_subject_public_key (cert, results);
if (err != GRUB_ERR_NONE)
goto cleanup_name;
/*
* TBSCertificate ::= SEQUENCE {
* ...
* extensions [3] EXPLICIT Extensions OPTIONAL
* -- If present, version MUST be v3
* }
*/
err = verify_extensions (cert);
if (err != GRUB_ERR_NONE)
goto cleanup_mpis;
/*
* We do not read or check the signature on the certificate:
* as discussed we do not try to validate the certificate but trust
* it implictly.
*/
asn1_delete_structure (&cert);
/* Add the fingerprint of the certificate. */
add_cert_fingerprint (data, data_size, results);
return GRUB_ERR_NONE;
cleanup_mpis:
_gcry_mpi_release (results->mpis[GRUB_RSA_PK_MODULUS]);
_gcry_mpi_release (results->mpis[GRUB_RSA_PK_EXPONENT]);
cleanup_name:
grub_free (results->subject);
cleanup_issuer:
grub_free (results->issuer);
cleanup_serial:
grub_free (results->serial);
cleanup:
asn1_delete_structure (&cert);
return err;
}
/*
* Release all the storage associated with the x509 certificate. If the caller
* dynamically allocated the certificate, it must free it. The caller is also
* responsible for maintenance of the linked list.
*/
void
grub_x509_cert_release (grub_x509_cert_t *cert)
{
grub_free (cert->issuer);
grub_free (cert->subject);
grub_free (cert->serial);
_gcry_mpi_release (cert->mpis[GRUB_RSA_PK_MODULUS]);
_gcry_mpi_release (cert->mpis[GRUB_RSA_PK_EXPONENT]);
}

View File

@ -28,6 +28,7 @@
#include <grub/misc.h> #include <grub/misc.h>
#include <grub/mm.h> #include <grub/mm.h>
#include <grub/partition.h> #include <grub/partition.h>
#include <grub/tpm.h>
#include <grub/types.h> #include <grub/types.h>
GRUB_MOD_LICENSE ("GPLv3+"); GRUB_MOD_LICENSE ("GPLv3+");
@ -127,12 +128,34 @@ set_loader_device_part_uuid (void)
return status; return status;
} }
static grub_err_t
set_loader_active_pcr_banks (void)
{
grub_efi_uint32_t active_pcr_banks;
char *active_pcr_banks_str;
grub_err_t status;
active_pcr_banks = grub_tpm2_active_pcr_banks();
active_pcr_banks_str = grub_xasprintf ("0x%08x", active_pcr_banks);
if (active_pcr_banks_str == NULL)
return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate active PCR banks string"));
status = grub_efi_set_variable_to_string ("LoaderTpm2ActivePcrBanks",
&bli_vendor_guid,
active_pcr_banks_str,
GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS |
GRUB_EFI_VARIABLE_RUNTIME_ACCESS);
grub_free (active_pcr_banks_str);
return status;
}
GRUB_MOD_INIT (bli) GRUB_MOD_INIT (bli)
{ {
grub_efi_set_variable_to_string ("LoaderInfo", &bli_vendor_guid, PACKAGE_STRING, grub_efi_set_variable_to_string ("LoaderInfo", &bli_vendor_guid, PACKAGE_STRING,
GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS | GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS |
GRUB_EFI_VARIABLE_RUNTIME_ACCESS); GRUB_EFI_VARIABLE_RUNTIME_ACCESS);
set_loader_device_part_uuid (); set_loader_device_part_uuid ();
set_loader_active_pcr_banks ();
/* No error here is critical, other than being logged */ /* No error here is critical, other than being logged */
grub_print_error (); grub_print_error ();
} }

1503
grub-core/commands/blsuki.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -129,6 +129,7 @@ grub_cmd_lsefi (grub_command_t cmd __attribute__ ((unused)),
} }
grub_free (handles);
return 0; return 0;
} }

View File

@ -47,6 +47,7 @@ static const struct guid_mapping guid_mappings[] =
{ GRUB_EFI_HOB_LIST_GUID, "HOB LIST"}, { GRUB_EFI_HOB_LIST_GUID, "HOB LIST"},
{ GRUB_EFI_IMAGE_SECURITY_DATABASE_GUID, "IMAGE EXECUTION INFORMATION"}, { GRUB_EFI_IMAGE_SECURITY_DATABASE_GUID, "IMAGE EXECUTION INFORMATION"},
{ GRUB_EFI_LZMA_CUSTOM_DECOMPRESS_GUID, "LZMA CUSTOM DECOMPRESS"}, { GRUB_EFI_LZMA_CUSTOM_DECOMPRESS_GUID, "LZMA CUSTOM DECOMPRESS"},
{ GRUB_EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMORY ATTRIBUTES TABLE"},
{ GRUB_EFI_MEMORY_TYPE_INFORMATION_GUID, "MEMORY TYPE INFO"}, { GRUB_EFI_MEMORY_TYPE_INFORMATION_GUID, "MEMORY TYPE INFO"},
{ GRUB_EFI_MPS_TABLE_GUID, "MPS"}, { GRUB_EFI_MPS_TABLE_GUID, "MPS"},
{ GRUB_EFI_RT_PROPERTIES_TABLE_GUID, "RT PROPERTIES"}, { GRUB_EFI_RT_PROPERTIES_TABLE_GUID, "RT PROPERTIES"},
@ -54,6 +55,7 @@ static const struct guid_mapping guid_mappings[] =
{ GRUB_EFI_SMBIOS_TABLE_GUID, "SMBIOS"}, { GRUB_EFI_SMBIOS_TABLE_GUID, "SMBIOS"},
{ GRUB_EFI_SMBIOS3_TABLE_GUID, "SMBIOS3"}, { GRUB_EFI_SMBIOS3_TABLE_GUID, "SMBIOS3"},
{ GRUB_EFI_SYSTEM_RESOURCE_TABLE_GUID, "SYSTEM RESOURCE TABLE"}, { GRUB_EFI_SYSTEM_RESOURCE_TABLE_GUID, "SYSTEM RESOURCE TABLE"},
{ GRUB_EFI_TCG2_FINAL_EVENTS_TABLE_GUID, "TCG2 FINAL EVENTS TABLE"},
{ GRUB_EFI_TIANO_CUSTOM_DECOMPRESS_GUID, "TIANO CUSTOM DECOMPRESS"}, { GRUB_EFI_TIANO_CUSTOM_DECOMPRESS_GUID, "TIANO CUSTOM DECOMPRESS"},
{ GRUB_EFI_TSC_FREQUENCY_GUID, "TSC FREQUENCY"}, { GRUB_EFI_TSC_FREQUENCY_GUID, "TSC FREQUENCY"},
}; };

View File

@ -39,6 +39,7 @@ static grub_uint8_t grub_tpm_version;
static grub_int8_t tpm1_present = -1; static grub_int8_t tpm1_present = -1;
static grub_int8_t tpm2_present = -1; static grub_int8_t tpm2_present = -1;
static grub_efi_int64_t tpm2_active_pcr_banks = -1;
static grub_efi_boolean_t static grub_efi_boolean_t
grub_tpm1_present (grub_efi_tpm_protocol_t *tpm) grub_tpm1_present (grub_efi_tpm_protocol_t *tpm)
@ -112,6 +113,7 @@ grub_tpm_handle_find (grub_efi_handle_t *tpm_handle,
grub_tpm_version = 1; grub_tpm_version = 1;
*protocol_version = 1; *protocol_version = 1;
grub_dprintf ("tpm", "TPM handle Found, version: 1\n"); grub_dprintf ("tpm", "TPM handle Found, version: 1\n");
grub_free (handles);
return 1; return 1;
} }
@ -124,6 +126,7 @@ grub_tpm_handle_find (grub_efi_handle_t *tpm_handle,
grub_tpm_version = 2; grub_tpm_version = 2;
*protocol_version = 2; *protocol_version = 2;
grub_dprintf ("tpm", "TPM handle Found, version: 2\n"); grub_dprintf ("tpm", "TPM handle Found, version: 2\n");
grub_free (handles);
return 1; return 1;
} }
@ -332,3 +335,49 @@ grub_tpm_present (void)
return grub_tpm2_present (tpm); return grub_tpm2_present (tpm);
} }
} }
grub_uint32_t
grub_tpm2_active_pcr_banks (void)
{
EFI_TCG2_BOOT_SERVICE_CAPABILITY caps;
grub_efi_handle_t tpm_handle;
grub_efi_uint8_t protocol_version;
grub_efi_tpm2_protocol_t *tpm;
grub_efi_uint32_t active_pcr_banks;
grub_efi_status_t status;
if (tpm2_active_pcr_banks >= 0)
return (grub_uint32_t) tpm2_active_pcr_banks;
if (!grub_tpm_handle_find (&tpm_handle, &protocol_version))
return (grub_uint32_t) (tpm2_active_pcr_banks = 0);
if (protocol_version == 1)
return (grub_uint32_t) (tpm2_active_pcr_banks = 0); /* We report TPM2 status. */
tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid,
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (tpm == NULL)
{
grub_dprintf ("tpm", "Cannot open TPM2 protocol\n");
return (grub_uint32_t) (tpm2_active_pcr_banks = 0);
}
if (!grub_tpm2_present (tpm))
return (grub_uint32_t) (tpm2_active_pcr_banks = 0);
caps.Size = (grub_uint8_t) sizeof (caps);
status = tpm->get_capability (tpm, &caps);
if (status != GRUB_EFI_SUCCESS)
return (grub_uint32_t) (tpm2_active_pcr_banks = 0);
if (caps.StructureVersion.Major < 1 ||
(caps.StructureVersion.Major == 1 && caps.StructureVersion.Minor < 1))
/* There's a working TPM2 but without querying protocol, let userspace figure it out. */
return (grub_uint32_t) (tpm2_active_pcr_banks = GRUB_UINT_MAX);
status = tpm->get_active_pcr_banks (tpm, &active_pcr_banks);
if (status != GRUB_EFI_SUCCESS)
return (grub_uint32_t) (tpm2_active_pcr_banks = 0); /* Assume none available if the call fails. */
return (grub_uint32_t) (tpm2_active_pcr_banks = active_pcr_banks);
}

View File

@ -139,6 +139,9 @@ grub_register_extcmd_lockdown (const char *name, grub_extcmd_func_t func,
void void
grub_unregister_extcmd (grub_extcmd_t ext) grub_unregister_extcmd (grub_extcmd_t ext)
{ {
if (ext == NULL)
return;
grub_unregister_command (ext->cmd); grub_unregister_command (ext->cmd);
grub_free (ext); grub_free (ext);
} }

View File

@ -27,67 +27,20 @@
#include <grub/mm.h> #include <grub/mm.h>
#include <grub/misc.h> #include <grub/misc.h>
static int
ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex,
grub_uint32_t eventtype,
const char *description,
grub_size_t description_size,
void *buf, grub_size_t size)
{
struct tpm_2hash_ext_log
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_cell_t method;
grub_ieee1275_cell_t ihandle;
grub_ieee1275_cell_t size;
grub_ieee1275_cell_t buf;
grub_ieee1275_cell_t description_size;
grub_ieee1275_cell_t description;
grub_ieee1275_cell_t eventtype;
grub_ieee1275_cell_t pcrindex;
grub_ieee1275_cell_t catch_result;
grub_ieee1275_cell_t rc;
};
struct tpm_2hash_ext_log args;
INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 2);
args.method = (grub_ieee1275_cell_t) "2hash-ext-log";
args.ihandle = grub_ieee1275_tpm_ihandle;
args.pcrindex = pcrindex;
args.eventtype = eventtype;
args.description = (grub_ieee1275_cell_t) description;
args.description_size = description_size;
args.buf = (grub_ieee1275_cell_t) buf;
args.size = (grub_ieee1275_cell_t) size;
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
return -1;
/*
* catch_result is set if firmware does not support 2hash-ext-log
* rc is GRUB_IEEE1275_CELL_FALSE (0) on failure
*/
if ((args.catch_result) || args.rc == GRUB_IEEE1275_CELL_FALSE)
return -1;
return 0;
}
static grub_err_t static grub_err_t
tpm2_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, tpm2_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
const char *description) const char *description)
{ {
static int error_displayed = 0; static int error_displayed = 0;
int rc; grub_err_t err;
rc = ibmvtpm_2hash_ext_log (pcr, EV_IPL, err = grub_ieee1275_ibmvtpm_2hash_ext_log (pcr, EV_IPL,
description, grub_strlen(description) + 1, description, grub_strlen(description) + 1,
buf, size); buf, size);
if (rc && !error_displayed) if (err != GRUB_ERR_NONE && !error_displayed)
{ {
error_displayed++; error_displayed++;
return grub_error (GRUB_ERR_BAD_DEVICE, return err;
"2HASH-EXT-LOG failed: Firmware is likely too old.\n");
} }
return GRUB_ERR_NONE; return GRUB_ERR_NONE;

View File

@ -143,7 +143,7 @@ legacy_file (const char *filename)
args[0] = oldname; args[0] = oldname;
grub_normal_add_menu_entry (1, args, NULL, NULL, "legacy", grub_normal_add_menu_entry (1, args, NULL, NULL, "legacy",
NULL, NULL, NULL, NULL,
entrysrc, 0); entrysrc, 0, NULL);
grub_free (args); grub_free (args);
entrysrc[0] = 0; entrysrc[0] = 0;
grub_free (oldname); grub_free (oldname);
@ -204,7 +204,7 @@ legacy_file (const char *filename)
} }
args[0] = entryname; args[0] = entryname;
grub_normal_add_menu_entry (1, args, NULL, NULL, NULL, grub_normal_add_menu_entry (1, args, NULL, NULL, NULL,
NULL, NULL, entrysrc, 0); NULL, NULL, entrysrc, 0, NULL);
grub_free (args); grub_free (args);
} }

View File

@ -53,6 +53,18 @@ grub_cmd_lsfreemem (grub_command_t cmd __attribute__ ((unused)),
return 0; return 0;
} }
static grub_err_t
grub_cmd_lsmemregions (grub_command_t cmd __attribute__ ((unused)),
int argc __attribute__ ((unused)),
char **args __attribute__ ((unused)))
{
#ifndef GRUB_MACHINE_EMU
grub_mm_dump_regions ();
#endif
return 0;
}
static grub_err_t static grub_err_t
grub_cmd_stress_big_allocs (grub_command_t cmd __attribute__ ((unused)), grub_cmd_stress_big_allocs (grub_command_t cmd __attribute__ ((unused)),
@ -132,7 +144,7 @@ grub_cmd_stress_big_allocs (grub_command_t cmd __attribute__ ((unused)),
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
static grub_command_t cmd_lsmem, cmd_lsfreemem, cmd_sba; static grub_command_t cmd_lsmem, cmd_lsfreemem, cmd_lsmemregions, cmd_sba;
GRUB_MOD_INIT (memtools) GRUB_MOD_INIT (memtools)
{ {
@ -140,6 +152,8 @@ GRUB_MOD_INIT (memtools)
0, N_("List free and allocated memory blocks.")); 0, N_("List free and allocated memory blocks."));
cmd_lsfreemem = grub_register_command ("lsfreemem", grub_cmd_lsfreemem, cmd_lsfreemem = grub_register_command ("lsfreemem", grub_cmd_lsfreemem,
0, N_("List free memory blocks.")); 0, N_("List free memory blocks."));
cmd_lsmemregions = grub_register_command ("lsmemregions", grub_cmd_lsmemregions,
0, N_("List memory regions."));
cmd_sba = grub_register_command ("stress_big_allocs", grub_cmd_stress_big_allocs, cmd_sba = grub_register_command ("stress_big_allocs", grub_cmd_stress_big_allocs,
0, N_("Stress test large allocations.")); 0, N_("Stress test large allocations."));
} }
@ -148,5 +162,6 @@ GRUB_MOD_FINI (memtools)
{ {
grub_unregister_command (cmd_lsmem); grub_unregister_command (cmd_lsmem);
grub_unregister_command (cmd_lsfreemem); grub_unregister_command (cmd_lsfreemem);
grub_unregister_command (cmd_lsmemregions);
grub_unregister_command (cmd_sba); grub_unregister_command (cmd_sba);
} }

View File

@ -78,7 +78,7 @@ grub_normal_add_menu_entry (int argc, const char **args,
char **classes, const char *id, char **classes, const char *id,
const char *users, const char *hotkey, const char *users, const char *hotkey,
const char *prefix, const char *sourcecode, const char *prefix, const char *sourcecode,
int submenu) int submenu, grub_blsuki_entry_t *blsuki)
{ {
int menu_hotkey = 0; int menu_hotkey = 0;
char **menu_args = NULL; char **menu_args = NULL;
@ -188,6 +188,7 @@ grub_normal_add_menu_entry (int argc, const char **args,
(*last)->args = menu_args; (*last)->args = menu_args;
(*last)->sourcecode = menu_sourcecode; (*last)->sourcecode = menu_sourcecode;
(*last)->submenu = submenu; (*last)->submenu = submenu;
(*last)->blsuki = blsuki;
menu->size++; menu->size++;
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
@ -265,6 +266,9 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
if (! argc) if (! argc)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing arguments"); return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing arguments");
if (! grub_strlen (args[argc - 1]))
return grub_error (GRUB_ERR_BAD_ARGUMENT, "menuentry title is missing");
if (ctxt->state[3].set && ctxt->script) if (ctxt->state[3].set && ctxt->script)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "multiple menuentry definitions"); return grub_error (GRUB_ERR_BAD_ARGUMENT, "multiple menuentry definitions");
@ -286,7 +290,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
users, users,
ctxt->state[2].arg, 0, ctxt->state[2].arg, 0,
ctxt->state[3].arg, ctxt->state[3].arg,
ctxt->extcmd->cmd->name[0] == 's'); ctxt->extcmd->cmd->name[0] == 's',
NULL);
src = args[argc - 1]; src = args[argc - 1];
args[argc - 1] = NULL; args[argc - 1] = NULL;
@ -303,7 +308,7 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
ctxt->state[0].args, ctxt->state[4].arg, ctxt->state[0].args, ctxt->state[4].arg,
users, users,
ctxt->state[2].arg, prefix, src + 1, ctxt->state[2].arg, prefix, src + 1,
ctxt->extcmd->cmd->name[0] == 's'); ctxt->extcmd->cmd->name[0] == 's', NULL);
src[len - 1] = ch; src[len - 1] = ch;
args[argc - 1] = src; args[argc - 1] = src;

View File

@ -136,10 +136,6 @@ struct signature_v4_header
grub_uint16_t hashed_sub; grub_uint16_t hashed_sub;
} GRUB_PACKED; } GRUB_PACKED;
struct gcry_pk_spec *grub_crypto_pk_dsa;
struct gcry_pk_spec *grub_crypto_pk_ecdsa;
struct gcry_pk_spec *grub_crypto_pk_rsa;
struct struct
{ {
const char *name; const char *name;
@ -924,7 +920,7 @@ GRUB_MOD_INIT(pgp)
grub_memset (&pseudo_file, 0, sizeof (pseudo_file)); grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
/* Not an ELF module, skip. */ /* Not an ELF module, skip. */
if (header->type != OBJ_TYPE_PUBKEY) if (header->type != OBJ_TYPE_GPG_PUBKEY)
continue; continue;
pseudo_file.fs = &pseudo_fs; pseudo_file.fs = &pseudo_fs;

View File

@ -403,7 +403,7 @@ test_parse (char **args, int *argn, int argc, int *depth)
if (++(*depth) > MAX_TEST_RECURSION_DEPTH) if (++(*depth) > MAX_TEST_RECURSION_DEPTH)
{ {
grub_error (GRUB_ERR_OUT_OF_RANGE, N_("max recursion depth exceeded")); grub_error (GRUB_ERR_OUT_OF_RANGE, N_("max recursion depth exceeded"));
depth--; (*depth)--;
return ctx.or || ctx.and; return ctx.or || ctx.and;
} }

View File

@ -28,6 +28,7 @@
#include <tss2_buffer.h> #include <tss2_buffer.h>
#include <tss2_types.h> #include <tss2_types.h>
#include <tss2_mu.h> #include <tss2_mu.h>
#include <tcg2.h>
#include "tpm2_args.h" #include "tpm2_args.h"
#include "tpm2.h" #include "tpm2.h"
@ -47,6 +48,7 @@ typedef enum tpm2_protector_options
OPTION_MODE, OPTION_MODE,
OPTION_PCRS, OPTION_PCRS,
OPTION_BANK, OPTION_BANK,
OPTION_CAPPCRS,
OPTION_TPM2KEY, OPTION_TPM2KEY,
OPTION_KEYFILE, OPTION_KEYFILE,
OPTION_SRK, OPTION_SRK,
@ -61,6 +63,8 @@ typedef struct tpm2_protector_context
grub_uint8_t pcr_count; grub_uint8_t pcr_count;
grub_srk_type_t srk_type; grub_srk_type_t srk_type;
TPM_ALG_ID_t bank; TPM_ALG_ID_t bank;
grub_uint8_t cap_pcrs[TPM_MAX_PCRS];
grub_uint8_t cap_pcr_count;
const char *tpm2key; const char *tpm2key;
const char *keyfile; const char *keyfile;
TPM_HANDLE_t srk; TPM_HANDLE_t srk;
@ -100,6 +104,16 @@ static const struct grub_arg_option tpm2_protector_init_cmd_options[] =
N_("Bank of PCRs used to authorize key release: " N_("Bank of PCRs used to authorize key release: "
"SHA1, SHA256, SHA384 or SHA512. (default: SHA256)"), "SHA1, SHA256, SHA384 or SHA512. (default: SHA256)"),
}, },
{
.longarg = "cap-pcrs",
.shortarg = 'c',
.flags = 0,
.arg = NULL,
.type = ARG_TYPE_STRING,
.doc =
N_("Comma-separated list of PCRs to be capped after key release "
"e.g., '7,11'."),
},
/* SRK-mode options */ /* SRK-mode options */
{ {
.longarg = "tpm2key", .longarg = "tpm2key",
@ -1212,19 +1226,45 @@ tpm2_protector_nv_recover (const tpm2_protector_context_t *ctx,
return err; return err;
} }
static grub_err_t
tpm2_protector_cap_pcrs (const tpm2_protector_context_t *ctx)
{
grub_uint8_t i;
grub_err_t err;
for (i = 0; i < ctx->cap_pcr_count; i++)
{
err = grub_tcg2_cap_pcr (ctx->cap_pcrs[i]);
if (err != GRUB_ERR_NONE)
return err;
}
return GRUB_ERR_NONE;
}
static grub_err_t static grub_err_t
tpm2_protector_recover (const tpm2_protector_context_t *ctx, tpm2_protector_recover (const tpm2_protector_context_t *ctx,
grub_uint8_t **key, grub_size_t *key_size) grub_uint8_t **key, grub_size_t *key_size)
{ {
grub_err_t err;
switch (ctx->mode) switch (ctx->mode)
{ {
case TPM2_PROTECTOR_MODE_SRK: case TPM2_PROTECTOR_MODE_SRK:
return tpm2_protector_srk_recover (ctx, key, key_size); err = tpm2_protector_srk_recover (ctx, key, key_size);
break;
case TPM2_PROTECTOR_MODE_NV: case TPM2_PROTECTOR_MODE_NV:
return tpm2_protector_nv_recover (ctx, key, key_size); err = tpm2_protector_nv_recover (ctx, key, key_size);
break;
default: default:
return GRUB_ERR_BAD_ARGUMENT; err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Unknown Mode"));
} }
/* Cap the selected PCRs when the key is unsealed successfully */
if (ctx->cap_pcr_count > 0 && err == GRUB_ERR_NONE)
err = tpm2_protector_cap_pcrs (ctx);
return err;
} }
static grub_err_t static grub_err_t
@ -1364,6 +1404,15 @@ tpm2_protector_init_cmd_handler (grub_extcmd_context_t ctxt, int argc,
return err; return err;
} }
if (state[OPTION_CAPPCRS].set) /* cap-pcrs */
{
err = grub_tpm2_protector_parse_pcrs (state[OPTION_CAPPCRS].arg,
tpm2_protector_ctx.cap_pcrs,
&tpm2_protector_ctx.cap_pcr_count);
if (err != GRUB_ERR_NONE)
return err;
}
if (state[OPTION_TPM2KEY].set) /* tpm2key */ if (state[OPTION_TPM2KEY].set) /* tpm2key */
{ {
err = tpm2_protector_parse_file (state[OPTION_TPM2KEY].arg, err = tpm2_protector_parse_file (state[OPTION_TPM2KEY].arg,
@ -1465,6 +1514,7 @@ GRUB_MOD_INIT (tpm2_key_protector)
N_("[-m mode] " N_("[-m mode] "
"[-p pcr_list] " "[-p pcr_list] "
"[-b pcr_bank] " "[-b pcr_bank] "
"[-c pcr_list] "
"[-T tpm2_key_file_path] " "[-T tpm2_key_file_path] "
"[-k sealed_key_file_path] " "[-k sealed_key_file_path] "
"[-s srk_handle] " "[-s srk_handle] "

View File

@ -90,7 +90,7 @@ grub_usb_get_string (grub_usb_device_t dev, grub_uint8_t index, int langid,
0x06, (3 << 8) | index, 0x06, (3 << 8) | index,
langid, descstr.length, (char *) descstrp); langid, descstr.length, (char *) descstrp);
if (descstrp->length == 0) if (descstrp->length < 2)
{ {
grub_free (descstrp); grub_free (descstrp);
*string = grub_strdup (""); *string = grub_strdup ("");
@ -99,7 +99,7 @@ grub_usb_get_string (grub_usb_device_t dev, grub_uint8_t index, int langid,
return GRUB_USB_ERR_NONE; return GRUB_USB_ERR_NONE;
} }
*string = grub_malloc (descstr.length * 2 + 1); *string = grub_malloc (descstrp->length * 2 + 1);
if (! *string) if (! *string)
{ {
grub_free (descstrp); grub_free (descstrp);

View File

@ -29,6 +29,7 @@
#include <grub/partition.h> #include <grub/partition.h>
#include <grub/key_protector.h> #include <grub/key_protector.h>
#include <grub/safemath.h> #include <grub/safemath.h>
#include <grub/hwfeatures-gcry.h>
#ifdef GRUB_UTIL #ifdef GRUB_UTIL
#include <grub/emu/hostdisk.h> #include <grub/emu/hostdisk.h>
@ -48,7 +49,8 @@ enum
OPTION_KEYFILE_OFFSET, OPTION_KEYFILE_OFFSET,
OPTION_KEYFILE_SIZE, OPTION_KEYFILE_SIZE,
OPTION_HEADER, OPTION_HEADER,
OPTION_PROTECTOR OPTION_PROTECTOR,
OPTION_HWACCEL
}; };
static const struct grub_arg_option options[] = static const struct grub_arg_option options[] =
@ -64,6 +66,7 @@ static const struct grub_arg_option options[] =
{"header", 'H', 0, N_("Read header from file"), 0, ARG_TYPE_STRING}, {"header", 'H', 0, N_("Read header from file"), 0, ARG_TYPE_STRING},
{"protector", 'P', GRUB_ARG_OPTION_REPEATABLE, {"protector", 'P', GRUB_ARG_OPTION_REPEATABLE,
N_("Unlock volume(s) using key protector(s)."), 0, ARG_TYPE_STRING}, N_("Unlock volume(s) using key protector(s)."), 0, ARG_TYPE_STRING},
{"hw-accel", 'A', 0, N_("Enable hardware acceleration."), 0, 0},
{0, 0, 0, 0, 0, 0} {0, 0, 0, 0, 0, 0}
}; };
@ -1420,7 +1423,7 @@ grub_cryptodisk_clear_key_cache (struct grub_cryptomount_args *cargs)
} }
static grub_err_t static grub_err_t
grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) __grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
{ {
struct grub_arg_list *state = ctxt->state; struct grub_arg_list *state = ctxt->state;
struct grub_cryptomount_args cargs = {0}; struct grub_cryptomount_args cargs = {0};
@ -1629,6 +1632,23 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
} }
} }
static grub_err_t
grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = ctxt->state;
grub_err_t err;
if (state[OPTION_HWACCEL].set)
grub_enable_gcry_hwf ();
err = __grub_cmd_cryptomount (ctxt, argc, args);
if (state[OPTION_HWACCEL].set)
grub_reset_gcry_hwf ();
return err;
}
static struct grub_disk_dev grub_cryptodisk_dev = { static struct grub_disk_dev grub_cryptodisk_dev = {
.name = "cryptodisk", .name = "cryptodisk",
.id = GRUB_DISK_DEVICE_CRYPTODISK_ID, .id = GRUB_DISK_DEVICE_CRYPTODISK_ID,
@ -1898,7 +1918,7 @@ GRUB_MOD_INIT (cryptodisk)
cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0, cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0,
N_("[ [-p password] | [-k keyfile" N_("[ [-p password] | [-k keyfile"
" [-O keyoffset] [-S keysize] ] ] [-H file]" " [-O keyoffset] [-S keysize] ] ] [-H file]"
" [-P protector [-P protector ...]]" " [-P protector [-P protector ...]] | [-A]"
" <SOURCE|-u UUID|-a|-b>"), " <SOURCE|-u UUID|-a|-b>"),
N_("Mount a crypto device."), options); N_("Mount a crypto device."), options);
grub_procfs_register ("luks_script", &luks_script); grub_procfs_register ("luks_script", &luks_script);

View File

@ -464,9 +464,7 @@ geli_recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_ar
grub_crypto_hmac_write (hnd, header.salt, sizeof (header.salt)); grub_crypto_hmac_write (hnd, header.salt, sizeof (header.salt));
grub_crypto_hmac_write (hnd, cargs->key_data, cargs->key_len); grub_crypto_hmac_write (hnd, cargs->key_data, cargs->key_len);
gcry_err = grub_crypto_hmac_fini (hnd, geomkey); grub_crypto_hmac_fini (hnd, geomkey);
if (gcry_err)
return grub_crypto_gcry_error (gcry_err);
} }
gcry_err = grub_crypto_hmac_buffer (dev->hash, geomkey, gcry_err = grub_crypto_hmac_buffer (dev->hash, geomkey,

View File

@ -93,6 +93,7 @@ ofdisk_hash_add_real (char *devpath)
grub_add (sz, sizeof ("ieee1275/"), &sz)) grub_add (sz, sizeof ("ieee1275/"), &sz))
{ {
grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of device path")); grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of device path"));
grub_free (p);
return NULL; return NULL;
} }
@ -109,6 +110,8 @@ ofdisk_hash_add_real (char *devpath)
if (grub_add (grub_strlen (p->devpath), 3, &sz)) if (grub_add (grub_strlen (p->devpath), 3, &sz))
{ {
grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of an open path")); grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of an open path"));
grub_free (p->grub_devpath);
grub_free (p);
return NULL; return NULL;
} }

View File

@ -39,6 +39,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
enum grub_luks2_kdf_type enum grub_luks2_kdf_type
{ {
LUKS2_KDF_TYPE_ARGON2I, LUKS2_KDF_TYPE_ARGON2I,
LUKS2_KDF_TYPE_ARGON2ID,
LUKS2_KDF_TYPE_PBKDF2 LUKS2_KDF_TYPE_PBKDF2
}; };
typedef enum grub_luks2_kdf_type grub_luks2_kdf_type_t; typedef enum grub_luks2_kdf_type grub_luks2_kdf_type_t;
@ -159,13 +160,21 @@ luks2_parse_keyslot (grub_luks2_keyslot_t *out, const grub_json_t *keyslot)
grub_json_getstring (&type, &kdf, "type") || grub_json_getstring (&type, &kdf, "type") ||
grub_json_getstring (&out->kdf.salt, &kdf, "salt")) grub_json_getstring (&out->kdf.salt, &kdf, "salt"))
return grub_error (GRUB_ERR_BAD_ARGUMENT, "Missing or invalid KDF"); return grub_error (GRUB_ERR_BAD_ARGUMENT, "Missing or invalid KDF");
else if (!grub_strcmp (type, "argon2i") || !grub_strcmp (type, "argon2id")) else if (!grub_strcmp (type, "argon2i"))
{ {
out->kdf.type = LUKS2_KDF_TYPE_ARGON2I; out->kdf.type = LUKS2_KDF_TYPE_ARGON2I;
if (grub_json_getint64 (&out->kdf.u.argon2i.time, &kdf, "time") || if (grub_json_getint64 (&out->kdf.u.argon2i.time, &kdf, "time") ||
grub_json_getint64 (&out->kdf.u.argon2i.memory, &kdf, "memory") || grub_json_getint64 (&out->kdf.u.argon2i.memory, &kdf, "memory") ||
grub_json_getint64 (&out->kdf.u.argon2i.cpus, &kdf, "cpus")) grub_json_getint64 (&out->kdf.u.argon2i.cpus, &kdf, "cpus"))
return grub_error (GRUB_ERR_BAD_ARGUMENT, "Missing Argon2i parameters"); return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing Argon2i parameters");
}
else if (!grub_strcmp (type, "argon2id"))
{
out->kdf.type = LUKS2_KDF_TYPE_ARGON2ID;
if (grub_json_getint64 (&out->kdf.u.argon2i.time, &kdf, "time") ||
grub_json_getint64 (&out->kdf.u.argon2i.memory, &kdf, "memory") ||
grub_json_getint64 (&out->kdf.u.argon2i.cpus, &kdf, "cpus"))
return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing Argon2id parameters");
} }
else if (!grub_strcmp (type, "pbkdf2")) else if (!grub_strcmp (type, "pbkdf2"))
{ {
@ -444,6 +453,8 @@ luks2_decrypt_key (grub_uint8_t *out_key,
grub_uint8_t salt[GRUB_CRYPTODISK_MAX_KEYLEN]; grub_uint8_t salt[GRUB_CRYPTODISK_MAX_KEYLEN];
grub_uint8_t *split_key = NULL; grub_uint8_t *split_key = NULL;
idx_t saltlen = sizeof (salt); idx_t saltlen = sizeof (salt);
int subalgo;
unsigned long param[4];
char cipher[32], *p; char cipher[32], *p;
const gcry_md_spec_t *hash; const gcry_md_spec_t *hash;
gcry_err_code_t gcry_ret; gcry_err_code_t gcry_ret;
@ -460,8 +471,29 @@ luks2_decrypt_key (grub_uint8_t *out_key,
switch (k->kdf.type) switch (k->kdf.type)
{ {
case LUKS2_KDF_TYPE_ARGON2I: case LUKS2_KDF_TYPE_ARGON2I:
ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Argon2 not supported"); case LUKS2_KDF_TYPE_ARGON2ID:
if (k->kdf.type == LUKS2_KDF_TYPE_ARGON2I)
subalgo = GRUB_GCRY_KDF_ARGON2I;
else
subalgo = GRUB_GCRY_KDF_ARGON2ID;
param[0] = k->area.key_size;
param[1] = k->kdf.u.argon2i.time;
param[2] = k->kdf.u.argon2i.memory;
param[3] = k->kdf.u.argon2i.cpus;
gcry_ret = grub_crypto_argon2 (subalgo, param, 4,
passphrase, passphraselen,
salt, saltlen,
NULL, 0, NULL, 0,
k->area.key_size, area_key);
if (gcry_ret)
{
ret = grub_crypto_gcry_error (gcry_ret);
goto err; goto err;
}
break;
case LUKS2_KDF_TYPE_PBKDF2: case LUKS2_KDF_TYPE_PBKDF2:
hash = grub_crypto_lookup_md_by_name (k->kdf.u.pbkdf2.hash); hash = grub_crypto_lookup_md_by_name (k->kdf.u.pbkdf2.hash);
if (!hash) if (!hash)

View File

@ -203,6 +203,9 @@ grub_efiemu_count_symbols (const Elf_Ehdr *e)
grub_efiemu_elfsyms = (struct grub_efiemu_elf_sym *) grub_efiemu_elfsyms = (struct grub_efiemu_elf_sym *)
grub_calloc (grub_efiemu_nelfsyms, sizeof (struct grub_efiemu_elf_sym)); grub_calloc (grub_efiemu_nelfsyms, sizeof (struct grub_efiemu_elf_sym));
if (grub_efiemu_elfsyms == NULL)
return grub_errno;
/* Relocators */ /* Relocators */
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum; i < e->e_shnum;

View File

@ -2334,14 +2334,20 @@ struct embed_region {
}; };
/* /*
* https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs(5)#BOOTLOADER_SUPPORT * https://btrfs.readthedocs.io/en/latest/btrfs-man5.html#man-btrfs5-bootloader-support
* or invoke "man 5 btrfs" and visit the "BOOTLOADER SUPPORT" subsection.
* The first 1 MiB on each device is unused with the exception of primary * The first 1 MiB on each device is unused with the exception of primary
* superblock that is on the offset 64 KiB and spans 4 KiB. * superblock that is on the offset 64 KiB and spans 4 KiB.
*
* Note: If this table is modified, also update
* util/grub-editenv.c::fs_envblk_spec, which describes the file-system
* specific layout of reserved raw blocks used as environment blocks so that
* both stay consistent.
*/ */
static const struct { static const struct {
struct embed_region available; struct embed_region available;
struct embed_region used[6]; struct embed_region used[9];
} btrfs_head = { } btrfs_head = {
.available = {0, GRUB_DISK_KiB_TO_SECTORS (1024)}, /* The first 1 MiB. */ .available = {0, GRUB_DISK_KiB_TO_SECTORS (1024)}, /* The first 1 MiB. */
.used = { .used = {
@ -2349,6 +2355,9 @@ static const struct {
{GRUB_DISK_KiB_TO_SECTORS (64) - 1, 1}, /* Overflow guard. */ {GRUB_DISK_KiB_TO_SECTORS (64) - 1, 1}, /* Overflow guard. */
{GRUB_DISK_KiB_TO_SECTORS (64), GRUB_DISK_KiB_TO_SECTORS (4)}, /* 4 KiB superblock. */ {GRUB_DISK_KiB_TO_SECTORS (64), GRUB_DISK_KiB_TO_SECTORS (4)}, /* 4 KiB superblock. */
{GRUB_DISK_KiB_TO_SECTORS (68), 1}, /* Overflow guard. */ {GRUB_DISK_KiB_TO_SECTORS (68), 1}, /* Overflow guard. */
{(GRUB_ENV_BTRFS_OFFSET >> GRUB_DISK_SECTOR_BITS) - 1, 1}, /* Overflow guard. */
{(GRUB_ENV_BTRFS_OFFSET >> GRUB_DISK_SECTOR_BITS), 1}, /* Environment Block. */
{(GRUB_ENV_BTRFS_OFFSET >> GRUB_DISK_SECTOR_BITS) + 1, 1}, /* Overflow guard. */
{GRUB_DISK_KiB_TO_SECTORS (1024) - 1, 1}, /* Overflow guard. */ {GRUB_DISK_KiB_TO_SECTORS (1024) - 1, 1}, /* Overflow guard. */
{0, 0} /* Array terminator. */ {0, 0} /* Array terminator. */
} }

View File

@ -736,7 +736,9 @@ list_nodes (void *record, void *hook_arg)
int mode = (grub_be_to_cpu16 (fileinfo->mode) int mode = (grub_be_to_cpu16 (fileinfo->mode)
& GRUB_HFSPLUS_FILEMODE_MASK); & GRUB_HFSPLUS_FILEMODE_MASK);
if (mode == GRUB_HFSPLUS_FILEMODE_REG) if (mode == 0) /* Created by pre-Mac OS X. */
type = GRUB_FSHELP_REG;
else if (mode == GRUB_HFSPLUS_FILEMODE_REG)
type = GRUB_FSHELP_REG; type = GRUB_FSHELP_REG;
else if (mode == GRUB_HFSPLUS_FILEMODE_SYMLINK) else if (mode == GRUB_HFSPLUS_FILEMODE_SYMLINK)
type = GRUB_FSHELP_SYMLINK; type = GRUB_FSHELP_SYMLINK;

View File

@ -233,7 +233,12 @@ next_attribute (grub_uint8_t *curr_attribute, void *end, bool validate)
return NULL; return NULL;
next += u16at (curr_attribute, 4); next += u16at (curr_attribute, 4);
if (validate && validate_attribute (next, end) == false) if (validate)
{
if (validate_attribute (next, end) == false)
return NULL;
}
else if (next >= (grub_uint8_t *) end)
return NULL; return NULL;
return next; return next;

View File

@ -2743,7 +2743,7 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type,
grub_uint64_t blkid, blksz; /* the block id this object dnode is in */ grub_uint64_t blkid, blksz; /* the block id this object dnode is in */
int epbs; /* shift of number of dnodes in a block */ int epbs; /* shift of number of dnodes in a block */
int idx; /* index within a block */ int idx; /* index within a block */
void *dnbuf; dnode_phys_t *dnbuf;
grub_err_t err; grub_err_t err;
grub_zfs_endian_t endian; grub_zfs_endian_t endian;
@ -2773,7 +2773,7 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type,
grub_dprintf ("zfs", "endian = %d, blkid=%llx\n", mdn->endian, grub_dprintf ("zfs", "endian = %d, blkid=%llx\n", mdn->endian,
(unsigned long long) blkid); (unsigned long long) blkid);
err = dmu_read (mdn, blkid, &dnbuf, &endian, data); err = dmu_read (mdn, blkid, (void **) &dnbuf, &endian, data);
if (err) if (err)
return err; return err;
grub_dprintf ("zfs", "alive\n"); grub_dprintf ("zfs", "alive\n");
@ -2795,7 +2795,7 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type,
data->dnode_endian = endian; data->dnode_endian = endian;
} }
grub_memmove (&(buf->dn), (dnode_phys_t *) dnbuf + idx, DNODE_SIZE); grub_memmove (&(buf->dn), dnbuf + idx, DNODE_SIZE);
if (data->dnode_buf == 0) if (data->dnode_buf == 0)
/* dnbuf not used anymore if data->dnode_mdn malloc failed */ /* dnbuf not used anymore if data->dnode_mdn malloc failed */
grub_free (dnbuf); grub_free (dnbuf);

View File

@ -502,6 +502,8 @@ grub_cmd_translate (grub_command_t cmd __attribute__ ((unused)),
return 0; return 0;
} }
static grub_command_t cmd;
GRUB_MOD_INIT (gettext) GRUB_MOD_INIT (gettext)
{ {
const char *lang; const char *lang;
@ -521,11 +523,12 @@ GRUB_MOD_INIT (gettext)
grub_register_variable_hook ("locale_dir", NULL, read_main); grub_register_variable_hook ("locale_dir", NULL, read_main);
grub_register_variable_hook ("secondary_locale_dir", NULL, read_secondary); grub_register_variable_hook ("secondary_locale_dir", NULL, read_secondary);
grub_register_command_p1 ("gettext", grub_cmd_translate, cmd = grub_register_command_p1 ("gettext", grub_cmd_translate,
N_("STRING"), N_("STRING"),
/* TRANSLATORS: It refers to passing the string through gettext. /*
So it's "translate" in the same meaning as in what you're * TRANSLATORS: It refers to passing the string through gettext.
doing now. * So it's "translate" in the same meaning as in what you're
* doing now.
*/ */
N_("Translates the string with the current settings.")); N_("Translates the string with the current settings."));
@ -544,6 +547,8 @@ GRUB_MOD_FINI (gettext)
grub_register_variable_hook ("secondary_locale_dir", NULL, NULL); grub_register_variable_hook ("secondary_locale_dir", NULL, NULL);
grub_register_variable_hook ("lang", NULL, NULL); grub_register_variable_hook ("lang", NULL, NULL);
grub_unregister_command (cmd);
grub_gettext_delete_list (&main_context); grub_gettext_delete_list (&main_context);
grub_gettext_delete_list (&secondary_context); grub_gettext_delete_list (&secondary_context);

251
grub-core/io/zstdio.c Normal file
View File

@ -0,0 +1,251 @@
/* zstdio.c - decompression support for zstd */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2025 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 <grub/err.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/file.h>
#include <grub/fs.h>
#include <grub/dl.h>
GRUB_MOD_LICENSE ("GPLv3+");
#include "zstd.h"
#define STREAM_HEADER_SIZE 16
struct zstdio
{
grub_file_t file;
ZSTD_DCtx *dctx;
grub_size_t insize;
grub_size_t outsize;
ZSTD_outBuffer output;
ZSTD_inBuffer input;
grub_off_t saved_offset;
grub_uint8_t bufs[];
};
typedef struct zstdio *zstdio_t;
static struct grub_fs zstdio_fs;
static bool
test_header (grub_file_t file)
{
zstdio_t zstdio = file->data;
size_t zret;
zstdio->input.pos = 0;
zstdio->output.pos = 0;
zstdio->output.size = zstdio->outsize;
zstdio->input.size = grub_file_read (zstdio->file, zstdio->bufs,
STREAM_HEADER_SIZE);
if (zstdio->input.size != STREAM_HEADER_SIZE)
return false;
zret = ZSTD_decompressStream (zstdio->dctx, &zstdio->output, &zstdio->input);
if (ZSTD_isError (zret))
return false;
return true;
}
static grub_file_t
grub_zstdio_open (grub_file_t io, enum grub_file_type type)
{
grub_file_t file;
zstdio_t zstdio;
if (type & GRUB_FILE_TYPE_NO_DECOMPRESS)
return io;
file = (grub_file_t) grub_zalloc (sizeof (*file));
if (file == NULL)
return NULL;
zstdio = grub_zalloc (sizeof (zstdio_t) + ZSTD_DStreamInSize () +
ZSTD_DStreamOutSize ());
if (zstdio == NULL)
{
grub_free (file);
return NULL;
}
zstdio->file = io;
zstdio->insize = ZSTD_DStreamInSize ();
zstdio->outsize = ZSTD_DStreamOutSize ();
zstdio->input.src = zstdio->bufs;
zstdio->output.dst = &zstdio->bufs[zstdio->insize];
file->device = io->device;
file->data = zstdio;
file->fs = &zstdio_fs;
file->size = GRUB_FILE_SIZE_UNKNOWN;
file->not_easily_seekable = 1;
if (grub_file_tell (zstdio->file) != 0)
if (grub_file_seek (zstdio->file, 0) == (grub_off_t) -1)
{
grub_free (file);
grub_free (zstdio);
return NULL;
}
zstdio->dctx = ZSTD_createDCtx ();
if (zstdio->dctx == NULL)
{
grub_free (file);
grub_free (zstdio);
return NULL;
}
if (test_header (file) == false)
{
grub_errno = GRUB_ERR_NONE;
if (grub_file_seek (io, 0) == (grub_off_t) -1)
{
grub_free (file);
grub_free (zstdio);
return NULL;
}
ZSTD_freeDCtx (zstdio->dctx);
grub_free (zstdio);
grub_free (file);
return io;
}
return file;
}
static grub_ssize_t
grub_zstdio_read (grub_file_t file, char *buf, grub_size_t len)
{
zstdio_t zstdio = file->data;
grub_ssize_t ret = 0;
grub_ssize_t readret;
grub_off_t current_offset;
grub_off_t new_offset;
grub_size_t delta;
grub_size_t zret;
/* If seek backward need to reset decoder and start from beginning of file. */
if (file->offset < zstdio->saved_offset)
{
ZSTD_initDStream (zstdio->dctx);
zstdio->input.pos = 0;
zstdio->input.size = 0;
zstdio->output.pos = 0;
zstdio->saved_offset = 0;
grub_file_seek (zstdio->file, 0);
}
current_offset = zstdio->saved_offset;
while (len > 0)
{
zstdio->output.size = file->offset + ret + len - current_offset;
if (zstdio->output.size > zstdio->outsize)
zstdio->output.size = zstdio->outsize;
if (zstdio->input.pos == zstdio->input.size)
{
readret = grub_file_read (zstdio->file, zstdio->bufs,
zstdio->insize);
if (readret < 0)
return -1;
zstdio->input.size = readret;
zstdio->input.pos = 0;
}
zret = ZSTD_decompressStream (zstdio->dctx, &zstdio->output,
&zstdio->input);
if (ZSTD_isError (zret))
{
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
N_("zstd file corrupted or unsupported block options"));
return -1;
}
new_offset = current_offset + zstdio->output.pos;
/* Store first chunk of data in buffer. */
if (file->offset <= new_offset)
{
delta = new_offset - (file->offset + ret);
grub_memmove (buf, (grub_uint8_t *) zstdio->output.dst +
(zstdio->output.pos - delta),
delta);
len -= delta;
buf += delta;
ret += delta;
}
current_offset = new_offset;
zstdio->output.pos = 0;
if (zstdio->input.pos == 0 && zstdio->output.pos == 0)
break;
}
if (ret >= 0)
zstdio->saved_offset = file->offset + ret;
return ret;
}
/* Release everything, including the underlying file object. */
static grub_err_t
grub_zstdio_close (grub_file_t file)
{
zstdio_t zstdio = file->data;
ZSTD_freeDCtx (zstdio->dctx);
grub_file_close (zstdio->file);
grub_free (zstdio);
/* Device must not be closed twice. */
file->device = 0;
file->name = 0;
return grub_errno;
}
static struct grub_fs zstdio_fs = {
.name = "zstdio",
.fs_dir = 0,
.fs_open = 0,
.fs_read = grub_zstdio_read,
.fs_close = grub_zstdio_close,
.fs_label = 0,
.next = 0
};
GRUB_MOD_INIT (zstdio)
{
grub_file_filter_register (GRUB_FILE_FILTER_ZSTDIO, grub_zstdio_open);
}
GRUB_MOD_FINI (zstdio)
{
grub_file_filter_unregister (GRUB_FILE_FILTER_ZSTDIO);
}

View File

@ -104,6 +104,9 @@ grub_register_command_lockdown (const char *name,
void void
grub_unregister_command (grub_command_t cmd) grub_unregister_command (grub_command_t cmd)
{ {
if (cmd == NULL)
return;
if ((cmd->prio & GRUB_COMMAND_FLAG_ACTIVE) && (cmd->next)) if ((cmd->prio & GRUB_COMMAND_FLAG_ACTIVE) && (cmd->next))
cmd->next->prio |= GRUB_COMMAND_FLAG_ACTIVE; cmd->next->prio |= GRUB_COMMAND_FLAG_ACTIVE;
grub_list_remove (GRUB_AS_LIST (cmd)); grub_list_remove (GRUB_AS_LIST (cmd));

View File

@ -24,7 +24,7 @@
void * GRUB_BUILTIN_ATTR void * GRUB_BUILTIN_ATTR
memcpy (void *dest, const void *src, grub_size_t n) memcpy (void *dest, const void *src, grub_size_t n)
{ {
return grub_memmove (dest, src, n); return grub_memcpy (dest, src, n);
} }
void * GRUB_BUILTIN_ATTR void * GRUB_BUILTIN_ATTR
memmove (void *dest, const void *src, grub_size_t n) memmove (void *dest, const void *src, grub_size_t n)
@ -372,11 +372,11 @@ grub_int32_t
__aeabi_idiv (grub_int32_t a, grub_int32_t b) __aeabi_idiv (grub_int32_t a, grub_int32_t b)
__attribute__ ((alias ("__divsi3"))); __attribute__ ((alias ("__divsi3")));
void *__aeabi_memcpy (void *dest, const void *src, grub_size_t n) void *__aeabi_memcpy (void *dest, const void *src, grub_size_t n)
__attribute__ ((alias ("grub_memcpy"))); __attribute__ ((alias ("memcpy")));
void *__aeabi_memcpy4 (void *dest, const void *src, grub_size_t n) void *__aeabi_memcpy4 (void *dest, const void *src, grub_size_t n)
__attribute__ ((alias ("grub_memcpy"))); __attribute__ ((alias ("memcpy")));
void *__aeabi_memcpy8 (void *dest, const void *src, grub_size_t n) void *__aeabi_memcpy8 (void *dest, const void *src, grub_size_t n)
__attribute__ ((alias ("grub_memcpy"))); __attribute__ ((alias ("memcpy")));
void *__aeabi_memset (void *s, int c, grub_size_t n) void *__aeabi_memset (void *s, int c, grub_size_t n)
__attribute__ ((alias ("memset"))); __attribute__ ((alias ("memset")));

View File

@ -152,6 +152,8 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)),
case GRUB_FILE_TYPE_TESTLOAD: case GRUB_FILE_TYPE_TESTLOAD:
case GRUB_FILE_TYPE_GET_SIZE: case GRUB_FILE_TYPE_GET_SIZE:
case GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY: case GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY:
case GRUB_FILE_TYPE_CRYPTODISK_ENCRYPTION_KEY:
case GRUB_FILE_TYPE_CRYPTODISK_DETACHED_HEADER:
case GRUB_FILE_TYPE_CAT: case GRUB_FILE_TYPE_CAT:
case GRUB_FILE_TYPE_HEXCAT: case GRUB_FILE_TYPE_HEXCAT:
case GRUB_FILE_TYPE_CMP: case GRUB_FILE_TYPE_CMP:

View File

@ -33,15 +33,24 @@ static struct grub_error_saved grub_error_stack_items[GRUB_ERROR_STACK_SIZE];
static int grub_error_stack_pos; static int grub_error_stack_pos;
static int grub_error_stack_assert; static int grub_error_stack_assert;
#ifdef grub_error
#undef grub_error
#endif
grub_err_t grub_err_t
grub_error (grub_err_t n, const char *fmt, ...) grub_error (grub_err_t n, const char *file, const char *function, const int line, const char *fmt, ...)
{ {
va_list ap; va_list ap;
int m;
grub_errno = n; grub_errno = n;
m = grub_snprintf (grub_errmsg, sizeof (grub_errmsg), "%s:%s:%d:", file, function, line);
if (m < 0)
m = 0;
va_start (ap, fmt); va_start (ap, fmt);
grub_vsnprintf (grub_errmsg, sizeof (grub_errmsg), _(fmt), ap); grub_vsnprintf (grub_errmsg + m, sizeof (grub_errmsg) - m, _(fmt), ap);
va_end (ap); va_end (ap);
return n; return n;

View File

@ -201,12 +201,12 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len)
grub_err_t grub_err_t
grub_file_close (grub_file_t file) grub_file_close (grub_file_t file)
{ {
if (file->fs->mod)
grub_dl_unref (file->fs->mod);
if (file->fs->fs_close) if (file->fs->fs_close)
(file->fs->fs_close) (file); (file->fs->fs_close) (file);
if (file->fs->mod)
grub_dl_unref (file->fs->mod);
if (file->device) if (file->device)
grub_device_close (file->device); grub_device_close (file->device);
grub_free (file->name); grub_free (file->name);

View File

@ -352,6 +352,10 @@ grub_xen_setup_pvh (void)
grub_xen_mm_init_regions (); grub_xen_mm_init_regions ();
grub_rsdp_addr = pvh_start_info->rsdp_paddr; grub_rsdp_addr = pvh_start_info->rsdp_paddr;
grub_strncpy ((char *) grub_xen_start_page_addr->cmd_line,
(const char *)(grub_addr_t) pvh_start_info->cmdline_paddr,
GRUB_XEN_MAX_GUEST_CMDLINE);
} }
grub_err_t grub_err_t

View File

@ -23,7 +23,6 @@
#define IEEE1275_PHANDLE_INVALID ((grub_ieee1275_cell_t) -1) #define IEEE1275_PHANDLE_INVALID ((grub_ieee1275_cell_t) -1)
#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_cell_t) 0) #define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_cell_t) 0)
#define IEEE1275_CELL_INVALID ((grub_ieee1275_cell_t) -1)

View File

@ -49,6 +49,16 @@
#if defined(__powerpc__) || defined(__i386__) #if defined(__powerpc__) || defined(__i386__)
#include <grub/ieee1275/alloc.h> #include <grub/ieee1275/alloc.h>
#endif #endif
#if defined(__powerpc__)
#include <grub/lockdown.h>
#include <grub/powerpc/ieee1275/ieee1275.h>
#include <grub/powerpc/ieee1275/platform_keystore.h>
#endif
#ifdef __powerpc__
#define GRUB_SB_DISABLED ((grub_uint32_t) 0)
#define GRUB_SB_ENFORCE ((grub_uint32_t) 2)
#endif
/* The maximum heap size we're going to claim at boot. Not used by sparc. */ /* The maximum heap size we're going to claim at boot. Not used by sparc. */
#ifdef __i386__ #ifdef __i386__
@ -152,6 +162,8 @@ grub_machine_get_bootlocation (char **device, char **path)
char *bootpath; char *bootpath;
char *filename; char *filename;
char *type; char *type;
char *ret_device = NULL;
char *ret_path = NULL;
bootpath = grub_ieee1275_get_boot_dev (); bootpath = grub_ieee1275_get_boot_dev ();
if (! bootpath) if (! bootpath)
@ -167,7 +179,7 @@ grub_machine_get_bootlocation (char **device, char **path)
dev = grub_ieee1275_get_aliasdevname (bootpath); dev = grub_ieee1275_get_aliasdevname (bootpath);
canon = grub_ieee1275_canonicalise_devname (dev); canon = grub_ieee1275_canonicalise_devname (dev);
if (! canon) if (! canon)
return; goto done;
ptr = canon + grub_strlen (canon) - 1; ptr = canon + grub_strlen (canon) - 1;
while (ptr > canon && (*ptr == ',' || *ptr == ':')) while (ptr > canon && (*ptr == ',' || *ptr == ':'))
ptr--; ptr--;
@ -175,13 +187,17 @@ grub_machine_get_bootlocation (char **device, char **path)
*ptr = 0; *ptr = 0;
if (grub_ieee1275_net_config) if (grub_ieee1275_net_config)
grub_ieee1275_net_config (canon, device, path, bootpath); grub_ieee1275_net_config (canon, &ret_device, &ret_path, bootpath);
grub_free (dev); grub_free (dev);
grub_free (canon); grub_free (canon);
/* Use path from net config if it is provided by cached DHCP info */
if (ret_path != NULL)
goto done;
/* Fall through to use firmware bootpath */
} }
else else
*device = grub_ieee1275_encode_devname (bootpath); ret_device = grub_ieee1275_encode_devname (bootpath);
grub_free (type);
filename = grub_ieee1275_get_filename (bootpath); filename = grub_ieee1275_get_filename (bootpath);
if (filename) if (filename)
@ -194,10 +210,18 @@ grub_machine_get_bootlocation (char **device, char **path)
*lastslash = '\0'; *lastslash = '\0';
grub_translate_ieee1275_path (filename); grub_translate_ieee1275_path (filename);
*path = filename; ret_path = filename;
} }
} }
done:
grub_free (type);
grub_free (bootpath); grub_free (bootpath);
if (device != NULL)
*device = ret_device;
if (path != NULL)
*path = ret_path;
} }
/* Claim some available memory in the first /memory node. */ /* Claim some available memory in the first /memory node. */
@ -994,7 +1018,51 @@ grub_parse_cmdline (void)
} }
} }
} }
#ifdef __powerpc__
static void
grub_ieee1275_get_secure_boot (void)
{
grub_ieee1275_phandle_t root;
grub_uint32_t sb_mode = GRUB_SB_DISABLED;
grub_int32_t rc;
rc = grub_ieee1275_finddevice ("/", &root);
if (rc != 0)
{
grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't find / node");
return;
}
rc = grub_ieee1275_get_integer_property (root, "ibm,secure-boot", &sb_mode, sizeof (sb_mode), 0);
if (rc != 0)
{
grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't examine /ibm,secure-boot property");
return;
}
/*
* Secure Boot Mode:
* 0 - disabled
* No signature verification is performed. This is the default.
* 1 - audit
* Signature verification is performed and if signature verification
* fails, display the errors and allow the boot to continue.
* 2 - enforce
* Lockdown the GRUB. Signature verification is performed and If
* signature verification fails, display the errors and stop the boot.
*
* Now, only support disabled and enforce.
*/
if (sb_mode == GRUB_SB_ENFORCE)
{
grub_dprintf ("ieee1275", "Secure Boot Enabled\n");
grub_lockdown ();
}
else
grub_dprintf ("ieee1275", "Secure Boot Disabled\n");
grub_pks_keystore_init ();
}
#endif /* __powerpc__ */
grub_addr_t grub_modbase; grub_addr_t grub_modbase;
void void
@ -1020,6 +1088,10 @@ grub_machine_init (void)
#else #else
grub_install_get_time_ms (grub_rtc_get_time_ms); grub_install_get_time_ms (grub_rtc_get_time_ms);
#endif #endif
#ifdef __powerpc__
grub_ieee1275_get_secure_boot ();
#endif
} }
void void

View File

@ -201,6 +201,11 @@ grub_ieee1275_devalias_next (struct grub_ieee1275_devalias *alias)
alias->path = 0; alias->path = 0;
} }
tmp = grub_strdup (alias->name); tmp = grub_strdup (alias->name);
if (tmp == NULL)
{
grub_ieee1275_devalias_free (alias);
return 0;
}
if (grub_ieee1275_next_property (alias->parent_dev, tmp, if (grub_ieee1275_next_property (alias->parent_dev, tmp,
alias->name) <= 0) alias->name) <= 0)
{ {
@ -432,9 +437,15 @@ grub_ieee1275_parse_args (const char *path, enum grub_ieee1275_parse_type ptype)
ret = grub_strdup (args); ret = grub_strdup (args);
else else
ret = grub_strndup (args, (grub_size_t)(comma - args)); ret = grub_strndup (args, (grub_size_t)(comma - args));
/* Consistently provide numbered partitions to GRUB.
OpenBOOT traditionally uses alphabetical partition if (ret == NULL)
specifiers. */ return 0;
/*
* Consistently provide numbered partitions to GRUB.
* OpenBOOT traditionally uses alphabetical partition
* specifiers.
*/
if (ret[0] >= 'a' && ret[0] <= 'z') if (ret[0] >= 'a' && ret[0] <= 'z')
ret[0] = '1' + (ret[0] - 'a'); ret[0] = '1' + (ret[0] - 'a');
grub_free (args); grub_free (args);
@ -501,7 +512,20 @@ grub_ieee1275_encode_devname (const char *path)
} }
if (partition && partition[0]) if (partition && partition[0])
{ {
unsigned int partno = grub_strtoul (partition, 0, 0); unsigned long partno;
const char *endptr;
partno = grub_strtoul (partition, &endptr, 0);
grub_errno = GRUB_ERR_NONE;
if (*endptr != '\0' || partno > 65535 ||
(partno == 0 && ! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_0_BASED_PARTITIONS)))
{
grub_free (partition);
grub_free (device);
grub_free (encoding);
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid partition number"));
return NULL;
}
*optr++ = ','; *optr++ = ',';
@ -509,7 +533,7 @@ grub_ieee1275_encode_devname (const char *path)
/* GRUB partition 1 is OF partition 0. */ /* GRUB partition 1 is OF partition 0. */
partno++; partno++;
grub_snprintf (optr, sizeof ("XXXXXXXXXXXX"), "%d", partno); grub_snprintf (optr, sizeof ("XXXXXXXXXXXX"), "%lu", partno);
} }
else else
*optr = '\0'; *optr = '\0';

View File

@ -403,6 +403,9 @@ grub_machine_get_bootlocation (char **device, char **path)
if (!syspart) if (!syspart)
return; return;
loaddev = grub_strdup (syspart); loaddev = grub_strdup (syspart);
if (loaddev == NULL)
return;
} }
partptr = get_part (loaddev); partptr = get_part (loaddev);

View File

@ -26,6 +26,7 @@
#include <grub/i18n.h> #include <grub/i18n.h>
#include <grub/types.h> #include <grub/types.h>
#include <grub/charset.h> #include <grub/charset.h>
#include <stddef.h>
union printf_arg union printf_arg
{ {
@ -99,6 +100,37 @@ grub_memmove (void *dest, const void *src, grub_size_t n)
return dest; return dest;
} }
static void *
__memcpy_aligned (void *dest, const void *src, grub_size_t n)
{
grub_addr_t *dw = (grub_addr_t *) dest;
const grub_addr_t *sw = (const grub_addr_t *) src;
grub_uint8_t *d;
const grub_uint8_t *s;
for (; n >= sizeof (grub_addr_t); n -= sizeof (grub_addr_t))
*dw++ = *sw++;
d = (grub_uint8_t *) dw;
s = (const grub_uint8_t *) sw;
for (; n > 0; n--)
*d++ = *s++;
return dest;
}
void *
grub_memcpy (void *dest, const void *src, grub_size_t n)
{
/* Check if dest and src are aligned and n >= sizeof(grub_addr_t). */
if (((grub_addr_t) dest & (sizeof (grub_addr_t) - 1)) == 0 &&
((grub_addr_t) src & (sizeof (grub_addr_t) - 1)) == 0 &&
n >= sizeof (grub_addr_t))
return __memcpy_aligned (dest, src, n);
return grub_memmove (dest, src, n);
}
char * char *
grub_strcpy (char *dest, const char *src) grub_strcpy (char *dest, const char *src)
{ {
@ -231,14 +263,14 @@ grub_debug_enabled (const char * condition)
} }
void void
grub_real_dprintf (const char *file, const int line, const char *condition, grub_real_dprintf (const char *file, const char *function, const int line, const char *condition,
const char *fmt, ...) const char *fmt, ...)
{ {
va_list args; va_list args;
if (grub_debug_enabled (condition)) if (grub_debug_enabled (condition))
{ {
grub_printf ("%s:%d:%s: ", file, line, condition); grub_printf ("%s:%s:%d:%s: ", file, function, line, condition);
va_start (args, fmt); va_start (args, fmt);
grub_vprintf (fmt, args); grub_vprintf (fmt, args);
va_end (args); va_end (args);
@ -401,6 +433,68 @@ grub_strword (const char *haystack, const char *needle)
return 0; return 0;
} }
char *
grub_strtok_r (char *s, const char *delim, char **save_ptr)
{
char *token;
const char *c;
bool is_delim;
if (s == NULL)
s = *save_ptr;
/* Scan leading delimiters. */
while (*s != '\0')
{
is_delim = false;
for (c = delim; *c != '\0'; c++)
{
if (*s == *c)
{
is_delim = true;
break;
}
}
if (is_delim == true)
s++;
else
break;
}
if (*s == '\0')
{
*save_ptr = s;
return NULL;
}
/* Find the end of the token. */
token = s;
while (*s != '\0')
{
for (c = delim; *c != '\0'; c++)
{
if (*s == *c)
{
*s = '\0';
*save_ptr = s + 1;
return token;
}
}
s++;
}
*save_ptr = s;
return token;
}
char *
grub_strtok (char *s, const char *delim)
{
static char *last;
return grub_strtok_r (s, delim, &last);
}
int int
grub_isspace (int c) grub_isspace (int c)
{ {
@ -739,6 +833,9 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args,
COMPILE_TIME_ASSERT (sizeof (long) <= sizeof (long long)); COMPILE_TIME_ASSERT (sizeof (long) <= sizeof (long long));
COMPILE_TIME_ASSERT (sizeof (long long) == sizeof (void *) COMPILE_TIME_ASSERT (sizeof (long long) == sizeof (void *)
|| sizeof (int) == sizeof (void *)); || sizeof (int) == sizeof (void *));
COMPILE_TIME_ASSERT (sizeof (size_t) == sizeof (unsigned)
|| sizeof (size_t) == sizeof (unsigned long)
|| sizeof (size_t) == sizeof (unsigned long long));
fmt = fmt0; fmt = fmt0;
while ((c = *fmt++) != 0) while ((c = *fmt++) != 0)
@ -773,11 +870,17 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args,
fmt++; fmt++;
c = *fmt++; c = *fmt++;
if (c == 'z')
{
c = *fmt++;
goto do_count;
}
if (c == 'l') if (c == 'l')
c = *fmt++; c = *fmt++;
if (c == 'l') if (c == 'l')
c = *fmt++; c = *fmt++;
do_count:
switch (c) switch (c)
{ {
case 'p': case 'p':
@ -874,6 +977,14 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args,
continue; continue;
} }
if (c == 'z')
{
c = *fmt++;
if (sizeof (size_t) == sizeof (unsigned long))
longfmt = 1;
else if (sizeof (size_t) == sizeof (unsigned long long))
longfmt = 2;
}
if (c == 'l') if (c == 'l')
{ {
c = *fmt++; c = *fmt++;
@ -1050,6 +1161,8 @@ grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0,
} }
c = *fmt++; c = *fmt++;
if (c == 'z')
c = *fmt++;
if (c == 'l') if (c == 'l')
c = *fmt++; c = *fmt++;
if (c == 'l') if (c == 'l')

View File

@ -786,6 +786,39 @@ grub_mm_dump (unsigned lineno)
grub_printf ("\n"); grub_printf ("\n");
} }
void
grub_mm_dump_regions (void)
{
grub_mm_region_t r;
grub_mm_header_t p;
grub_size_t num_blocks, sum_free, sum_alloc;
for (r = grub_mm_base; r; r = r->next)
{
num_blocks = 0;
sum_free = 0;
sum_alloc = 0;
p = (grub_mm_header_t) ALIGN_UP ((grub_addr_t) (r + 1), GRUB_MM_ALIGN);
for (; (grub_addr_t) p < (grub_addr_t) (r+1) + r->size; p++, num_blocks++)
{
switch (p->magic)
{
case GRUB_MM_FREE_MAGIC:
sum_free += p->size;
break;
case GRUB_MM_ALLOC_MAGIC:
sum_alloc += p->size;
break;
}
}
grub_printf ("Region %p (size %" PRIuGRUB_SIZE " blocks %" PRIuGRUB_SIZE " free %" PRIuGRUB_SIZE " alloc %" PRIuGRUB_SIZE ")\n\n",
r, r->size, num_blocks, sum_free << GRUB_MM_ALIGN_LOG2, sum_alloc << GRUB_MM_ALIGN_LOG2);
}
grub_printf ("\n");
}
void * void *
grub_debug_calloc (const char *file, int line, grub_size_t nmemb, grub_size_t size) grub_debug_calloc (const char *file, int line, grub_size_t nmemb, grub_size_t size)
{ {

View File

@ -0,0 +1,137 @@
/* ieee1275.c - Access the Open Firmware client interface. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
* Copyright (C) 2020, 2021, 2022, 2023, 2024, 2025 IBM Corporation
*
* 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/ieee1275/ieee1275.h>
#include <grub/powerpc/ieee1275/ieee1275.h>
#include <grub/misc.h>
grub_int32_t
grub_ieee1275_test (const char *interface_name)
{
struct test_args
{
struct grub_ieee1275_common_hdr common;/* The header information like interface name, number of inputs and outputs. */
grub_ieee1275_cell_t name; /* The interface name. */
grub_ieee1275_cell_t missing;
} args;
INIT_IEEE1275_COMMON (&args.common, "test", 1, 1);
args.name = (grub_ieee1275_cell_t) interface_name;
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
return -1;
if (args.missing == IEEE1275_CELL_INVALID)
return -1;
return 0;
}
grub_int32_t
grub_ieee1275_pks_max_object_size (grub_uint32_t *result)
{
struct mos_args
{
struct grub_ieee1275_common_hdr common;/* The header information like interface name, number of inputs and outputs. */
grub_ieee1275_cell_t size; /* The maximum object size for a PKS object. */
} args;
INIT_IEEE1275_COMMON (&args.common, GRUB_PKS_MAX_OBJ_INTERFACE, 0, 1);
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
return -1;
if (args.size == IEEE1275_CELL_INVALID || args.size == 0)
return -1;
*result = args.size;
return 0;
}
grub_int32_t
grub_ieee1275_pks_read_object (const grub_uint32_t consumer, const char *label,
const grub_uint32_t label_len, const grub_uint32_t buffer_len,
grub_uint8_t *buffer, grub_uint32_t *data_len,
grub_uint32_t *policies)
{
struct pks_read_args
{
struct grub_ieee1275_common_hdr common; /* The header information like interface name, number of inputs and outputs. */
grub_ieee1275_cell_t consumer; /* The object belonging to consumer with the label. */
grub_ieee1275_cell_t label; /* Object label buffer logical real address. */
grub_ieee1275_cell_t label_len; /* The byte length of the object label. */
grub_ieee1275_cell_t buffer; /* Output buffer logical real address. */
grub_ieee1275_cell_t buffer_len; /* Length of the output buffer. */
grub_ieee1275_cell_t data_len; /* The number of bytes copied to the output buffer. */
grub_ieee1275_cell_t policies; /* The object policies. */
grub_int32_t rc; /* The return code. */
} args;
INIT_IEEE1275_COMMON (&args.common, GRUB_PKS_READ_OBJ_INTERFACE, 5, 3);
args.consumer = consumer;
args.label_len = label_len;
args.buffer_len = buffer_len;
args.label = (grub_ieee1275_cell_t) label;
args.buffer = (grub_ieee1275_cell_t) buffer;
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
return -1;
if (args.data_len == IEEE1275_CELL_INVALID)
return -1;
*data_len = args.data_len;
*policies = args.policies;
return args.rc;
}
grub_int32_t
grub_ieee1275_pks_read_sbvar (const grub_uint32_t sbvar_flags, const grub_uint32_t sbvar_type,
const grub_uint32_t buffer_len, grub_uint8_t *buffer,
grub_size_t *data_len)
{
struct pks_read_sbvar_args
{
struct grub_ieee1275_common_hdr common; /* The header information like interface name, number of inputs and outputs. */
grub_ieee1275_cell_t sbvar_flags; /* The sbvar operation flags. */
grub_ieee1275_cell_t sbvar_type; /* The sbvar being requested. */
grub_ieee1275_cell_t buffer; /* Output buffer logical real address. */
grub_ieee1275_cell_t buffer_len; /* Length of the Output buffer. */
grub_ieee1275_cell_t data_len; /* The number of bytes copied to the output buffer. */
grub_int32_t rc; /* The return code. */
} args;
INIT_IEEE1275_COMMON (&args.common, GRUB_PKS_READ_SBVAR_INTERFACE, 4, 2);
args.sbvar_flags = sbvar_flags;
args.sbvar_type = sbvar_type;
args.buffer_len = buffer_len;
args.buffer = (grub_ieee1275_cell_t) buffer;
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
return -1;
if (args.data_len == IEEE1275_CELL_INVALID)
return -1;
*data_len = args.data_len;
return args.rc;
}

View File

@ -0,0 +1,333 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2024 Free Software Foundation, Inc.
* Copyright (C) 2022, 2023, 2024, 2025 IBM Corporation
*
* 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/mm.h>
#include <grub/types.h>
#include <grub/misc.h>
#include <grub/lockdown.h>
#include <grub/ieee1275/ieee1275.h>
#include <grub/powerpc/ieee1275/ieee1275.h>
#include <grub/powerpc/ieee1275/platform_keystore.h>
/* PKS object maximum size. */
static grub_uint32_t pks_max_object_size = 0;
/* Platform KeyStore db and dbx. */
static grub_pks_t pks_keystore = { .db = NULL, .dbx = NULL, .db_entries = 0,
.dbx_entries = 0, .db_exists = true};
/*
* pks_use_keystore: Key Management Modes
* False: Static key management (use built-in Keys). This is default.
* True: Dynamic key management (use Platform KeySotre).
*/
static bool pks_use_keystore = false;
/*
* Reads the Globally Unique Identifier (GUID), EFI Signature Database (ESD),
* and its size from the Platform KeyStore EFI Signature List (ESL), then
* stores them into the PKS Signature Database (SD) (i.e., pks_sd buffer
* and pks_sd entries) in the GRUB.
*/
static grub_err_t
_esl_to_esd (const grub_uint8_t *esl_data, grub_size_t esl_size,
const grub_size_t signature_size, const grub_packed_guid_t *guid,
grub_pks_sd_t **pks_sd, grub_uint32_t *pks_sd_entries)
{
grub_esd_t *esd;
grub_pks_sd_t *signature = *pks_sd;
grub_uint32_t entries = *pks_sd_entries;
grub_size_t data_size, offset = 0;
/* Reads the ESD from ESL. */
while (esl_size > 0)
{
esd = (grub_esd_t *) (esl_data + offset);
data_size = signature_size - sizeof (grub_esd_t);
signature = grub_realloc (signature, (entries + 1) * sizeof (grub_pks_sd_t));
if (signature == NULL)
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
signature[entries].data = grub_malloc (data_size * sizeof (grub_uint8_t));
if (signature[entries].data == NULL)
{
/* Allocated memory will be freed by grub_pks_free_data(). */
*pks_sd = signature;
*pks_sd_entries = entries + 1;
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
}
grub_memcpy (signature[entries].data, esd->signature_data, data_size);
signature[entries].data_size = data_size;
signature[entries].guid = *guid;
entries++;
esl_size -= signature_size;
offset += signature_size;
}
*pks_sd = signature;
*pks_sd_entries = entries;
return GRUB_ERR_NONE;
}
/* Extract the ESD after removing the ESL header from ESL. */
static grub_err_t
esl_to_esd (const grub_uint8_t *esl_data, grub_size_t *next_esl,
grub_pks_sd_t **pks_sd, grub_uint32_t *pks_sd_entries)
{
grub_packed_guid_t guid;
grub_esl_t *esl;
grub_size_t offset, esl_size, signature_size, signature_header_size;
/* Convert the ESL data into the ESL. */
esl = (grub_esl_t *) esl_data;
if (*next_esl < sizeof (grub_esl_t) || esl == NULL)
return grub_error (GRUB_ERR_BUG, "invalid ESL");
esl_size = grub_le_to_cpu32 (esl->signature_list_size);
signature_header_size = grub_le_to_cpu32 (esl->signature_header_size);
signature_size = grub_le_to_cpu32 (esl->signature_size);
grub_memcpy (&guid, &esl->signature_type, sizeof (grub_packed_guid_t));
if (esl_size < sizeof (grub_esl_t) || esl_size > *next_esl)
return grub_error (GRUB_ERR_BUG, "invalid ESL size (%u)\n", esl_size);
*next_esl = esl_size;
offset = sizeof (grub_esl_t) + signature_header_size;
esl_size = esl_size - offset;
return _esl_to_esd (esl_data + offset, esl_size, signature_size, &guid,
pks_sd, pks_sd_entries);
}
/*
* Import the EFI Signature Database (ESD) and the number of ESD from the ESL
* into the pks_sd buffer and pks_sd entries.
*/
static grub_err_t
pks_sd_from_esl (const grub_uint8_t *esl_data, grub_size_t esl_size,
grub_pks_sd_t **pks_sd, grub_uint32_t *pks_sd_entries)
{
grub_err_t rc;
grub_size_t next_esl = esl_size;
do
{
rc = esl_to_esd (esl_data, &next_esl, pks_sd, pks_sd_entries);
if (rc != GRUB_ERR_NONE)
break;
esl_data += next_esl;
esl_size -= next_esl;
next_esl = esl_size;
}
while (esl_size > 0);
return rc;
}
/* Read the secure boot version from PKS as an object. Caller must free result. */
static grub_err_t
read_sbversion_from_pks (grub_uint8_t **out)
{
grub_int32_t rc;
grub_uint32_t outlen = 0, policy = 0;
*out = grub_malloc (pks_max_object_size);
if (*out == NULL)
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
rc = grub_ieee1275_pks_read_object (GRUB_PKS_CONSUMER_FW, GRUB_SB_VERSION_KEY_NAME,
GRUB_SB_VERSION_KEY_LEN, pks_max_object_size, *out,
&outlen, &policy);
if (rc < 0)
{
grub_free (*out);
return grub_error (GRUB_ERR_READ_ERROR, "SB version read failed (%d)\n", rc);
}
if (outlen != 1 || (**out >= 2))
{
grub_free (*out);
return grub_error (GRUB_ERR_BAD_NUMBER, "found unexpected SB version: %u\n", **out);
}
return GRUB_ERR_NONE;
}
/*
* Reads the secure boot variable from PKS, unpacks it, read the ESD from ESL,
* and store the information in the pks_sd buffer.
*/
static grub_err_t
read_sbvar_from_pks (const grub_uint32_t sbvarflags, const grub_uint32_t sbvartype,
grub_pks_sd_t **pks_sd, grub_uint32_t *pks_sd_entries)
{
grub_int32_t rc;
grub_err_t err = GRUB_ERR_NONE;
grub_uint8_t *esl_data = NULL;
grub_size_t esl_data_size = 0;
esl_data = grub_malloc (pks_max_object_size);
if (esl_data == NULL)
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
rc = grub_ieee1275_pks_read_sbvar (sbvarflags, sbvartype, pks_max_object_size,
esl_data, &esl_data_size);
if (rc == IEEE1275_CELL_NOT_FOUND)
{
err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "secure boot variable %s not found (%d)",
(sbvartype == GRUB_PKS_SBVAR_DB) ? "db" : "dbx", rc);
goto fail;
}
else if (rc < 0)
{
err = grub_error (GRUB_ERR_READ_ERROR, "secure boot variable %s reading (%d)",
(sbvartype == GRUB_PKS_SBVAR_DB) ? "db" : "dbx", rc);
goto fail;
}
if (esl_data_size > 0)
err = pks_sd_from_esl (esl_data, esl_data_size, pks_sd, pks_sd_entries);
else
err = GRUB_ERR_BAD_NUMBER;
fail:
grub_free (esl_data);
return err;
}
/*
* Test the availability of PKS support. If PKS support is avaialble and objects
* present, it reads the secure boot version (SB_VERSION) from PKS.
*
* SB_VERSION: Key Management Mode
* 1 - Enable dynamic key management mode. Read the db and dbx variables from PKS,
* and use them for signature verification.
* 0 - Enable static key management mode. Read keys from the GRUB ELF Note and use
* it for signature verification.
*/
static bool
is_pks_present (void)
{
grub_err_t err;
grub_int32_t rc;
grub_uint8_t *data = NULL;
bool ret = false;
rc = grub_ieee1275_test (GRUB_PKS_MAX_OBJ_INTERFACE);
if (rc < 0)
{
grub_error (GRUB_ERR_BAD_FIRMWARE, "firmware doesn't have PKS support\n");
return ret;
}
else
{
rc = grub_ieee1275_pks_max_object_size (&pks_max_object_size);
if (rc < 0)
{
grub_error (GRUB_ERR_BAD_NUMBER, "PKS support is there but it has zero objects\n");
return ret;
}
}
err = read_sbversion_from_pks (&data);
if (err != GRUB_ERR_NONE)
return ret;
/*
* If *data == 1, use dynamic key management and read the keys from the PKS.
* Else, use static key management and read the keys from the GRUB ELF Note.
*/
ret = ((*data == 1) ? true : false);
grub_free (data);
return ret;
}
/* Free allocated memory. */
void
grub_pks_free_data (void)
{
grub_size_t i;
for (i = 0; i < pks_keystore.db_entries; i++)
grub_free (pks_keystore.db[i].data);
for (i = 0; i < pks_keystore.dbx_entries; i++)
grub_free (pks_keystore.dbx[i].data);
grub_free (pks_keystore.db);
grub_free (pks_keystore.dbx);
grub_memset (&pks_keystore, 0, sizeof (grub_pks_t));
}
grub_pks_t *
grub_pks_get_keystore (void)
{
return (pks_use_keystore == true) ? &pks_keystore : NULL;
}
/* Initialization of the Platform KeyStore. */
void
grub_pks_keystore_init (void)
{
grub_err_t rc_db, rc_dbx;
grub_dprintf ("ieee1275", "trying to load Platform KeyStore\n");
if (is_pks_present () == false)
{
grub_dprintf ("ieee1275", "Platform PKS is not available\n");
return;
}
/*
* When read db from PKS, there are three scenarios
* 1. db fully loaded from PKS
* 2. db partially loaded from PKS
* 3. no keys are loaded from db (if db does not exist in PKS), default to
* built-in keys (static keys)
* each of these scenarios, the db keys are checked against dbx.
*/
rc_db = read_sbvar_from_pks (0, GRUB_PKS_SBVAR_DB, &pks_keystore.db, &pks_keystore.db_entries);
if (rc_db == GRUB_ERR_FILE_NOT_FOUND)
pks_keystore.db_exists = false;
/*
* Read dbx from PKS. If dbx is not completely loaded from PKS, then this
* could lead to the loading of vulnerable GRUB modules and kernel binaries.
* So, this should be prevented by freeing up loaded dbx and db.
*/
rc_dbx = read_sbvar_from_pks (0, GRUB_PKS_SBVAR_DBX, &pks_keystore.dbx, &pks_keystore.dbx_entries);
if (rc_dbx == GRUB_ERR_FILE_NOT_FOUND || rc_dbx == GRUB_ERR_BAD_NUMBER)
rc_dbx = GRUB_ERR_NONE;
if (rc_dbx != GRUB_ERR_NONE)
grub_pks_free_data ();
/*
* At this point, it's evident that PKS infrastructure exists, so the PKS
* keystore must be used for validating appended signatures.
*/
pks_use_keystore = true;
}

View File

@ -0,0 +1,360 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2025 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 <grub/env.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/xen.h>
#include <grub/err.h>
enum splitter_state
{
SPLITTER_NORMAL = 0x0,
SPLITTER_HIT_BACKSLASH = 0x1,
SPLITTER_IN_SINGLE_QUOTES = 0x2,
SPLITTER_IN_DOUBLE_QUOTES = 0x4,
};
typedef enum splitter_state splitter_state_t;
/*
* The initial size of the current_word buffer. The buffer may be resized as
* needed.
*/
#define PARSER_BASE_WORD_SIZE 32
struct parser_state
{
char **words;
grub_size_t words_count;
char *current_word;
grub_size_t current_word_len;
grub_size_t current_word_pos;
};
typedef struct parser_state parser_state_t;
static grub_err_t
append_char_to_word (parser_state_t *ps, char c, bool allow_null)
{
/*
* We ban any chars that are not in the ASCII printable range. If
* allow_null == true, we make an exception for NUL. (This is needed so that
* append_word_to_list can add a NUL terminator to the word).
*/
if (!grub_isprint (c) && allow_null == false)
return GRUB_ERR_BAD_ARGUMENT;
else if (allow_null == true && c != '\0')
return GRUB_ERR_BAD_ARGUMENT;
if (ps->current_word_pos == ps->current_word_len)
{
ps->current_word = grub_realloc (ps->current_word, ps->current_word_len *= 2);
if (ps->current_word == NULL)
{
ps->current_word_len /= 2;
return grub_errno;
}
}
ps->current_word[ps->current_word_pos++] = c;
return GRUB_ERR_NONE;
}
static grub_err_t
append_word_to_list (parser_state_t *ps)
{
/* No-op on empty words. */
if (ps->current_word_pos == 0)
return GRUB_ERR_NONE;
if (append_char_to_word (ps, '\0', true) != GRUB_ERR_NONE)
grub_fatal ("couldn't append NUL terminator to word during Xen cmdline parsing");
ps->current_word_len = grub_strlen (ps->current_word) + 1;
ps->current_word = grub_realloc (ps->current_word, ps->current_word_len);
if (ps->current_word == NULL)
return grub_errno;
ps->words = grub_realloc (ps->words, ++ps->words_count * sizeof (char *));
if (ps->words == NULL)
return grub_errno;
ps->words[ps->words_count - 1] = ps->current_word;
ps->current_word_len = PARSER_BASE_WORD_SIZE;
ps->current_word_pos = 0;
ps->current_word = grub_malloc (ps->current_word_len);
if (ps->current_word == NULL)
return grub_errno;
return GRUB_ERR_NONE;
}
static bool
is_key_safe (char *key, grub_size_t len)
{
grub_size_t i;
for (i = 0; i < len; i++)
if (!grub_isalpha (key[i]) && key[i] != '_')
return false;
return true;
}
void
grub_parse_xen_cmdline (void)
{
parser_state_t ps = {0};
splitter_state_t ss = SPLITTER_NORMAL;
const char *cmdline = (const char *) grub_xen_start_page_addr->cmd_line;
grub_size_t cmdline_len;
bool cmdline_valid = false;
char **param_keys = NULL;
char **param_vals = NULL;
grub_size_t param_dict_len = 0;
grub_size_t param_dict_pos = 0;
char current_char = '\0';
grub_size_t i = 0;
/*
* The following algorithm is used to parse the Xen command line:
*
* - The command line is split into space-separated words.
* - Single and double quotes may be used to suppress the splitting
* behavior of spaces.
* - Double quotes are appended to the current word verbatim if they
* appear within a single-quoted string portion, and vice versa.
* - Backslashes may be used to cause the next character to be
* appended to the current word verbatim. This is only useful when
* used to escape quotes, spaces, and backslashes, but for simplicity
* we allow backslash-escaping anything.
* - After splitting the command line into words, each word is checked to
* see if it contains an equals sign.
* - If it does, it is split on the equals sign into a key-value pair. The
* key is then treated as an variable name, and the value is treated as
* the variable's value.
* - If it does not, the entire word is treated as a variable name. The
* variable's value is implicitly considered to be `1`.
* - All variables detected on the command line are checked to see if their
* names begin with the string `xen_grub_env_`. Variables that do not pass
* this check are discarded, variables that do pass this check are
* exported so they are available to the GRUB configuration.
*
* This behavior is intended to somewhat mimic the splitter behavior in Bash
* and in GRUB's config file parser.
*/
ps.current_word_len = PARSER_BASE_WORD_SIZE;
ps.current_word = grub_malloc (ps.current_word_len);
if (ps.current_word == NULL)
goto cleanup_main;
for (i = 0; i < GRUB_XEN_MAX_GUEST_CMDLINE; i++)
{
if (cmdline[i] == '\0')
{
cmdline_valid = true;
break;
}
}
if (cmdline_valid == false)
{
grub_error (GRUB_ERR_BAD_ARGUMENT,
"command line from Xen is not NUL-terminated");
grub_print_error ();
goto cleanup_main;
}
cmdline_len = grub_strlen (cmdline);
for (i = 0; i < cmdline_len; i++)
{
current_char = cmdline[i];
/*
* If the previous character was a backslash, append the current
* character to the word verbatim
*/
if (ss & SPLITTER_HIT_BACKSLASH)
{
ss &= ~SPLITTER_HIT_BACKSLASH;
if (append_char_to_word (&ps, current_char, false) != GRUB_ERR_NONE)
goto cleanup_main;
continue;
}
switch (current_char)
{
case '\\':
/* Backslashes escape arbitrary characters. */
ss |= SPLITTER_HIT_BACKSLASH;
break;
case '\'':
/*
* Single quotes suppress word splitting and double quoting until
* the next single quote is encountered.
*/
if (ss & SPLITTER_IN_DOUBLE_QUOTES)
{
if (append_char_to_word (&ps, current_char, false) != GRUB_ERR_NONE)
goto cleanup_main;
break;
}
ss ^= SPLITTER_IN_SINGLE_QUOTES;
break;
case '"':
/*
* Double quotes suppress word splitting and single quoting until
* the next double quote is encountered.
*/
if (ss & SPLITTER_IN_SINGLE_QUOTES)
{
if (append_char_to_word (&ps, current_char, false) != GRUB_ERR_NONE)
goto cleanup_main;
break;
}
ss ^= SPLITTER_IN_DOUBLE_QUOTES;
break;
case ' ':
/* Spaces separate words in the command line from each other. */
if (ss & SPLITTER_IN_SINGLE_QUOTES ||
ss & SPLITTER_IN_DOUBLE_QUOTES)
{
if (append_char_to_word (&ps, current_char, false) != GRUB_ERR_NONE)
goto cleanup_main;
break;
}
if (append_word_to_list (&ps) != GRUB_ERR_NONE)
goto cleanup_main;
break;
default:
if (append_char_to_word (&ps, current_char, false) != GRUB_ERR_NONE)
goto cleanup_main;
}
}
if (append_word_to_list (&ps) != GRUB_ERR_NONE)
goto cleanup_main;
param_keys = grub_malloc (ps.words_count * sizeof (char *));
if (param_keys == NULL)
goto cleanup_main;
param_vals = grub_malloc (ps.words_count * sizeof (char *));
if (param_vals == NULL)
goto cleanup_main;
for (i = 0; i < ps.words_count; i++)
{
char *eq_pos;
ps.current_word = ps.words[i];
ps.current_word_len = grub_strlen (ps.current_word) + 1;
eq_pos = grub_strchr (ps.current_word, '=');
if (eq_pos != NULL)
{
/*
* Both pre_eq_len and post_eq_len represent substring lengths
* without a NUL terminator.
*/
grub_size_t pre_eq_len = (grub_size_t) (eq_pos - ps.current_word);
/*
* ps.current_word_len includes the NUL terminator, so we subtract
* one to get rid of the terminator, and one more to get rid of the
* equals sign.
*/
grub_size_t post_eq_len = (ps.current_word_len - 2) - pre_eq_len;
if (is_key_safe (ps.current_word, pre_eq_len) == true)
{
param_dict_pos = param_dict_len++;
param_keys[param_dict_pos] = grub_malloc (pre_eq_len + 1);
if (param_keys == NULL)
goto cleanup_main;
param_vals[param_dict_pos] = grub_malloc (post_eq_len + 1);
if (param_vals == NULL)
goto cleanup_main;
grub_strncpy (param_keys[param_dict_pos], ps.current_word, pre_eq_len);
grub_strncpy (param_vals[param_dict_pos],
ps.current_word + pre_eq_len + 1, post_eq_len);
param_keys[param_dict_pos][pre_eq_len] = '\0';
param_vals[param_dict_pos][post_eq_len] = '\0';
}
}
else if (is_key_safe (ps.current_word, ps.current_word_len - 1) == true)
{
param_dict_pos = param_dict_len++;
param_keys[param_dict_pos] = grub_malloc (ps.current_word_len);
if (param_keys == NULL)
goto cleanup_main;
param_vals[param_dict_pos] = grub_zalloc (2);
if (param_vals == NULL)
goto cleanup_main;
grub_strncpy (param_keys[param_dict_pos], ps.current_word,
ps.current_word_len);
if (param_keys[param_dict_pos][ps.current_word_len - 1] != '\0' )
grub_fatal ("NUL terminator missing from key during Xen cmdline parsing");
*param_vals[param_dict_pos] = '1';
}
}
for (i = 0; i < param_dict_len; i++)
{
/*
* Find keys that start with "xen_grub_env_" and export them
* as environment variables.
*/
if (grub_strncmp (param_keys[i],
"xen_grub_env_",
sizeof ("xen_grub_env_") - 1) != 0)
continue;
if (grub_env_set (param_keys[i], param_vals[i]) != GRUB_ERR_NONE)
{
grub_printf ("warning: could not set environment variable `%s' to value `%s'\n",
param_keys[i], param_vals[i]);
continue;
}
if (grub_env_export (param_keys[i]) != GRUB_ERR_NONE)
grub_printf ("warning: could not export environment variable `%s'",
param_keys[i]);
}
cleanup_main:
for (i = 0; i < ps.words_count; i++)
grub_free (ps.words[i]);
for (i = 0; i < param_dict_len; i++)
{
grub_free (param_keys[i]);
grub_free (param_vals[i]);
}
grub_free (param_keys);
grub_free (param_vals);
grub_free (ps.words);
}

View File

@ -581,6 +581,8 @@ grub_machine_init (void)
grub_xendisk_init (); grub_xendisk_init ();
grub_boot_init (); grub_boot_init ();
grub_parse_xen_cmdline ();
} }
void void

52
grub-core/lib/argon2.c Normal file
View File

@ -0,0 +1,52 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2025 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 <grub/crypto.h>
#include <grub/dl.h>
GRUB_MOD_LICENSE ("GPLv3+");
gcry_err_code_t
grub_crypto_argon2 (int subalgo,
const unsigned long *param, unsigned int paramlen,
const void *password, grub_size_t passwordlen,
const void *salt, grub_size_t saltlen,
const void *key, grub_size_t keylen,
const void *ad, grub_size_t adlen,
grub_size_t resultlen, void *result)
{
gcry_kdf_hd_t hd = {0};
gpg_err_code_t err;
if (saltlen == 0)
return GPG_ERR_INV_VALUE;
err = _gcry_kdf_open (&hd, GRUB_GCRY_KDF_ARGON2, subalgo, param, paramlen,
password, passwordlen, salt, saltlen, key, keylen,
ad, adlen);
if (err != GPG_ERR_NO_ERROR)
return err;
err = _gcry_kdf_compute (hd, NULL);
if (err == GPG_ERR_NO_ERROR)
err = _gcry_kdf_final (hd, resultlen, result);
_gcry_kdf_close (hd);
return err;
}

View File

@ -100,8 +100,8 @@ _gpgrt_b64dec_start (const char *title)
/* Do in-place decoding of base-64 data of LENGTH in BUFFER. Stores the /* Do in-place decoding of base-64 data of LENGTH in BUFFER. Stores the
new length of the buffer at R_NBYTES. */ new length of the buffer at R_NBYTES. */
gpg_err_code_t gpg_err_code_t
_gpgrt_b64dec_proc (gpgrt_b64state_t state, void *buffer, size_t length, _gpgrt_b64dec_proc (gpgrt_b64state_t state, void *buffer, grub_size_t length,
size_t *r_nbytes) grub_size_t *r_nbytes)
{ {
enum decoder_states ds = state->idx; enum decoder_states ds = state->idx;
unsigned char val = state->radbuf[0]; unsigned char val = state->radbuf[0];

View File

@ -31,7 +31,9 @@ struct grub_crypto_hmac_handle
{ {
const struct gcry_md_spec *md; const struct gcry_md_spec *md;
void *ctx; void *ctx;
void *opad; void *ctx2;
void *ctx_cache;
void *ctx2_cache;
}; };
static gcry_cipher_spec_t *grub_ciphers = NULL; static gcry_cipher_spec_t *grub_ciphers = NULL;
@ -170,6 +172,10 @@ grub_md_unregister (gcry_md_spec_t *cipher)
} }
} }
struct gcry_pk_spec *grub_crypto_pk_dsa;
struct gcry_pk_spec *grub_crypto_pk_ecdsa;
struct gcry_pk_spec *grub_crypto_pk_rsa;
void void
grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in, grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in,
grub_size_t inlen) grub_size_t inlen)
@ -439,7 +445,8 @@ grub_crypto_hmac_init (const struct gcry_md_spec *md,
{ {
grub_uint8_t *helpkey = NULL; grub_uint8_t *helpkey = NULL;
grub_uint8_t *ipad = NULL, *opad = NULL; grub_uint8_t *ipad = NULL, *opad = NULL;
void *ctx = NULL; void *ctx = NULL, *ctx2 = NULL;
void *ctx_cache = NULL, *ctx2_cache = NULL;
struct grub_crypto_hmac_handle *ret = NULL; struct grub_crypto_hmac_handle *ret = NULL;
unsigned i; unsigned i;
@ -450,6 +457,18 @@ grub_crypto_hmac_init (const struct gcry_md_spec *md,
if (!ctx) if (!ctx)
goto err; goto err;
ctx2 = grub_malloc (md->contextsize);
if (!ctx2)
goto err;
ctx_cache = grub_malloc (md->contextsize);
if (!ctx_cache)
goto err;
ctx2_cache = grub_malloc (md->contextsize);
if (!ctx2_cache)
goto err;
if ( keylen > md->blocksize ) if ( keylen > md->blocksize )
{ {
helpkey = grub_malloc (md->mdlen); helpkey = grub_malloc (md->mdlen);
@ -479,26 +498,40 @@ grub_crypto_hmac_init (const struct gcry_md_spec *md,
grub_free (helpkey); grub_free (helpkey);
helpkey = NULL; helpkey = NULL;
/* inner pad */
md->init (ctx, 0); md->init (ctx, 0);
md->write (ctx, ipad, md->blocksize);
md->write (ctx, ipad, md->blocksize); /* inner pad */ grub_memcpy (ctx_cache, ctx, md->contextsize);
grub_memset (ipad, 0, md->blocksize); grub_memset (ipad, 0, md->blocksize);
grub_free (ipad); grub_free (ipad);
ipad = NULL; ipad = NULL;
/* outer pad */
md->init (ctx2, 0);
md->write (ctx2, opad, md->blocksize);
grub_memcpy (ctx2_cache, ctx2, md->contextsize);
grub_memset (opad, 0, md->blocksize);
grub_free (opad);
opad = NULL;
ret = grub_malloc (sizeof (*ret)); ret = grub_malloc (sizeof (*ret));
if (!ret) if (!ret)
goto err; goto err;
ret->md = md; ret->md = md;
ret->ctx = ctx; ret->ctx = ctx;
ret->opad = opad; ret->ctx2 = ctx2;
ret->ctx_cache = ctx_cache;
ret->ctx2_cache = ctx2_cache;
return ret; return ret;
err: err:
grub_free (helpkey); grub_free (helpkey);
grub_free (ctx); grub_free (ctx);
grub_free (ctx2);
grub_free (ctx_cache);
grub_free (ctx2_cache);
grub_free (ipad); grub_free (ipad);
grub_free (opad); grub_free (opad);
return NULL; return NULL;
@ -512,37 +545,48 @@ grub_crypto_hmac_write (struct grub_crypto_hmac_handle *hnd,
hnd->md->write (hnd->ctx, data, datalen); hnd->md->write (hnd->ctx, data, datalen);
} }
gcry_err_code_t void
grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out) grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out)
{ {
grub_uint8_t *p; grub_crypto_hmac_final (hnd, out);
grub_uint8_t *ctx2; grub_crypto_hmac_free (hnd);
}
ctx2 = grub_malloc (hnd->md->contextsize); void
if (!ctx2) grub_crypto_hmac_reset (struct grub_crypto_hmac_handle *hnd)
return GPG_ERR_OUT_OF_MEMORY; {
grub_memcpy (hnd->ctx, hnd->ctx_cache, hnd->md->contextsize);
grub_memcpy (hnd->ctx2, hnd->ctx2_cache, hnd->md->contextsize);
}
void
grub_crypto_hmac_final (struct grub_crypto_hmac_handle *hnd, void *out)
{
grub_uint8_t *p;
hnd->md->final (hnd->ctx); hnd->md->final (hnd->ctx);
hnd->md->read (hnd->ctx); hnd->md->read (hnd->ctx);
p = hnd->md->read (hnd->ctx); p = hnd->md->read (hnd->ctx);
hnd->md->init (ctx2, 0); hnd->md->write (hnd->ctx2, p, hnd->md->mdlen);
hnd->md->write (ctx2, hnd->opad, hnd->md->blocksize); hnd->md->final (hnd->ctx2);
hnd->md->write (ctx2, p, hnd->md->mdlen);
hnd->md->final (ctx2); grub_memcpy (out, hnd->md->read (hnd->ctx2), hnd->md->mdlen);
grub_memset (hnd->opad, 0, hnd->md->blocksize); }
grub_free (hnd->opad);
void
grub_crypto_hmac_free (struct grub_crypto_hmac_handle *hnd)
{
grub_memset (hnd->ctx, 0, hnd->md->contextsize); grub_memset (hnd->ctx, 0, hnd->md->contextsize);
grub_free (hnd->ctx); grub_free (hnd->ctx);
grub_memset (hnd->ctx2, 0, hnd->md->contextsize);
grub_memcpy (out, hnd->md->read (ctx2), hnd->md->mdlen); grub_free (hnd->ctx2);
grub_memset (ctx2, 0, hnd->md->contextsize); grub_memset (hnd->ctx_cache, 0, hnd->md->contextsize);
grub_free (ctx2); grub_free (hnd->ctx_cache);
grub_memset (hnd->ctx2_cache, 0, hnd->md->contextsize);
grub_free (hnd->ctx2_cache);
grub_memset (hnd, 0, sizeof (*hnd)); grub_memset (hnd, 0, sizeof (*hnd));
grub_free (hnd); grub_free (hnd);
return GPG_ERR_NO_ERROR;
} }
gcry_err_code_t gcry_err_code_t
@ -557,7 +601,8 @@ grub_crypto_hmac_buffer (const struct gcry_md_spec *md,
return GPG_ERR_OUT_OF_MEMORY; return GPG_ERR_OUT_OF_MEMORY;
grub_crypto_hmac_write (hnd, data, datalen); grub_crypto_hmac_write (hnd, data, datalen);
return grub_crypto_hmac_fini (hnd, out); grub_crypto_hmac_fini (hnd, out);
return GPG_ERR_NO_ERROR;
} }

View File

@ -64,7 +64,10 @@ grub_get_weekday_name (struct grub_datetime *datetime)
#define SECPERDAY (24*SECPERHOUR) #define SECPERDAY (24*SECPERHOUR)
#define DAYSPERYEAR 365 #define DAYSPERYEAR 365
#define DAYSPER4YEARS (4*DAYSPERYEAR+1) #define DAYSPER4YEARS (4*DAYSPERYEAR+1)
/* 24 leap years in 100 years */
#define DAYSPER100YEARS (100 * DAYSPERYEAR + 24)
/* 97 leap years in 400 years */
#define DAYSPER400YEARS (400 * DAYSPERYEAR + 97)
void void
grub_unixtime2datetime (grub_int64_t nix, struct grub_datetime *datetime) grub_unixtime2datetime (grub_int64_t nix, struct grub_datetime *datetime)
@ -76,10 +79,12 @@ grub_unixtime2datetime (grub_int64_t nix, struct grub_datetime *datetime)
/* Convenience: let's have 3 consecutive non-bissextile years /* Convenience: let's have 3 consecutive non-bissextile years
at the beginning of the counting date. So count from 1901. */ at the beginning of the counting date. So count from 1901. */
int days_epoch; int days_epoch;
/* Number of days since 1st Januar, 1901. */ /* Number of days since 1st January, 1 (proleptic). */
unsigned days; unsigned days;
/* Seconds into current day. */ /* Seconds into current day. */
unsigned secs_in_day; unsigned secs_in_day;
/* Tracks whether this is a leap year. */
bool bisextile;
/* Transform C divisions and modulos to mathematical ones */ /* Transform C divisions and modulos to mathematical ones */
if (nix < 0) if (nix < 0)
@ -92,12 +97,45 @@ grub_unixtime2datetime (grub_int64_t nix, struct grub_datetime *datetime)
days_epoch = grub_divmod64 (nix, SECPERDAY, NULL); days_epoch = grub_divmod64 (nix, SECPERDAY, NULL);
secs_in_day = nix - days_epoch * SECPERDAY; secs_in_day = nix - days_epoch * SECPERDAY;
days = days_epoch + 69 * DAYSPERYEAR + 17; /*
* 1970 is Unix Epoch. Adjust to a year 1 epoch:
* Leap year logic:
* - Years evenly divisible by 400 are leap years
* - Otherwise, if divisible by 100 are not leap years
* - Otherwise, if divisible by 4 are leap years
* There are four 400-year periods (1600 years worth of days with leap days)
* There are 369 years in addition to the four 400 year periods
* There are three 100-year periods worth of leap days (3*24)
* There are 17 leap days in 69 years (beyond the three 100 year periods)
*/
days = 4 * DAYSPER400YEARS + 369 * DAYSPERYEAR + 3 * 24 + 17 + days_epoch;
datetime->year = 1901 + 4 * (days / DAYSPER4YEARS); datetime->year = 1 + 400 * (days / DAYSPER400YEARS);
days %= DAYSPER400YEARS;
/*
* On 31st December of bissextile (leap) years 365 days from the beginning
* of the year elapsed but year isn't finished yet - every 400 years
* 396 is 4 years less than 400 year leap cycle
* 96 is 1 day less than number of leap days in 400 years
*/
if (days / DAYSPER100YEARS == 4)
{
datetime->year += 396;
days -= 396 * DAYSPERYEAR + 96;
}
else
{
datetime->year += 100 * (days / DAYSPER100YEARS);
days %= DAYSPER100YEARS;
}
datetime->year += 4 * (days / DAYSPER4YEARS);
days %= DAYSPER4YEARS; days %= DAYSPER4YEARS;
/* On 31st December of bissextile years 365 days from the beginning /*
of the year elapsed but year isn't finished yet */ * On 31st December of bissextile (leap) years 365 days from the beginning
* of the year elapsed but year isn't finished yet - every 4 years
*/
if (days / DAYSPERYEAR == 4) if (days / DAYSPERYEAR == 4)
{ {
datetime->year += 3; datetime->year += 3;
@ -108,11 +146,14 @@ grub_unixtime2datetime (grub_int64_t nix, struct grub_datetime *datetime)
datetime->year += days / DAYSPERYEAR; datetime->year += days / DAYSPERYEAR;
days %= DAYSPERYEAR; days %= DAYSPERYEAR;
} }
for (i = 0; i < 12
&& days >= (i==1 && datetime->year % 4 == 0 bisextile = (datetime->year % 4 == 0
? 29 : months[i]); i++) && (datetime->year % 100 != 0
days -= (i==1 && datetime->year % 4 == 0 || datetime->year % 400 == 0)) ? true : false;
? 29 : months[i]); for (i = 0;
i < 12 && days >= ((i == 1 && bisextile == true) ? 29 : months[i]);
i++)
days -= ((i == 1 && bisextile == true) ? 29 : months[i]);
datetime->month = i + 1; datetime->month = i + 1;
datetime->day = 1 + days; datetime->day = 1 + days;
datetime->hour = (secs_in_day / SECPERHOUR); datetime->hour = (secs_in_day / SECPERHOUR);

View File

@ -22,6 +22,7 @@
#include <grub/efi/tpm.h> #include <grub/efi/tpm.h>
#include <grub/mm.h> #include <grub/mm.h>
#include <tss2_types.h>
#include <tcg2.h> #include <tcg2.h>
static grub_err_t static grub_err_t
@ -141,3 +142,42 @@ grub_tcg2_submit_command (grub_size_t input_size,
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
grub_err_t
grub_tcg2_cap_pcr (grub_uint8_t pcr)
{
grub_err_t err;
grub_efi_status_t status;
grub_efi_tpm2_protocol_t *protocol;
EFI_TCG2_EVENT *event;
grub_uint8_t separator[4] = {0};
if (pcr >= TPM_MAX_PCRS)
return GRUB_ERR_BAD_ARGUMENT;
err = tcg2_get_protocol (&protocol);
if (err != GRUB_ERR_NONE)
return err;
event = grub_zalloc (sizeof (EFI_TCG2_EVENT) + sizeof (separator));
if (event == NULL)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
N_("cannot allocate TPM event buffer"));
event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER);
event->Header.HeaderVersion = 1;
event->Header.PCRIndex = pcr;
event->Header.EventType = GRUB_EV_SEPARATOR;
event->Size = sizeof (*event) - sizeof (event->Event) + sizeof (separator);
grub_memcpy (event->Event, separator, sizeof (separator));
status = protocol->hash_log_extend_event (protocol, 0,
(grub_addr_t) separator,
sizeof (separator), event);
grub_free (event);
if (status != GRUB_EFI_SUCCESS)
return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot cap PCR %u"), pcr);
return GRUB_ERR_NONE;
}

View File

@ -50,7 +50,7 @@
- return REG_NOERROR; - return REG_NOERROR;
+ return err; + return err;
} }
/* If it is possible to do searching in single byte encoding instead of UTF-8 /* If it is possible to do searching in single byte encoding instead of UTF-8
@@ -1677,12 +1677,11 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root) @@ -1677,12 +1677,11 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root)
{ {
@ -106,5 +106,5 @@
+ +
+ return err; + return err;
} }
/* Functions for token which are used in the parser. */ /* Functions for token which are used in the parser. */

View File

@ -1,6 +1,6 @@
--- a/lib/regexec.c 2020-10-21 14:25:35.310195912 +0000 --- a/lib/regexec.c 2020-10-21 14:25:35.310195912 +0000
+++ b/lib/regexec.c 2020-10-21 14:32:07.961765604 +0000 +++ b/lib/regexec.c 2020-10-21 14:32:07.961765604 +0000
@@ -828,7 +828,11 @@ @@ -807,7 +807,11 @@
break; break;
if (__glibc_unlikely (err != REG_NOMATCH)) if (__glibc_unlikely (err != REG_NOMATCH))
goto free_return; goto free_return;

View File

@ -0,0 +1,52 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2025 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 <grub/dl.h>
#include <grub/hwfeatures-gcry.h>
#if defined (__x86_64__) && defined (GRUB_MACHINE_EFI)
#include <grub/x86_64/efi/hwfeatures-gcry.h>
#endif
GRUB_MOD_LICENSE ("GPLv3+");
static bool __gcry_use_hwf = false;
bool
grub_gcry_hwf_enabled (void)
{
return __gcry_use_hwf;
}
void
grub_enable_gcry_hwf (void)
{
#if defined (__x86_64__) && defined (GRUB_MACHINE_EFI)
grub_enable_gcry_hwf_x86_64_efi ();
#endif
__gcry_use_hwf = true;
}
void
grub_reset_gcry_hwf (void)
{
#if defined (__x86_64__) && defined (GRUB_MACHINE_EFI)
grub_reset_gcry_hwf_x86_64_efi ();
#endif
__gcry_use_hwf = false;
}

View File

@ -26,6 +26,8 @@
#include <grub/relocator.h> #include <grub/relocator.h>
#include <grub/relocator_private.h> #include <grub/relocator_private.h>
#include <grub/i386/memory.h>
extern grub_uint8_t grub_relocator_forward_start; extern grub_uint8_t grub_relocator_forward_start;
extern grub_uint8_t grub_relocator_forward_end; extern grub_uint8_t grub_relocator_forward_end;
extern grub_uint8_t grub_relocator_backward_start; extern grub_uint8_t grub_relocator_backward_start;
@ -41,20 +43,122 @@ extern grub_size_t grub_relocator_forward_chunk_size;
#define RELOCATOR_SIZEOF(x) (&grub_relocator##x##_end - &grub_relocator##x##_start) #define RELOCATOR_SIZEOF(x) (&grub_relocator##x##_end - &grub_relocator##x##_start)
grub_size_t grub_relocator_align = 1;
grub_size_t grub_relocator_forward_size; grub_size_t grub_relocator_forward_size;
grub_size_t grub_relocator_backward_size; grub_size_t grub_relocator_backward_size;
grub_size_t grub_relocator_preamble_size = 0;
#ifdef __x86_64__ #ifdef __x86_64__
grub_size_t grub_relocator_jumper_size = 12; grub_size_t grub_relocator_jumper_size = 12;
#else #else
grub_size_t grub_relocator_jumper_size = 7; grub_size_t grub_relocator_jumper_size = 7;
#endif #endif
#if defined(__x86_64__) && defined(GRUB_MACHINE_EFI)
grub_size_t grub_relocator_align = 4096;
#else
grub_size_t grub_relocator_align = 1;
#endif
#if defined(__x86_64__) && defined(GRUB_MACHINE_EFI)
#define PAGE_PRESENT 1
#define PAGE_WRITABLE 2
#define PAGE_USER 4
#define PAGE_PS 0x80
#define PAGE_IDX_SIZE 9
#define PAGE_PS_SHIFT 21
#define PAGE_NUM_ENTRIES 0x200
#define PS_PAGE_SIZE 0x200000
static grub_uint64_t max_ram_size;
/* Helper for grub_get_multiboot_mmap_count. */
static int
max_hook (grub_uint64_t addr,
grub_uint64_t size,
grub_memory_type_t type __attribute__ ((unused)),
void *data __attribute__ ((unused)))
{
max_ram_size = grub_max (max_ram_size, addr + size);
return 0;
}
static grub_uint64_t
find_max_size (void)
{
if (!max_ram_size)
{
/* We need to map the first 4GiB of address space as well as all the
available RAM, so start with 4GiB and increase if we see any RAM
above this. */
max_ram_size = 1ULL << 32;
grub_mmap_iterate (max_hook, NULL);
}
return max_ram_size;
}
void
grub_cpu_relocator_preamble (void *rels)
{
grub_uint64_t nentries = (find_max_size () + PS_PAGE_SIZE - 1) >> PAGE_PS_SHIFT;
grub_uint64_t npt2pages = (nentries + PAGE_NUM_ENTRIES - 1) >> PAGE_IDX_SIZE;
grub_uint64_t npt3pages = (npt2pages + PAGE_NUM_ENTRIES - 1) >> PAGE_IDX_SIZE;
grub_uint8_t *p = rels;
grub_uint64_t *pt4 = (grub_uint64_t *) (p + GRUB_PAGE_SIZE);
grub_uint64_t *pt3 = pt4 + PAGE_NUM_ENTRIES;
grub_uint64_t *pt2 = pt3 + (npt3pages << PAGE_IDX_SIZE);
grub_uint64_t *endpreamble = pt2 + (npt2pages << PAGE_IDX_SIZE);
grub_uint64_t i;
/* movabs $pt4, %rax. */
*p++ = 0x48;
*p++ = 0xb8;
*(grub_uint64_t *) p = (grub_uint64_t) pt4;
p += 8;
/* mov %rax, %cr3. */
*p++ = 0x0f;
*p++ = 0x22;
*p++ = 0xd8;
/* jmp $endpreamble. */
*p++ = 0xe9;
*(grub_uint32_t *) p = (grub_uint8_t *) endpreamble - p - 4;
for (i = 0; i < npt3pages; i++)
pt4[i] = ((grub_uint64_t) pt3 + (i << GRUB_PAGE_SHIFT)) | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
for (i = 0; i < npt2pages; i++)
pt3[i] = ((grub_uint64_t) pt2 + (i << GRUB_PAGE_SHIFT)) | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
for (i = 0; i < (npt2pages << PAGE_IDX_SIZE); i++)
pt2[i] = (i << PAGE_PS_SHIFT) | PAGE_PS | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
}
static void
compute_preamble_size (void)
{
grub_uint64_t nentries = (find_max_size () + PS_PAGE_SIZE - 1) >> PAGE_PS_SHIFT;
grub_uint64_t npt2pages = (nentries + PAGE_NUM_ENTRIES - 1) >> PAGE_IDX_SIZE;
grub_uint64_t npt3pages = (npt2pages + PAGE_NUM_ENTRIES - 1) >> PAGE_IDX_SIZE;
grub_relocator_preamble_size = (npt2pages + npt3pages + 1 + 1) << GRUB_PAGE_SHIFT;
}
#else
void
grub_cpu_relocator_preamble (void *rels __attribute__((unused)))
{
}
#endif
void void
grub_cpu_relocator_init (void) grub_cpu_relocator_init (void)
{ {
grub_relocator_forward_size = RELOCATOR_SIZEOF (_forward); grub_relocator_forward_size = RELOCATOR_SIZEOF (_forward);
grub_relocator_backward_size = RELOCATOR_SIZEOF (_backward); grub_relocator_backward_size = RELOCATOR_SIZEOF (_backward);
#if defined(__x86_64__) && defined(GRUB_MACHINE_EFI)
compute_preamble_size ();
#endif
} }
void void

View File

@ -56,6 +56,52 @@ grub_ieee1275_tpm_init (void)
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
grub_err_t
grub_ieee1275_ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex,
grub_uint32_t eventtype,
const char *description,
grub_size_t description_size,
void *buf, grub_size_t size)
{
struct tpm_2hash_ext_log
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_cell_t method;
grub_ieee1275_cell_t ihandle;
grub_ieee1275_cell_t size;
grub_ieee1275_cell_t buf;
grub_ieee1275_cell_t description_size;
grub_ieee1275_cell_t description;
grub_ieee1275_cell_t eventtype;
grub_ieee1275_cell_t pcrindex;
grub_ieee1275_cell_t catch_result;
grub_ieee1275_cell_t rc;
};
struct tpm_2hash_ext_log args;
INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 2);
args.method = (grub_ieee1275_cell_t) "2hash-ext-log";
args.ihandle = grub_ieee1275_tpm_ihandle;
args.pcrindex = pcrindex;
args.eventtype = eventtype;
args.description = (grub_ieee1275_cell_t) description;
args.description_size = description_size;
args.buf = (grub_ieee1275_cell_t) buf;
args.size = (grub_ieee1275_cell_t) size;
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
return grub_error (GRUB_ERR_BAD_DEVICE, "2HASH-EXT-LOG failed: Firmware is likely too old.\n");
/*
* catch_result is set if firmware does not support 2hash-ext-log
* rc is GRUB_IEEE1275_CELL_FALSE (0) on failure
*/
if ((args.catch_result) || args.rc == GRUB_IEEE1275_CELL_FALSE)
return grub_error (GRUB_ERR_BAD_DEVICE, "2HASH-EXT-LOG failed: Firmware is likely too old.\n");
return GRUB_ERR_NONE;
}
grub_err_t grub_err_t
grub_tcg2_get_max_output_size (grub_size_t *size) grub_tcg2_get_max_output_size (grub_size_t *size)
{ {
@ -155,3 +201,22 @@ grub_tcg2_submit_command (grub_size_t input_size,
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
grub_err_t
grub_tcg2_cap_pcr (grub_uint8_t pcr)
{
char separator[4] = {0};
static int error_displayed = 0;
grub_err_t err;
err = grub_ieee1275_ibmvtpm_2hash_ext_log (pcr, GRUB_EV_SEPARATOR,
separator, sizeof (separator),
separator, sizeof (separator));
if (err != GRUB_ERR_NONE && !error_displayed)
{
error_displayed++;
return err;
}
return GRUB_ERR_NONE;
}

View File

@ -508,6 +508,9 @@ grub_legacy_parse (const char *buf, char **entryname, char **suffix)
char *ret; char *ret;
int len = grub_strlen (buf); int len = grub_strlen (buf);
ret = grub_malloc (len + 2); ret = grub_malloc (len + 2);
if (ret == NULL)
return NULL;
grub_memcpy (ret, buf, len); grub_memcpy (ret, buf, len);
if (len && ret[len - 1] == '\n') if (len && ret[len - 1] == '\n')
ret[len] = 0; ret[len] = 0;

View File

@ -0,0 +1,63 @@
From 42e9975171439e2e9713e122cb0e74174f057e98 Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Mon, 25 Aug 2025 15:54:24 +0800
Subject: [PATCH 1/4] libgcrypt/kdf: Implement blake2b_512.hash_buffers()
Add argon2_blake2b_512_hash_buffers() as the replacement of
_gcry_digest_spec_blake2b_512.hash_buffers().
Signed-off-by: Gary Lin <glin@suse.com>
---
grub-core/lib/libgcrypt-grub/cipher/kdf.c | 25 ++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/grub-core/lib/libgcrypt-grub/cipher/kdf.c b/grub-core/lib/libgcrypt-grub/cipher/kdf.c
index 0689f88b1..08e3ef658 100644
--- a/grub-core/lib/libgcrypt-grub/cipher/kdf.c
+++ b/grub-core/lib/libgcrypt-grub/cipher/kdf.c
@@ -129,10 +129,31 @@ beswap64_block (u64 *dst)
#endif
}
+/* Implementation of _gcry_blake2b_512_hash_buffers */
+static gcry_err_code_t
+argon2_blake2b_512_hash_buffers (void *outbuf, const gcry_buffer_t *iov, int iovcnt)
+{
+ void *hd;
+
+ hd = xtrymalloc (_gcry_digest_spec_blake2b_512.contextsize);
+ if (!hd)
+ return GPG_ERR_OUT_OF_MEMORY;
+
+ _gcry_digest_spec_blake2b_512.init (hd, 0);
+ for (;iovcnt > 0; iov++, iovcnt--)
+ _gcry_digest_spec_blake2b_512.write (hd, (const char*)iov[0].data + iov[0].off, iov[0].len);
+ _gcry_digest_spec_blake2b_512.final (hd);
+ grub_memcpy (outbuf, _gcry_digest_spec_blake2b_512.read (hd), 512 / 8);
+
+ xfree (hd);
+
+ return GPG_ERR_NO_ERROR;
+}
static gpg_err_code_t
argon2_fill_first_blocks (argon2_ctx_t a)
{
+ gpg_err_code_t err;
unsigned char h0_01_i[72];
unsigned char buf[10][4];
gcry_buffer_t iov[8];
@@ -195,7 +216,9 @@ argon2_fill_first_blocks (argon2_ctx_t a)
iov_count++;
}
- _gcry_digest_spec_blake2b_512.hash_buffers (h0_01_i, 64, iov, iov_count);
+ err = argon2_blake2b_512_hash_buffers (h0_01_i, iov, iov_count);
+ if (err != GPG_ERR_NO_ERROR)
+ return err;
for (i = 0; i < a->lanes; i++)
{
--
2.51.0

View File

@ -0,0 +1,48 @@
From 89f793515d927d8f7099b61d0b7b200611e56acd Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Mon, 25 Aug 2025 15:56:03 +0800
Subject: [PATCH 2/4] libgcrypt/kdf: Get rid of gpg_err_code_from_errno()
gpg_err_code_from_errno() requires libgcrypt_wrap/mem.c which is not in
Makefile.utilgcry.def. This commit replaces gpg_err_code_from_errno()
with GPG_ERR_* to avoid the build errors.
Signed-off-by: Gary Lin <glin@suse.com>
---
grub-core/lib/libgcrypt-grub/cipher/kdf.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/grub-core/lib/libgcrypt-grub/cipher/kdf.c b/grub-core/lib/libgcrypt-grub/cipher/kdf.c
index 08e3ef658..6e0351d8a 100644
--- a/grub-core/lib/libgcrypt-grub/cipher/kdf.c
+++ b/grub-core/lib/libgcrypt-grub/cipher/kdf.c
@@ -265,7 +265,7 @@ argon2_init (argon2_ctx_t a, unsigned int parallelism,
block = xtrymalloc (1024 * memory_blocks);
if (!block)
{
- ec = gpg_err_code_from_errno (errno);
+ ec = GPG_ERR_OUT_OF_MEMORY;
return ec;
}
memset (block, 0, 1024 * memory_blocks);
@@ -273,7 +273,7 @@ argon2_init (argon2_ctx_t a, unsigned int parallelism,
thread_data = xtrymalloc (a->lanes * sizeof (struct argon2_thread_data));
if (!thread_data)
{
- ec = gpg_err_code_from_errno (errno);
+ ec = GPG_ERR_OUT_OF_MEMORY;
xfree (block);
return ec;
}
@@ -624,7 +624,7 @@ argon2_open (gcry_kdf_hd_t *hd, int subalgo,
n = offsetof (struct argon2_context, out) + taglen;
a = xtrymalloc (n);
if (!a)
- return gpg_err_code_from_errno (errno);
+ return GPG_ERR_OUT_OF_MEMORY;
a->algo = GCRY_KDF_ARGON2;
a->hash_type = hash_type;
--
2.51.0

View File

@ -0,0 +1,166 @@
From fc9c57f54fd28685f7df79e53078e1dc9e44f964 Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Mon, 25 Aug 2025 16:00:17 +0800
Subject: [PATCH 3/4] libgcrypt/kdf: Remove unsupported KDFs
Clean up _gcry_kdf_*() to remove unsupported KDFs.
Signed-off-by: Gary Lin <glin@suse.com>
---
grub-core/lib/libgcrypt-grub/cipher/kdf.c | 119 ----------------------
1 file changed, 119 deletions(-)
diff --git a/grub-core/lib/libgcrypt-grub/cipher/kdf.c b/grub-core/lib/libgcrypt-grub/cipher/kdf.c
index 6e0351d8a..c51a70eff 100644
--- a/grub-core/lib/libgcrypt-grub/cipher/kdf.c
+++ b/grub-core/lib/libgcrypt-grub/cipher/kdf.c
@@ -821,64 +821,6 @@ _gcry_kdf_open (gcry_kdf_hd_t *hd, int algo, int subalgo,
key, keylen, ad, adlen);
break;
- case GCRY_KDF_BALLOON:
- if (!inputlen || !saltlen || keylen || adlen)
- ec = GPG_ERR_INV_VALUE;
- else
- {
- (void)key;
- (void)ad;
- ec = balloon_open (hd, subalgo, param, paramlen,
- input, inputlen, salt, saltlen);
- }
- break;
-
- case GCRY_KDF_ONESTEP_KDF:
- if (!inputlen || !paramlen || !adlen)
- ec = GPG_ERR_INV_VALUE;
- else
- {
- (void)salt;
- (void)key;
- ec = onestep_kdf_open (hd, subalgo, param, paramlen,
- input, inputlen, ad, adlen);
- }
- break;
-
- case GCRY_KDF_ONESTEP_KDF_MAC:
- if (!inputlen || !paramlen || !keylen || !adlen)
- ec = GPG_ERR_INV_VALUE;
- else
- {
- (void)salt;
- ec = onestep_kdf_mac_open (hd, subalgo, param, paramlen,
- input, inputlen, key, keylen, ad, adlen);
- }
- break;
-
- case GCRY_KDF_HKDF:
- if (!inputlen || !paramlen)
- ec = GPG_ERR_INV_VALUE;
- else
- {
- (void)salt;
- ec = hkdf_open (hd, subalgo, param, paramlen,
- input, inputlen, key, keylen, ad, adlen);
- }
- break;
-
- case GCRY_KDF_X963_KDF:
- if (!inputlen || !paramlen)
- ec = GPG_ERR_INV_VALUE;
- else
- {
- (void)salt;
- (void)key;
- ec = x963_kdf_open (hd, subalgo, param, paramlen,
- input, inputlen, ad, adlen);
- }
- break;
-
default:
ec = GPG_ERR_UNKNOWN_ALGORITHM;
break;
@@ -898,26 +840,6 @@ _gcry_kdf_compute (gcry_kdf_hd_t h, const struct gcry_kdf_thread_ops *ops)
ec = argon2_compute ((argon2_ctx_t)(void *)h, ops);
break;
- case GCRY_KDF_BALLOON:
- ec = balloon_compute_all ((balloon_ctx_t)(void *)h, ops);
- break;
-
- case GCRY_KDF_ONESTEP_KDF:
- ec = onestep_kdf_compute ((onestep_kdf_ctx_t)(void *)h, ops);
- break;
-
- case GCRY_KDF_ONESTEP_KDF_MAC:
- ec = onestep_kdf_mac_compute ((onestep_kdf_mac_ctx_t)(void *)h, ops);
- break;
-
- case GCRY_KDF_HKDF:
- ec = hkdf_compute ((hkdf_ctx_t)(void *)h, ops);
- break;
-
- case GCRY_KDF_X963_KDF:
- ec = x963_kdf_compute ((x963_kdf_ctx_t)(void *)h, ops);
- break;
-
default:
ec = GPG_ERR_UNKNOWN_ALGORITHM;
break;
@@ -938,27 +860,6 @@ _gcry_kdf_final (gcry_kdf_hd_t h, size_t resultlen, void *result)
ec = argon2_final ((argon2_ctx_t)(void *)h, resultlen, result);
break;
- case GCRY_KDF_BALLOON:
- ec = balloon_final ((balloon_ctx_t)(void *)h, resultlen, result);
- break;
-
- case GCRY_KDF_ONESTEP_KDF:
- ec = onestep_kdf_final ((onestep_kdf_ctx_t)(void *)h, resultlen, result);
- break;
-
- case GCRY_KDF_ONESTEP_KDF_MAC:
- ec = onestep_kdf_mac_final ((onestep_kdf_mac_ctx_t)(void *)h,
- resultlen, result);
- break;
-
- case GCRY_KDF_HKDF:
- ec = hkdf_final ((hkdf_ctx_t)(void *)h, resultlen, result);
- break;
-
- case GCRY_KDF_X963_KDF:
- ec = x963_kdf_final ((x963_kdf_ctx_t)(void *)h, resultlen, result);
- break;
-
default:
ec = GPG_ERR_UNKNOWN_ALGORITHM;
break;
@@ -976,26 +877,6 @@ _gcry_kdf_close (gcry_kdf_hd_t h)
argon2_close ((argon2_ctx_t)(void *)h);
break;
- case GCRY_KDF_BALLOON:
- balloon_close ((balloon_ctx_t)(void *)h);
- break;
-
- case GCRY_KDF_ONESTEP_KDF:
- onestep_kdf_close ((onestep_kdf_ctx_t)(void *)h);
- break;
-
- case GCRY_KDF_ONESTEP_KDF_MAC:
- onestep_kdf_mac_close ((onestep_kdf_mac_ctx_t)(void *)h);
- break;
-
- case GCRY_KDF_HKDF:
- hkdf_close ((hkdf_ctx_t)(void *)h);
- break;
-
- case GCRY_KDF_X963_KDF:
- x963_kdf_close ((x963_kdf_ctx_t)(void *)h);
- break;
-
default:
break;
}
--
2.51.0

View File

@ -0,0 +1,79 @@
From 990a5f7df076200aa031b1bcde6bc4b13d4f198e Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Mon, 25 Aug 2025 16:01:45 +0800
Subject: [PATCH 4/4] libgcrypt/kdf: Fix 64-bit modulus on 32-bit platforms
Use grub_divmod64() for the 64-bit modulus to prevent creation of
special division calls such as __umoddi3() and __aeabi_uldivmod() on
32-bit platforms.
Signed-off-by: Gary Lin <glin@suse.com>
---
grub-core/lib/libgcrypt-grub/cipher/kdf.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/grub-core/lib/libgcrypt-grub/cipher/kdf.c b/grub-core/lib/libgcrypt-grub/cipher/kdf.c
index c51a70eff..f4bb51809 100644
--- a/grub-core/lib/libgcrypt-grub/cipher/kdf.c
+++ b/grub-core/lib/libgcrypt-grub/cipher/kdf.c
@@ -375,6 +375,7 @@ index_alpha (argon2_ctx_t a, const struct argon2_thread_data *t,
u32 reference_area_size;
u64 relative_position;
u32 start_position;
+ u64 remainder;
if (t->pass == 0)
{
@@ -411,7 +412,8 @@ index_alpha (argon2_ctx_t a, const struct argon2_thread_data *t,
? 0
: (t->slice + 1) * a->segment_length;
- return (start_position + relative_position) % a->lane_length;
+ grub_divmod64 (start_position + relative_position, a->lane_length, &remainder);
+ return remainder;
}
static void
@@ -425,6 +427,7 @@ argon2_compute_segment (void *priv)
u64 input_block[1024/sizeof (u64)];
u64 address_block[1024/sizeof (u64)];
u64 *random_block = NULL;
+ u64 remainder;
if (a->hash_type == GCRY_KDF_ARGON2I
|| (a->hash_type == GCRY_KDF_ARGON2ID && t->pass == 0 && t->slice < 2))
@@ -449,7 +452,8 @@ argon2_compute_segment (void *priv)
i = 0;
curr_offset = t->lane * a->lane_length + t->slice * a->segment_length + i;
- if ((curr_offset % a->lane_length))
+ grub_divmod64 (curr_offset, a->lane_length, &remainder);
+ if (remainder)
prev_offset = curr_offset - 1;
else
prev_offset = curr_offset + a->lane_length - 1;
@@ -459,7 +463,8 @@ argon2_compute_segment (void *priv)
u64 *ref_block, *curr_block;
u64 rand64;
- if ((curr_offset % a->lane_length) == 1)
+ grub_divmod64 (curr_offset, a->lane_length, &remainder);
+ if (remainder == 1)
prev_offset = curr_offset - 1;
if (random_block)
@@ -475,7 +480,10 @@ argon2_compute_segment (void *priv)
if (t->pass == 0 && t->slice == 0)
ref_lane = t->lane;
else
- ref_lane = (rand64 >> 32) % a->lanes;
+ {
+ grub_divmod64 (rand64 >> 32, a->lanes, &remainder);
+ ref_lane = remainder;
+ }
ref_index = index_alpha (a, t, i, (rand64 & 0xffffffff),
ref_lane == t->lane);
--
2.51.0

View File

@ -0,0 +1,87 @@
From 4403c452240417aaac7d3120c80b1325b7218768 Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Fri, 18 Jul 2025 15:21:51 +0800
Subject: [PATCH 1/4] libgcrypt: Implement _gcry_get_hw_features()
Implement _gcry_get_hw_features() and enable hardware feature detection
for x86_64.
Signed-off-by: Gary Lin <glin@suse.com>
---
grub-core/Makefile.gcry.def | 8 ++++
grub-core/lib/libgcrypt-grub/src/hwfeatures.c | 47 +++++++++++++++++++
2 files changed, 55 insertions(+)
create mode 100644 grub-core/lib/libgcrypt-grub/src/hwfeatures.c
diff --git a/grub-core/Makefile.gcry.def b/grub-core/Makefile.gcry.def
index a0593fa09..c8caf17dc 100644
--- a/grub-core/Makefile.gcry.def
+++ b/grub-core/Makefile.gcry.def
@@ -226,3 +226,11 @@ module = {
cppflags = '$(CPPFLAGS_GCRY)';
};
+module = {
+ name = gcry_hwfeatures;
+ common = lib/libgcrypt-grub/src/hwfeatures.c;
+ x86_64_efi = lib/libgcrypt-grub/src/hwf-x86.c;
+
+ cflags = '$(CFLAGS_GCRY)';
+ cppflags = '$(CPPFLAGS_GCRY) $(CPPFLAGS_GCRY_ASM)';
+};
diff --git a/grub-core/lib/libgcrypt-grub/src/hwfeatures.c b/grub-core/lib/libgcrypt-grub/src/hwfeatures.c
new file mode 100644
index 000000000..4d744f8ec
--- /dev/null
+++ b/grub-core/lib/libgcrypt-grub/src/hwfeatures.c
@@ -0,0 +1,47 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2025 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 <grub/dl.h>
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#include <grub/crypto.h>
+#include <grub/hwfeatures-gcry.h>
+#include "hwf-common.h"
+
+unsigned int
+_gcry_get_hw_features (void)
+{
+ static bool detected = false;
+ static unsigned int hw_features = 0;
+
+ if (grub_gcry_hwf_enabled () == false)
+ return 0;
+
+ if (detected == true)
+ return hw_features;
+
+#if defined (__x86_64__) && defined (GRUB_MACHINE_EFI)
+ hw_features = _gcry_hwf_detect_x86 ();
+#endif
+
+ grub_dprintf ("hwfeatures", "Detected features: 0x%x\n", hw_features);
+
+ detected = true;
+
+ return hw_features;
+}
--
2.51.0

View File

@ -0,0 +1,35 @@
From 5698f7c5055ea481d0040ea4495829e5d02781cc Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Fri, 18 Jul 2025 15:34:21 +0800
Subject: [PATCH 2/4] libgcrypt: Declare the sha256 shaext function
There is no prototype of _gcry_sha256_transform_intel_shaext() defined
in the header or libgcrypt-grub/cipher/sha256.c, and gcc may complain
the missing-prototypes error when compiling sha256-intel-shaext.c.
Declare the prototype in sha256-intel-shaext.c to avoid the error.
Signed-off-by: Gary Lin <glin@suse.com>
---
grub-core/lib/libgcrypt-grub/cipher/sha256-intel-shaext.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/grub-core/lib/libgcrypt-grub/cipher/sha256-intel-shaext.c b/grub-core/lib/libgcrypt-grub/cipher/sha256-intel-shaext.c
index 48c09eefe..7ec49f05e 100644
--- a/grub-core/lib/libgcrypt-grub/cipher/sha256-intel-shaext.c
+++ b/grub-core/lib/libgcrypt-grub/cipher/sha256-intel-shaext.c
@@ -95,6 +95,11 @@ typedef struct u128_s
u32 a, b, c, d;
} u128_t;
+
+unsigned int ASM_FUNC_ATTR
+_gcry_sha256_transform_intel_shaext(u32 state[8], const unsigned char *data,
+ size_t nblks);
+
/*
* Transform nblks*64 bytes (nblks*16 32-bit words) at DATA.
*/
--
2.51.0

View File

@ -0,0 +1,43 @@
From 3443b213bb87112144d753678d0f1bbbc72b2b7a Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Fri, 18 Jul 2025 15:23:25 +0800
Subject: [PATCH 3/4] libgcrypt: Add hardware acceleration for gcry_sha256
Enable hardware acceleration for the gcry_sha256 module when building
for the x86_64 EFI target.
Signed-off-by: Gary Lin <glin@suse.com>
---
grub-core/Makefile.gcry.def | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/grub-core/Makefile.gcry.def b/grub-core/Makefile.gcry.def
index c8caf17dc..ac1d9a088 100644
--- a/grub-core/Makefile.gcry.def
+++ b/grub-core/Makefile.gcry.def
@@ -17,6 +17,7 @@ module = {
module = {
name = gcry_blake2;
common = lib/libgcrypt-grub/cipher/blake2.c;
+
cflags = '$(CFLAGS_GCRY)';
cppflags = '$(CPPFLAGS_GCRY)';
};
@@ -172,8 +173,13 @@ module = {
module = {
name = gcry_sha256;
common = lib/libgcrypt-grub/cipher/sha256.c;
+ x86_64_efi = lib/libgcrypt-grub/cipher/sha256-ssse3-amd64.S;
+ x86_64_efi = lib/libgcrypt-grub/cipher/sha256-avx-amd64.S;
+ x86_64_efi = lib/libgcrypt-grub/cipher/sha256-avx2-bmi2-amd64.S;
+ x86_64_efi = lib/libgcrypt-grub/cipher/sha256-intel-shaext.c;
+
cflags = '$(CFLAGS_GCRY) -Wno-cast-align';
- cppflags = '$(CPPFLAGS_GCRY)';
+ cppflags = '$(CPPFLAGS_GCRY) -DUSE_SHA256 $(CPPFLAGS_GCRY_ASM)';
};
module = {
--
2.51.0

View File

@ -0,0 +1,35 @@
From f62c2c7565237bbf059220e90d3f1f8c8d6eebd5 Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Wed, 3 Sep 2025 16:26:55 +0800
Subject: [PATCH 4/4] libgcrypt: Add hardware acceleration for gcry_sha512
Enable hardware acceleration for the gcry_sha512 module when building
for the x86_64 EFI target.
Signed-off-by: Gary Lin <glin@suse.com>
---
grub-core/Makefile.gcry.def | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/grub-core/Makefile.gcry.def b/grub-core/Makefile.gcry.def
index ac1d9a088..64ea5ee24 100644
--- a/grub-core/Makefile.gcry.def
+++ b/grub-core/Makefile.gcry.def
@@ -186,8 +186,13 @@ module = {
name = gcry_sha512;
common = lib/libgcrypt-grub/cipher/sha512.c;
common = lib/libgcrypt-grub/cipher/hash-common.c;
+ x86_64_efi = lib/libgcrypt-grub/cipher/sha512-ssse3-amd64.S;
+ x86_64_efi = lib/libgcrypt-grub/cipher/sha512-avx-amd64.S;
+ x86_64_efi = lib/libgcrypt-grub/cipher/sha512-avx2-bmi2-amd64.S;
+ x86_64_efi = lib/libgcrypt-grub/cipher/sha512-avx512-amd64.S;
+
cflags = '$(CFLAGS_GCRY) -Wno-cast-align';
- cppflags = '$(CPPFLAGS_GCRY)';
+ cppflags = '$(CPPFLAGS_GCRY) -DUSE_SHA512 $(CPPFLAGS_GCRY_ASM)';
};
module = {
--
2.51.0

View File

@ -45,6 +45,7 @@ grub_size_t grub_relocator_align = sizeof (grub_uint32_t);
grub_size_t grub_relocator_forward_size; grub_size_t grub_relocator_forward_size;
grub_size_t grub_relocator_backward_size; grub_size_t grub_relocator_backward_size;
grub_size_t grub_relocator_jumper_size = JUMP_SIZEOF + REGW_SIZEOF; grub_size_t grub_relocator_jumper_size = JUMP_SIZEOF + REGW_SIZEOF;
grub_size_t grub_relocator_preamble_size = 0;
void void
grub_cpu_relocator_init (void) grub_cpu_relocator_init (void)
@ -53,6 +54,11 @@ grub_cpu_relocator_init (void)
grub_relocator_backward_size = RELOCATOR_SIZEOF(backward); grub_relocator_backward_size = RELOCATOR_SIZEOF(backward);
} }
void
grub_cpu_relocator_preamble (void *rels __attribute__ ((unused)))
{
}
static void static void
write_reg (int regn, grub_uint32_t val, void **target) write_reg (int regn, grub_uint32_t val, void **target)
{ {

View File

@ -39,6 +39,7 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
unsigned int c, unsigned int c,
grub_uint8_t *DK, grub_size_t dkLen) grub_uint8_t *DK, grub_size_t dkLen)
{ {
struct grub_crypto_hmac_handle *hnd = NULL;
unsigned int hLen = md->mdlen; unsigned int hLen = md->mdlen;
grub_uint8_t U[GRUB_CRYPTO_MAX_MDLEN]; grub_uint8_t U[GRUB_CRYPTO_MAX_MDLEN];
grub_uint8_t T[GRUB_CRYPTO_MAX_MDLEN]; grub_uint8_t T[GRUB_CRYPTO_MAX_MDLEN];
@ -47,7 +48,6 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
unsigned int r; unsigned int r;
unsigned int i; unsigned int i;
unsigned int k; unsigned int k;
gcry_err_code_t rc;
grub_uint8_t *tmp; grub_uint8_t *tmp;
grub_size_t tmplen = Slen + 4; grub_size_t tmplen = Slen + 4;
@ -72,6 +72,13 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
grub_memcpy (tmp, S, Slen); grub_memcpy (tmp, S, Slen);
hnd = grub_crypto_hmac_init (md, P, Plen);
if (hnd == NULL)
{
grub_free (tmp);
return GPG_ERR_OUT_OF_MEMORY;
}
for (i = 1; i - 1 < l; i++) for (i = 1; i - 1 < l; i++)
{ {
grub_memset (T, 0, hLen); grub_memset (T, 0, hLen);
@ -85,16 +92,13 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
tmp[Slen + 2] = (i & 0x0000ff00) >> 8; tmp[Slen + 2] = (i & 0x0000ff00) >> 8;
tmp[Slen + 3] = (i & 0x000000ff) >> 0; tmp[Slen + 3] = (i & 0x000000ff) >> 0;
rc = grub_crypto_hmac_buffer (md, P, Plen, tmp, tmplen, U); grub_crypto_hmac_write (hnd, tmp, tmplen);
} }
else else
rc = grub_crypto_hmac_buffer (md, P, Plen, U, hLen, U); grub_crypto_hmac_write (hnd, U, hLen);
if (rc != GPG_ERR_NO_ERROR) grub_crypto_hmac_final (hnd, U);
{ grub_crypto_hmac_reset (hnd);
grub_free (tmp);
return rc;
}
for (k = 0; k < hLen; k++) for (k = 0; k < hLen; k++)
T[k] ^= U[k]; T[k] ^= U[k];
@ -103,6 +107,7 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
grub_memcpy (DK + (i - 1) * hLen, T, i == l ? r : hLen); grub_memcpy (DK + (i - 1) * hLen, T, i == l ? r : hLen);
} }
grub_crypto_hmac_free (hnd);
grub_free (tmp); grub_free (tmp);
return GPG_ERR_NO_ERROR; return GPG_ERR_NO_ERROR;

View File

@ -43,6 +43,7 @@ grub_size_t grub_relocator_align = sizeof (grub_uint32_t);
grub_size_t grub_relocator_forward_size; grub_size_t grub_relocator_forward_size;
grub_size_t grub_relocator_backward_size; grub_size_t grub_relocator_backward_size;
grub_size_t grub_relocator_jumper_size = JUMP_SIZEOF + REGW_SIZEOF; grub_size_t grub_relocator_jumper_size = JUMP_SIZEOF + REGW_SIZEOF;
grub_size_t grub_relocator_preamble_size = 0;
void void
grub_cpu_relocator_init (void) grub_cpu_relocator_init (void)
@ -51,6 +52,11 @@ grub_cpu_relocator_init (void)
grub_relocator_backward_size = RELOCATOR_SIZEOF(backward); grub_relocator_backward_size = RELOCATOR_SIZEOF(backward);
} }
void
grub_cpu_relocator_preamble (void *rels __attribute__((unused)))
{
}
static void static void
write_reg (int regn, grub_uint32_t val, void **target) write_reg (int regn, grub_uint32_t val, void **target)
{ {

View File

@ -110,7 +110,7 @@ grub_relocator_new (void)
return NULL; return NULL;
ret->postchunks = ~(grub_phys_addr_t) 0; ret->postchunks = ~(grub_phys_addr_t) 0;
ret->relocators_size = grub_relocator_jumper_size; ret->relocators_size = grub_relocator_jumper_size + grub_relocator_preamble_size;
grub_dprintf ("relocator", "relocators_size=%lu\n", grub_dprintf ("relocator", "relocators_size=%lu\n",
(unsigned long) ret->relocators_size); (unsigned long) ret->relocators_size);
return ret; return ret;
@ -398,9 +398,9 @@ free_subchunk (const struct grub_relocator_subchunk *subchu)
if (subchu->post) if (subchu->post)
{ {
int off = subchu->start + subchu->size - fend; int off = subchu->start + subchu->size - fend;
grub_memset (subchu->pre->freebytes, grub_memset (subchu->post->freebytes,
0xff, sizeof (subchu->pre->freebytes) - off / 8); 0xff, sizeof (subchu->post->freebytes) - off / 8 - 1);
subchu->pre->freebytes[off / 8] |= ((1 << (8 - (off % 8))) - 1); subchu->post->freebytes[sizeof (subchu->post->freebytes) - off / 8 - 1] |= ((1 << (8 - (off % 8))) - 1);
check_leftover (subchu->post); check_leftover (subchu->post);
} }
#endif #endif
@ -1605,6 +1605,9 @@ grub_relocator_prepare_relocs (struct grub_relocator *rel, grub_addr_t addr,
grub_free (to); grub_free (to);
} }
grub_cpu_relocator_preamble (rels);
rels += grub_relocator_preamble_size;
for (j = 0; j < nchunks; j++) for (j = 0; j < nchunks; j++)
{ {
grub_dprintf ("relocator", "sorted chunk %p->%p, 0x%lx\n", grub_dprintf ("relocator", "sorted chunk %p->%p, 0x%lx\n",

View File

@ -23,6 +23,8 @@
#include <grub/err.h> #include <grub/err.h>
#include <grub/types.h> #include <grub/types.h>
#define GRUB_EV_SEPARATOR 0x04
extern grub_err_t extern grub_err_t
grub_tcg2_get_max_output_size (grub_size_t *size); grub_tcg2_get_max_output_size (grub_size_t *size);
@ -32,4 +34,7 @@ grub_tcg2_submit_command (grub_size_t input_size,
grub_size_t output_size, grub_size_t output_size,
grub_uint8_t *output); grub_uint8_t *output);
extern grub_err_t
grub_tcg2_cap_pcr (grub_uint8_t pcr);
#endif /* ! GRUB_TPM2_TCG2_HEADER */ #endif /* ! GRUB_TPM2_TCG2_HEADER */

View File

@ -22,6 +22,7 @@
#include <tss2_buffer.h> #include <tss2_buffer.h>
#include <tss2_structs.h> #include <tss2_structs.h>
#include <tpm2_cmd.h>
#include <tcg2.h> #include <tcg2.h>
grub_err_t grub_err_t
@ -47,3 +48,22 @@ grub_tcg2_submit_command (grub_size_t input_size, grub_uint8_t *input,
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
grub_err_t
grub_tcg2_cap_pcr (grub_uint8_t pcr)
{
TPMS_AUTH_COMMAND_t authCmd = {
.sessionHandle = TPM_RS_PW,
};
TPM2B_EVENT_t data = {
.size = 4,
};
TPM_RC_t rc;
/* Submit an EV_SEPARATOR event, i.e. an event with 4 zero-bytes */
rc = grub_tpm2_pcr_event (pcr, &authCmd, &data, NULL, NULL);
if (rc != TPM_RC_SUCCESS)
return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot cap PCR %u"), pcr);
return GRUB_ERR_NONE;
}

View File

@ -89,6 +89,7 @@ tpm2_submit_command (const TPMI_ST_COMMAND_TAG_t tag,
/* Catch TPM_RC_RETRY and send the command again */ /* Catch TPM_RC_RETRY and send the command again */
do { do {
grub_tpm2_buffer_init (out);
err = tpm2_submit_command_real (tag, commandCode, responseCode, in, out); err = tpm2_submit_command_real (tag, commandCode, responseCode, in, out);
if (*responseCode != TPM_RC_RETRY) if (*responseCode != TPM_RC_RETRY)
break; break;
@ -167,7 +168,6 @@ grub_tpm2_createprimary (const TPMI_RH_HIERARCHY_t primaryHandle,
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (tag, TPM_CC_CreatePrimary, &responseCode, &in, &out); rc = tpm2_submit_command (tag, TPM_CC_CreatePrimary, &responseCode, &in, &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
return rc; return rc;
@ -250,7 +250,6 @@ grub_tpm2_startauthsession (const TPMI_DH_OBJECT_t tpmKey,
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (tag, TPM_CC_StartAuthSession, &responseCode, rc = tpm2_submit_command (tag, TPM_CC_StartAuthSession, &responseCode,
&in, &out); &in, &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
@ -308,7 +307,6 @@ grub_tpm2_policypcr (const TPMI_SH_POLICY_t policySessions,
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (tag, TPM_CC_PolicyPCR, &responseCode, &in, &out); rc = tpm2_submit_command (tag, TPM_CC_PolicyPCR, &responseCode, &in, &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
return rc; return rc;
@ -347,7 +345,6 @@ grub_tpm2_readpublic (const TPMI_DH_OBJECT_t objectHandle,
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (tag, TPM_CC_ReadPublic, &responseCode, &in, &out); rc = tpm2_submit_command (tag, TPM_CC_ReadPublic, &responseCode, &in, &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
return rc; return rc;
@ -408,7 +405,6 @@ grub_tpm2_load (const TPMI_DH_OBJECT_t parent_handle,
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (tag, TPM_CC_Load, &responseCode, &in, &out); rc = tpm2_submit_command (tag, TPM_CC_Load, &responseCode, &in, &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
return rc; return rc;
@ -475,7 +471,6 @@ grub_tpm2_loadexternal (const TPMS_AUTH_COMMAND_t *authCommand,
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (tag, TPM_CC_LoadExternal, &responseCode, &in, &out); rc = tpm2_submit_command (tag, TPM_CC_LoadExternal, &responseCode, &in, &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
return rc; return rc;
@ -527,7 +522,6 @@ grub_tpm2_unseal (const TPMI_DH_OBJECT_t itemHandle,
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (tag, TPM_CC_Unseal, &responseCode, &in, &out); rc = tpm2_submit_command (tag, TPM_CC_Unseal, &responseCode, &in, &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
return rc; return rc;
@ -561,7 +555,6 @@ grub_tpm2_flushcontext (const TPMI_DH_CONTEXT_t handle)
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (TPM_ST_NO_SESSIONS, TPM_CC_FlushContext, &responseCode, &in, &out); rc = tpm2_submit_command (TPM_ST_NO_SESSIONS, TPM_CC_FlushContext, &responseCode, &in, &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
return rc; return rc;
@ -575,6 +568,56 @@ grub_tpm2_flushcontext (const TPMI_DH_CONTEXT_t handle)
return TPM_RC_SUCCESS; return TPM_RC_SUCCESS;
} }
TPM_RC_t
grub_tpm2_pcr_event (const TPMI_DH_PCR_t pcrHandle,
const TPMS_AUTH_COMMAND_t *authCommand,
const TPM2B_EVENT_t *eventData,
TPML_DIGEST_VALUES_t *digests,
TPMS_AUTH_RESPONSE_t *authResponse)
{
TPM_RC_t rc;
struct grub_tpm2_buffer in;
struct grub_tpm2_buffer out;
TPML_DIGEST_VALUES_t digestsTmp;
TPMS_AUTH_RESPONSE_t authResponseTmp;
TPM_RC_t responseCode;
grub_uint32_t parameterSize;
if (eventData == NULL)
return TPM_RC_VALUE;
if (authCommand == NULL)
return TPM_RC_VALUE;
if (digests == NULL)
digests = &digestsTmp;
if (authResponse == NULL)
authResponse = &authResponseTmp;
/* Marshal */
grub_tpm2_buffer_init (&in);
grub_tpm2_buffer_pack_u32 (&in, pcrHandle);
grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
grub_Tss2_MU_TPM2B_Marshal (&in, eventData->size, eventData->buffer);
if (in.error == true)
return TPM_RC_FAILURE;
/* Submit */
rc = tpm2_submit_command (TPM_ST_SESSIONS, TPM_CC_PCR_Event, &responseCode, &in, &out);
if (rc != TPM_RC_SUCCESS)
return rc;
if (responseCode != TPM_RC_SUCCESS)
return responseCode;
/* Unmarshal */
grub_tpm2_buffer_unpack_u32 (&out, &parameterSize);
grub_Tss2_MU_TPML_DIGEST_VALUE_Unmarshal (&out, digests);
grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse);
if (out.error == true)
return TPM_RC_FAILURE;
return TPM_RC_SUCCESS;
}
TPM_RC_t TPM_RC_t
grub_tpm2_pcr_read (const TPMS_AUTH_COMMAND_t *authCommand, grub_tpm2_pcr_read (const TPMS_AUTH_COMMAND_t *authCommand,
const TPML_PCR_SELECTION_t *pcrSelectionIn, const TPML_PCR_SELECTION_t *pcrSelectionIn,
@ -615,7 +658,6 @@ grub_tpm2_pcr_read (const TPMS_AUTH_COMMAND_t *authCommand,
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (tag, TPM_CC_PCR_Read, &responseCode, &in, &out); rc = tpm2_submit_command (tag, TPM_CC_PCR_Read, &responseCode, &in, &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
return rc; return rc;
@ -668,7 +710,6 @@ grub_tpm2_policygetdigest (const TPMI_SH_POLICY_t policySession,
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (tag, TPM_CC_PolicyGetDigest, &responseCode, &in, &out); rc = tpm2_submit_command (tag, TPM_CC_PolicyGetDigest, &responseCode, &in, &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
return rc; return rc;
@ -751,7 +792,6 @@ grub_tpm2_create (const TPMI_DH_OBJECT_t parentHandle,
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (tag, TPM_CC_Create, &responseCode, &in, &out); rc = tpm2_submit_command (tag, TPM_CC_Create, &responseCode, &in, &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
return rc; return rc;
@ -805,7 +845,6 @@ grub_tpm2_evictcontrol (const TPMI_RH_PROVISION_t auth,
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (tag, TPM_CC_EvictControl, &responseCode, &in, &out); rc = tpm2_submit_command (tag, TPM_CC_EvictControl, &responseCode, &in, &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
return rc; return rc;
@ -871,7 +910,6 @@ grub_tpm2_hash (const TPMS_AUTH_COMMAND_t *authCommand,
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (tag, TPM_CC_Hash, &responseCode, &in, &out); rc = tpm2_submit_command (tag, TPM_CC_Hash, &responseCode, &in, &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
return rc; return rc;
@ -930,7 +968,6 @@ grub_tpm2_verifysignature (const TPMI_DH_OBJECT_t keyHandle,
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (tag, TPM_CC_VerifySignature, &responseCode, &in, &out); rc = tpm2_submit_command (tag, TPM_CC_VerifySignature, &responseCode, &in, &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
return rc; return rc;
@ -990,7 +1027,6 @@ grub_tpm2_policyauthorize (const TPMI_SH_POLICY_t policySession,
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (tag, TPM_CC_PolicyAuthorize, &responseCode, &in, &out); rc = tpm2_submit_command (tag, TPM_CC_PolicyAuthorize, &responseCode, &in, &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
return rc; return rc;
@ -1031,7 +1067,6 @@ grub_tpm2_testparms (const TPMT_PUBLIC_PARMS_t *parms,
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (tag, TPM_CC_TestParms, &responseCode, &in, rc = tpm2_submit_command (tag, TPM_CC_TestParms, &responseCode, &in,
&out); &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
@ -1075,7 +1110,6 @@ grub_tpm2_nv_definespace (const TPMI_RH_PROVISION_t authHandle,
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (tag, TPM_CC_NV_DefineSpace, &responseCode, &in, &out); rc = tpm2_submit_command (tag, TPM_CC_NV_DefineSpace, &responseCode, &in, &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
return rc; return rc;
@ -1110,7 +1144,6 @@ grub_tpm2_nv_undefinespace (const TPMI_RH_PROVISION_t authHandle,
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (tag, TPM_CC_NV_UndefineSpace, &responseCode, &in, &out); rc = tpm2_submit_command (tag, TPM_CC_NV_UndefineSpace, &responseCode, &in, &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
return rc; return rc;
@ -1146,7 +1179,6 @@ grub_tpm2_nv_readpublic (const TPMI_RH_NV_INDEX_t nvIndex,
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (tag, TPM_CC_NV_ReadPublic, &responseCode, &in, &out); rc = tpm2_submit_command (tag, TPM_CC_NV_ReadPublic, &responseCode, &in, &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
return rc; return rc;
@ -1191,7 +1223,6 @@ grub_tpm2_nv_read (const TPMI_RH_NV_AUTH_t authHandle,
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (tag, TPM_CC_NV_Read, &responseCode, &in, &out); rc = tpm2_submit_command (tag, TPM_CC_NV_Read, &responseCode, &in, &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
return rc; return rc;
@ -1233,7 +1264,6 @@ grub_tpm2_nv_write (const TPMI_RH_NV_AUTH_t authHandle,
return TPM_RC_FAILURE; return TPM_RC_FAILURE;
/* Submit */ /* Submit */
grub_tpm2_buffer_init (&out);
rc = tpm2_submit_command (tag, TPM_CC_NV_Write, &responseCode, &in, &out); rc = tpm2_submit_command (tag, TPM_CC_NV_Write, &responseCode, &in, &out);
if (rc != TPM_RC_SUCCESS) if (rc != TPM_RC_SUCCESS)
return rc; return rc;

View File

@ -89,6 +89,13 @@ grub_tpm2_unseal (const TPMI_DH_OBJECT_t item_handle,
extern TPM_RC_t extern TPM_RC_t
grub_tpm2_flushcontext (const TPMI_DH_CONTEXT_t handle); grub_tpm2_flushcontext (const TPMI_DH_CONTEXT_t handle);
extern TPM_RC_t
grub_tpm2_pcr_event (const TPMI_DH_PCR_t pcrHandle,
const TPMS_AUTH_COMMAND_t *authCommand,
const TPM2B_EVENT_t *eventData,
TPML_DIGEST_VALUES_t *digests,
TPMS_AUTH_RESPONSE_t *authResponse);
extern TPM_RC_t extern TPM_RC_t
grub_tpm2_pcr_read (const TPMS_AUTH_COMMAND_t *authCommand, grub_tpm2_pcr_read (const TPMS_AUTH_COMMAND_t *authCommand,
const TPML_PCR_SELECTION_t *pcrSelectionIn, const TPML_PCR_SELECTION_t *pcrSelectionIn,

View File

@ -1118,6 +1118,24 @@ grub_Tss2_MU_TPML_DIGEST_Unmarshal (grub_tpm2_buffer_t buffer,
grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (buffer, &digest->digests[i]); grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (buffer, &digest->digests[i]);
} }
void
grub_Tss2_MU_TPML_DIGEST_VALUE_Unmarshal (grub_tpm2_buffer_t buffer,
TPML_DIGEST_VALUES_t *digests)
{
grub_uint32_t i;
grub_tpm2_buffer_unpack_u32 (buffer, &digests->count);
if (digests->count > TPM_NUM_PCR_BANKS)
{
buffer->error = true;
return;
}
for (i = 0; i < digests->count; i++)
grub_Tss2_MU_TPMT_HA_Unmarshal (buffer, &digests->digests[i]);
}
void void
grub_Tss2_MU_TPMS_SIGNATURE_RSA_Unmarshal (grub_tpm2_buffer_t buffer, grub_Tss2_MU_TPMS_SIGNATURE_RSA_Unmarshal (grub_tpm2_buffer_t buffer,
TPMS_SIGNATURE_RSA_t *rsa) TPMS_SIGNATURE_RSA_t *rsa)

View File

@ -380,6 +380,10 @@ extern void
grub_Tss2_MU_TPML_DIGEST_Unmarshal (grub_tpm2_buffer_t buffer, grub_Tss2_MU_TPML_DIGEST_Unmarshal (grub_tpm2_buffer_t buffer,
TPML_DIGEST_t *digest); TPML_DIGEST_t *digest);
extern void
grub_Tss2_MU_TPML_DIGEST_VALUE_Unmarshal (grub_tpm2_buffer_t buffer,
TPML_DIGEST_VALUES_t *digests);
extern void extern void
grub_Tss2_MU_TPMS_SIGNATURE_RSA_Unmarshal (grub_tpm2_buffer_t buffer, grub_Tss2_MU_TPMS_SIGNATURE_RSA_Unmarshal (grub_tpm2_buffer_t buffer,
TPMS_SIGNATURE_RSA_t *p); TPMS_SIGNATURE_RSA_t *p);

View File

@ -144,6 +144,13 @@ typedef struct TPML_DIGEST TPML_DIGEST_t;
/* TPM2B_NONCE Type */ /* TPM2B_NONCE Type */
typedef TPM2B_DIGEST_t TPM2B_NONCE_t; typedef TPM2B_DIGEST_t TPM2B_NONCE_t;
/* TPM2B_EVENT Structure */
struct TPM2B_EVENT {
grub_uint16_t size;
grub_uint8_t buffer[1024];
};
typedef struct TPM2B_EVENT TPM2B_EVENT_t;
/* TPMA_SESSION Structure */ /* TPMA_SESSION Structure */
struct TPMA_SESSION struct TPMA_SESSION
{ {

View File

@ -343,6 +343,7 @@ typedef grub_uint32_t TPM_CC_t;
#define TPM_CC_NV_Write ((TPM_CC_t) 0x00000137) #define TPM_CC_NV_Write ((TPM_CC_t) 0x00000137)
#define TPM_CC_NV_UndefineSpace ((TPM_CC_t) 0x00000122) #define TPM_CC_NV_UndefineSpace ((TPM_CC_t) 0x00000122)
#define TPM_CC_GetCapability ((TPM_CC_t) 0x0000017a) #define TPM_CC_GetCapability ((TPM_CC_t) 0x0000017a)
#define TPM_CC_PCR_Event ((TPM_CC_t) 0x0000013c)
#define TPM_CC_PCR_Read ((TPM_CC_t) 0x0000017e) #define TPM_CC_PCR_Read ((TPM_CC_t) 0x0000017e)
#define TPM_CC_Load ((TPM_CC_t) 0x00000157) #define TPM_CC_Load ((TPM_CC_t) 0x00000157)
#define TPM_CC_LoadExternal ((TPM_CC_t) 0x00000167) #define TPM_CC_LoadExternal ((TPM_CC_t) 0x00000167)

View File

@ -0,0 +1,246 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2025 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 <grub/types.h>
#include <grub/x86_64/efi/hwfeatures-gcry.h>
#include <grub/x86_64/cpuid.h>
#include <grub/misc.h>
/*
* Older versions of GCC may reorder the inline asm, which can lead to
* unexpected behavior when reading the Control Registers. The __FORCE_ORDER
* macro is used to prevent this.
*
* Ref: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=aa5cacdc29d76a005cbbee018a47faa6e724dd2d
*/
#define __FORCE_ORDER "m"(*(unsigned int *) 0x1000UL)
#define HW_FEATURE_X86_64_SSE (1 << 0)
#define HW_FEATURE_X86_64_AVX (1 << 1)
static grub_uint32_t hw_features = 0;
static grub_uint64_t old_cr0, old_cr4, old_xcr0;
static grub_uint64_t
read_cr0 (void)
{
grub_uint64_t val;
asm volatile ("mov %%cr0, %0" : "=r" (val) : __FORCE_ORDER);
return val;
}
static grub_uint64_t
read_cr4 (void)
{
grub_uint64_t val;
asm volatile ("mov %%cr4,%0" : "=r" (val) : __FORCE_ORDER);
return val;
}
static void
write_cr0 (grub_uint64_t val)
{
asm volatile ("mov %0,%%cr4": "+r" (val) : : "memory");
}
static void
write_cr4 (grub_uint64_t val)
{
asm volatile ("mov %0,%%cr4": "+r" (val) : : "memory");
}
static grub_uint32_t
get_cpuid_ecx (void)
{
grub_uint32_t eax, ebx, ecx, edx;
grub_cpuid (1, eax, ebx, ecx, edx);
return ecx;
}
static grub_uint32_t
get_cpuid_edx (void)
{
grub_uint32_t eax, ebx, ecx, edx;
grub_cpuid (1, eax, ebx, ecx, edx);
return edx;
}
static bool
enable_sse (void)
{
grub_uint64_t cr0, cr4;
grub_uint32_t edx;
edx = get_cpuid_edx ();
/* Check CPUID.01H:EDX.FXSR[bit 24] and CPUID.01H:EDX.SSE[bit 25] */
if ((edx & (3 << 24)) != (3 << 24))
return false;
cr0 = old_cr0 = read_cr0 ();
cr4 = old_cr4 = read_cr4 ();
/* clear CR0.EM[bit 2] */
if ((cr0 & (1 << 2)) != 0)
cr0 &= ~(1 << 2);
/* Set CR0.MP[bit 1] */
if ((cr0 & (1 << 1)) == 0)
cr0 |= (1 << 1);
grub_dprintf ("hwfeatures", "CR0: 0x%"PRIxGRUB_UINT64_T" 0x%"PRIxGRUB_UINT64_T"\n", old_cr0, cr0);
if (old_cr0 != cr0)
write_cr0 (cr0);
/* Set CR4.OSFXSR[bit 9] and CR4.OSXMMEXCPT[bit 10] */
if ((cr4 & (3 << 9)) != (3 << 9))
cr4 |= (3 << 9);
grub_dprintf ("hwfeatures", "CR4: 0x%"PRIxGRUB_UINT64_T" 0x%"PRIxGRUB_UINT64_T"\n", old_cr4, cr4);
if (old_cr4 != cr4)
write_cr4 (cr4);
return true;
}
static grub_uint64_t
xgetbv (grub_uint32_t index)
{
grub_uint32_t eax, edx;
asm volatile ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (index));
return eax + ((grub_uint64_t)edx << 32);
}
static void
xsetbv (grub_uint32_t index, grub_uint64_t value)
{
grub_uint32_t eax = (grub_uint32_t)value;
grub_uint32_t edx = (grub_uint32_t)(value >> 32);
asm volatile ("xsetbv" :: "a" (eax), "d" (edx), "c" (index));
}
static bool
enable_avx (void)
{
grub_uint64_t cr4;
grub_uint32_t ecx;
grub_uint64_t sse_avx_mask = (1 << 2) | (1 << 1);
grub_uint64_t xcr0;
ecx = get_cpuid_ecx ();
/* Check the following two bits
* - CPUID.01H:ECX.XSAVE[bit 26]
* If XSAVE is not supported, setting CR4.OSXSAVE will cause
* general-protection fault (#GP).
* - CPUID.01H:ECX.AVX[bit 28]
*/
grub_dprintf ("hwfeatures", "Check CPUID.01H:ECX 0x%"PRIuGRUB_UINT32_T"\n", ecx);
if ((ecx & (5 << 26)) != (5 << 26))
return false;
cr4 = read_cr4 ();
/* Set CR4.OSXSAVE[bit 18] */
if ((cr4 & (1 << 18)) == 0)
{
grub_dprintf ("hwfeatures", "Set CR4.OSXSAVE\n");
cr4 |= 1 << 18;
write_cr4 (cr4);
}
ecx = get_cpuid_ecx ();
/* Check CPUID.01H:ECX.OSXSAVE[bit 27] */
if ((ecx & (1 << 27)) == 0)
return false;
xcr0 = old_xcr0 = xgetbv (0);
/* Set XCR0[bit 1] and XCR0[bit 2] to enable SSE/AVX */
if ((xcr0 & sse_avx_mask) != sse_avx_mask)
{
grub_dprintf ("hwfeatures", "Set XCR0[2:1] to 11b\n");
xcr0 |= sse_avx_mask;
xsetbv (0, xcr0);
}
return true;
}
void
grub_enable_gcry_hwf_x86_64_efi (void)
{
if (enable_sse () == true)
hw_features |= HW_FEATURE_X86_64_SSE;
if (enable_avx () == true)
hw_features |= HW_FEATURE_X86_64_AVX;
}
void
grub_reset_gcry_hwf_x86_64_efi (void)
{
grub_uint64_t cr0, cr4, xcr0;
if ((hw_features & HW_FEATURE_X86_64_AVX) != 0)
{
xcr0 = xgetbv (0);
if (xcr0 != old_xcr0)
{
/*
* Reset the AVX state with 'vzeroupper' before clearing XCR0[bit 2].
*
* Ref: Intel 64 and IA-32 Architectures Software Developer's Manual
* - 13.3 ENABLING THE XSAVE FEATURE SET AND XSAVE-ENABLED FEATURES
*
* "As noted in Section 13.1, the processor will preserve AVX state
* unmodified if software clears XCR0[2]. However, clearing XCR0[2]
* while AVX state is not in its initial configuration may cause SSE
* instructions to incur a power and performance penalty."
*/
asm volatile ("vzeroupper" ::: "memory");
xsetbv (0, old_xcr0);
}
}
if ((hw_features & HW_FEATURE_X86_64_AVX) != 0 || (hw_features & HW_FEATURE_X86_64_SSE) != 0)
{
cr4 = read_cr4 ();
if (cr4 != old_cr4)
write_cr4 (old_cr4);
}
if ((hw_features & HW_FEATURE_X86_64_SSE) != 0)
{
cr0 = read_cr0 ();
if (cr0 != old_cr0)
write_cr0 (old_cr0);
}
hw_features = 0;
}

View File

@ -36,7 +36,7 @@ GRUB_MOD_LICENSE "GPLv3+"
*/ */
FUNCTION(grub_setjmp) FUNCTION(grub_setjmp)
pop %rsi /* Return address, and adjust the stack */ pop %rsi /* Return address, and adjust the stack */
xorq %rax, %rax xorl %eax, %eax
movq %rbx, 0(%rdi) /* RBX */ movq %rbx, 0(%rdi) /* RBX */
movq %rsp, 8(%rdi) /* RSP */ movq %rsp, 8(%rdi) /* RSP */
push %rsi push %rsi

View File

@ -387,8 +387,7 @@ static enum xz_ret hash_validate(struct xz_dec *s, struct xz_buf *b,
&& sizeof (s->hash_value) >= hash->mdlen) && sizeof (s->hash_value) >= hash->mdlen)
{ {
hash->final(hash_context); hash->final(hash_context);
grub_memcpy (s->hash_value, hash->read(hash_context), memcpy (s->hash_value, hash->read (hash_context), hash->mdlen);
hash->mdlen);
s->have_hash_value = 1; s->have_hash_value = 1;
if (s->hash_id == 1 || crc32) if (s->hash_id == 1 || crc32)
{ {

View File

@ -174,7 +174,7 @@ prepare_xen_module_params (struct xen_boot_binary *module, void *xen_boot_fdt)
module->cmdline, module->cmdline, module->cmdline_size); module->cmdline, module->cmdline, module->cmdline_size);
retval = grub_fdt_set_prop (xen_boot_fdt, module_node, "bootargs", retval = grub_fdt_set_prop (xen_boot_fdt, module_node, "bootargs",
module->cmdline, module->cmdline_size + 1); module->cmdline, module->cmdline_size);
if (retval) if (retval)
return grub_error (GRUB_ERR_IO, "failed to update FDT"); return grub_error (GRUB_ERR_IO, "failed to update FDT");
} }

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