Re: [PATCH 0/2] Two small fixes to gzip
Hi Daniel, > Reviewed-by: Daniel Kiper for both patches... Thank you! > I assume I can add your SOB on your behalf... Oh! Yes! Sorry, 2 years of closed source development have apparently caused me to lose my 'git commit -s' habits! The sign-off for both patches is: Signed-off-by: Daniel Axtens Kind regards, Daniel ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 2/2] gzio: Properly init a table
ARRAY_SIZE is the count of elements, but the element size is 4 bytes, so this was only initing the first 1/4th of the table. Detected with valgrind. This should only matter in error paths, and I've not been able to identify any actual misbehaviour that results from reading in-bounds but uninited data. --- grub-core/io/gzio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c index 8f23a1705..7f7985214 100644 --- a/grub-core/io/gzio.c +++ b/grub-core/io/gzio.c @@ -522,7 +522,7 @@ huft_build (unsigned *b,/* code lengths in bits (all assumed <= BMAX) */ } /* Make a table of values in order of bit lengths */ - grub_memset (v, N_MAX, ARRAY_SIZE (v)); + grub_memset (v, N_MAX, sizeof (v)); p = b; i = 0; do -- 2.39.3 (Apple Git-145) ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 1/2] gzio: abort early when get_byte reads nothing
This isn't intended to be a functional change, but it makes a lot of failures a lot faster, which is extremely helpful for fuzzing. Without this change, we keep trying and trying to read more bytes into our buffer, never being able to (read always returns 0) and so we just return old buffer contents over and over until the decompression process fails some other way. --- grub-core/io/gzio.c | 53 + 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c index 71b2132dc..8f23a1705 100644 --- a/grub-core/io/gzio.c +++ b/grub-core/io/gzio.c @@ -366,6 +366,10 @@ static int dbits = 6; /* bits in base distance lookup table */ lookup of seven bits, the EOB code will be found in that first lookup, and so will not require that too many bits be pulled from the stream. + + Note that NEEDBITS() can fail if the file is corrupt/truncated. + The GOTOFAILIFERROR, RETURNIFERROR and RETURN1IFERROR macros can + help. */ static ush mask_bits[] = @@ -377,10 +381,14 @@ static ush mask_bits[] = #define NEEDBITS(n) do {while(k<(n)){b|=((ulg)get_byte(gzio))<>=(n);k-=(n);} while (0) +#define RETURNIFERROR if (grub_errno != GRUB_ERR_NONE) return +#define RETURN1IFERROR if (grub_errno != GRUB_ERR_NONE) return 1 +#define GOTOFAILIFERROR if (grub_errno != GRUB_ERR_NONE) goto fail static int get_byte (grub_gzio_t gzio) { + grub_ssize_t bytes_read; if (gzio->mem_input) { if (gzio->mem_input_off < gzio->mem_input_size) @@ -393,7 +401,14 @@ get_byte (grub_gzio_t gzio) || gzio->inbuf_d == INBUFSIZ)) { gzio->inbuf_d = 0; - grub_file_read (gzio->file, gzio->inbuf, INBUFSIZ); + bytes_read = grub_file_read (gzio->file, gzio->inbuf, INBUFSIZ); + /* Only trigger if we get 0 bytes: if we get negative bytes there should + * be an existing grub error code that we don't want to overwrite. */ + if (bytes_read == 0) + { + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "File is too short"); + return 0; + } } return gzio->inbuf[gzio->inbuf_d++]; @@ -684,7 +699,7 @@ inflate_codes_in_window (grub_gzio_t gzio) return 1; } - NEEDBITS ((unsigned) gzio->bl); + NEEDBITS ((unsigned) gzio->bl); RETURN1IFERROR; if ((e = (t = gzio->tl + ((unsigned) b & ml))->e) > 16) do { @@ -696,7 +711,7 @@ inflate_codes_in_window (grub_gzio_t gzio) } DUMPBITS (t->b); e -= 16; - NEEDBITS (e); + NEEDBITS (e); RETURN1IFERROR; } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); DUMPBITS (t->b); @@ -718,7 +733,7 @@ inflate_codes_in_window (grub_gzio_t gzio) } /* get length of block to copy */ - NEEDBITS (e); + NEEDBITS (e); RETURN1IFERROR; n = t->v.n + ((unsigned) b & mask_bits[e]); DUMPBITS (e); @@ -729,7 +744,7 @@ inflate_codes_in_window (grub_gzio_t gzio) } /* decode distance of block to copy */ - NEEDBITS ((unsigned) gzio->bd); + NEEDBITS ((unsigned) gzio->bd); RETURN1IFERROR; if ((e = (t = gzio->td + ((unsigned) b & md))->e) > 16) do { @@ -741,12 +756,12 @@ inflate_codes_in_window (grub_gzio_t gzio) } DUMPBITS (t->b); e -= 16; - NEEDBITS (e); + NEEDBITS (e); RETURN1IFERROR; } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); DUMPBITS (t->b); - NEEDBITS (e); + NEEDBITS (e); RETURN1IFERROR; d = w - t->v.n - ((unsigned) b & mask_bits[e]); DUMPBITS (e); gzio->code_state++; @@ -815,10 +830,10 @@ init_stored_block (grub_gzio_t gzio) DUMPBITS (k & 7); /* get the length and its complement */ - NEEDBITS (16); + NEEDBITS (16); RETURNIFERROR; gzio->block_len = ((unsigned) b & 0x); DUMPBITS (16); - NEEDBITS (16); + NEEDBITS (16); RETURNIFERROR; if (gzio->block_len != (int) ((~b) & 0x)) grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "the length of a stored block does not match"); @@ -900,13 +915,13 @@ init_dynamic_block (grub_gzio_t gzio) k = gzio->bk; /* read in table lengths */ - NEEDBITS (5); + NEEDBITS (5); RETURNIFERROR; nl = 257 + ((unsigned) b & 0x1f);/* number of literal/length codes */ DUMPBITS (5); - NEEDBITS (5); + NEEDBITS (5); RETURNIFERROR; nd = 1 + ((unsigned) b & 0x1f); /* number of distance codes */ DUMPBITS (5); - NEEDBITS (4); + NEEDBITS (4); RETURNIFERROR; nb = 4 + ((unsigned) b & 0xf); /* number
[PATCH 0/2] Two small fixes to gzip
I've been fuzzing gzip a bit. So far nothing super exciting, but it's helpful to add some code to bail early on EOF (patch 1) and to avoid some uninitialised data warnings from valgrind (patch 2). I'm not aware of any security implications of either change, and the gzip compression test still passes. Daniel Axtens (2): gzio: abort early when get_byte reads nothing gzio: Properly init a table grub-core/io/gzio.c | 55 - 1 file changed, 35 insertions(+), 20 deletions(-) -- 2.39.3 (Apple Git-145) ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH v8 0/2] Introduce EROFS support
Hi, > > Could you help have another look at this latest version? > Is it ready for merging (Yifan has been working on for almost one year > in his leisure time) so that kernel/initrd can be loaded then.. > Any comment would be much helpful. > I am doing this in my leisure time too - I appreciate your patience and sorry it’s taking a while! Thanks for the new version. I can confirm that I no longer see the ASAN issues I identified on v9. I had one other “maybe” finding. There’s a potentially very large allocation in the symlink code: + if (grub_add (erofs_inode_file_size (node), 1, )) +{ + grub_error (GRUB_ERR_OUT_OF_RANGE, N_ ("overflow is detected")); + return NULL; +} + + symlink = grub_malloc (sz); + if (!symlink) +return NULL; I don’t know if this is actually wrong or if the filesystem spec permits the size here to be very large. At any rate if the memory allocation cannot be satisfied the grub allocator will return NULL which you catch correctly. I’m not sure if this needs any change, but I wanted to bring it to your attention anyway just in case. I found no crash issues in the fuzzers not running ASAN. In total, there were over 14 billion executions of a basic fuzz harness over about 7 days. I’m rerunning the fuzzers with the new build but I don’t expect anything will pop up. Congratulations, as far as I can tell, your filesystem implementation is one of the most safe against arbitrary input in all of grub. For this series: Tested-by: Daniel Axtens mailto:d...@axtens.net>> # fuzz testing only Kind regards, Daniel > Thanks, > Gao Xiang > >> Yifan Zhao (2): >> fs/erofs: Add support for EROFS >> fs/erofs: Add tests for EROFS in grub-fs-tester >> .gitignore | 1 + >> INSTALL | 8 +- >> Makefile.util.def| 7 + >> docs/grub.texi | 3 +- >> grub-core/Makefile.core.def | 5 + >> grub-core/fs/erofs.c | 984 +++ >> grub-core/kern/misc.c| 14 + >> include/grub/misc.h | 1 + >> tests/erofs_test.in | 20 + >> tests/util/grub-fs-tester.in | 32 +- >> 10 files changed, 1063 insertions(+), 12 deletions(-) >> create mode 100644 grub-core/fs/erofs.c >> create mode 100644 tests/erofs_test.in >> Interdiff against v7: >> diff --git a/grub-core/fs/erofs.c b/grub-core/fs/erofs.c >> index 5b89b7924..13f92e71a 100644 >> --- a/grub-core/fs/erofs.c >> +++ b/grub-core/fs/erofs.c >> @@ -101,6 +101,7 @@ struct grub_erofs_inode_chunk_info >>#define EROFS_NULL_ADDR 1 >> #define EROFS_NAME_LEN 255 >> +#define EROFS_MIN_LOG2_BLOCK_SIZE 9 >> #define EROFS_MAX_LOG2_BLOCK_SIZE 16 >>struct grub_erofs_inode_chunk_index >> @@ -558,7 +559,7 @@ erofs_iterate_dir (grub_fshelp_node_t dir, >> grub_fshelp_iterate_dir_hook_t hook, >> goto not_found; >> nameoff = grub_le_to_cpu16 (de->nameoff); >> - if (nameoff < sizeof (struct grub_erofs_dirent) || nameoff > maxsize) >> + if (nameoff < sizeof (struct grub_erofs_dirent) || nameoff >= maxsize) >> { >>grub_error (GRUB_ERR_BAD_FS, >>"invalid nameoff %u @ inode %" PRIuGRUB_UINT64_T, >> @@ -587,11 +588,12 @@ erofs_iterate_dir (grub_fshelp_node_t dir, >> grub_fshelp_iterate_dir_hook_t hook, >>fdiro->inode_loaded = false; >>nameoff = grub_le_to_cpu16 (de->nameoff); >> - if (nameoff < sizeof (struct grub_erofs_dirent) || nameoff > maxsize) >> + if (nameoff < sizeof (struct grub_erofs_dirent) || nameoff >= maxsize) >> { >>grub_error (GRUB_ERR_BAD_FS, >>"invalid nameoff %u @ inode %" PRIuGRUB_UINT64_T, >>nameoff, dir->ino); >> + grub_free (fdiro); >>goto not_found; >> } >> @@ -607,6 +609,7 @@ erofs_iterate_dir (grub_fshelp_node_t dir, >> grub_fshelp_iterate_dir_hook_t hook, >>"invalid de_namelen %" PRIuGRUB_SIZE >>" @ inode %" PRIuGRUB_UINT64_T, >>de_namelen, dir->ino); >> + grub_free (fdiro); >>goto not_found; >> } >> @@ -700,6 +703,7 @@ erofs_mount (grub_disk_t disk, bool read_root) >>if (err != GRUB_ERR_NONE) >> return NULL; >>if (sb.magic != grub_cpu_to_le32_compile_time (EROFS_MAGIC) || >> + grub_le_to_cpu32 (sb.log2_blksz) < EROFS_MIN_LOG2_BLOCK_SIZE || >
Re: Module dependencies
> There is the problem with the new bli module, that it requires the > part_gpt module to be loaded beforehand, but the module dependency list > for bli is emplty (see moddep.lst). > > The part_gpt module only exports one function, > grub_gpt_partition_map_iterate(). This is not used in the bli module. > However, if part_gpt is not loaded grub does not know how to work with > gpt formatted disks and these are not visible. > The bli module then can't use grub_device_open(), grub_disk_open(), etc. > to get the partition UUID of the ESP. > > Adding this dummy call to bli.c causes part_gpt to appear as a > dependency: > (void) grub_gpt_partition_map_iterate (NULL, NULL, NULL); > > Thanks, I understand the problem now. Yeah, I had a similar problem when developing appended signature support: https://lists.gnu.org/archive/html/grub-devel/2020-10/msg00016.html +/* + * Force gcry_rsa to be a module dependency. + * + * If we use grub_crypto_pk_rsa, then then the gcry_rsa module won't be built + * in if you add 'appendedsig' to grub-install --modules. You would need to + * add 'gcry_rsa' too. That's confusing and seems suboptimal, especially when + * we only support RSA. + * + * Dynamic loading also causes some concerns. We can't load gcry_rsa from the + * the filesystem after we install the verifier - we won't be able to verify + * it without having it already present. We also shouldn't load it before we + * install the verifier, because that would mean it wouldn't be verified - an + * attacker could insert any code they wanted into the module. + * + * So instead, reference the internal symbol from gcry_rsa. That creates a + * direct dependency on gcry_rsa, so it will be built in when this module + * is built in. Being built in (assuming the core image is itself signed!) + * also resolves our concerns about loading from the filesystem. + */ +extern gcry_pk_spec_t _gcry_pubkey_spec_rsa; Offtopic, but one of my wild ideas for grub is that maybe it’s time to move towards allowing modules to be directly built in rather than the current system where “built in” modules are just stored in a different section of an elf binary and are still basically dynamically loaded. A more static binary would make more sense in an UEFI universe, especially for secure boot. We would probably need to bring in an explicit dependency specification and management system like Kconfig at the same time - which would solve your issue more cleanly. (It also makes building Rust support - which is what I _actually_ want to do - much easier.) Good luck with your work. Kind regards, Daniel ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: Module dependencies
(Unless anything has changed dramatically in the last year:) Dependencies are calculated automatically on the basis of symbols that you use in your module. If you look at genmoddep.awk and work out from there you can get a handle on the process. If you only use symbols provided by the ‘kernel’, then you won’t have any dependencies. If you are writing a new module, make sure it’s specified in Makefile.core.def and you’ve regenerated the necessary files. (From memory I used to need a full bootstrap to get changes to percolate through.) Kind regards, Daniel > On 4 Oct 2023, at 8:31 pm, Oliver Steffen wrote: > > Hi, > > Is there a way to specify dependencies for a module? As in a list of > other modules that need to be loaded before? > > I found a macro named GRUB_MOD_DEP in dh.h, but when I use it in the > module's .c file I get errors about a missing .moddeps section. It also > does not seem to be in use anywhere. > > How are dependencies handled? I looked at moddep.lst and it does not > show anything listed for the module I am working on, while other modules > have a list of dependencies. What am I missing here? > > Thanks a lot, > > Oliver > > > ___ > Grub-devel mailing list > Grub-devel@gnu.org > https://lists.gnu.org/mailman/listinfo/grub-devel ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 3/6] tests: create a fuzzer for the png image format
Create a libfuzzer harness for the png image format. Once built, the fuzzer runs as: ./grub-fuzz-png With some hackery it can also be built with the address sanitizer or afl++. With regard to the license: I first worked on this while I was at IBM. I believe, looking at the fuzz fixes, that this would have been 2021-2022. The code was released to a cross-company grub security working group at this time. I left IBM in April 2022. Work subsequent to that is my own, and is unrelated to my subsequent employer. Signed-off-by: Daniel Axtens --- .gitignore | 1 + Makefile.util.def | 78 ++ grub-core/tests/fuzz/imageXX.c | 75 grub-core/tests/fuzz/png.c | 3 ++ 4 files changed, 157 insertions(+) create mode 100644 grub-core/tests/fuzz/imageXX.c create mode 100644 grub-core/tests/fuzz/png.c diff --git a/.gitignore b/.gitignore index 4064d3d1ec89..05cb43189156 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ grub-emu grub-emu-lite grub-emu-lite.exe grub-emu.exe +grub-fuzz-png grub-macho2img grub_emu_init.c grub_emu_init.h diff --git a/Makefile.util.def b/Makefile.util.def index beaef1168f0d..decced46ec19 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -53,6 +53,63 @@ library = { common = grub-core/fs/archelp.c; }; +library = { + name = libfuzzkern.a; + cflags = '$(CFLAGS_GNULIB) -fsanitize=fuzzer-no-link'; + cppflags = '$(CPPFLAGS_GNULIB) -I$(srcdir)/grub-core/lib/json -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION'; + + nostrip = common; + + condition = COND_ENABLE_FUZZERS; + + common = util/misc.c; + common = grub-core/kern/command.c; + common = grub-core/kern/device.c; + common = grub-core/kern/disk.c; + common = grub-core/lib/disk.c; + common = util/getroot.c; + common = grub-core/osdep/unix/getroot.c; + common = grub-core/osdep/getroot.c; + common = grub-core/osdep/devmapper/getroot.c; + common = grub-core/osdep/relpath.c; + extra_dist = grub-core/kern/disk_common.c; + extra_dist = grub-core/osdep/unix/relpath.c; + extra_dist = grub-core/osdep/aros/relpath.c; + extra_dist = grub-core/osdep/windows/relpath.c; + common = grub-core/kern/emu/hostdisk.c; + common = grub-core/osdep/devmapper/hostdisk.c; + common = grub-core/osdep/hostdisk.c; + common = grub-core/osdep/unix/hostdisk.c; + common = grub-core/osdep/exec.c; + common = grub-core/osdep/sleep.c; + common = grub-core/osdep/password.c; + common = grub-core/kern/emu/misc.c; + common = grub-core/kern/emu/mm.c; + common = grub-core/kern/env.c; + common = grub-core/kern/err.c; + common = grub-core/kern/file.c; + common = grub-core/kern/fs.c; + common = grub-core/kern/list.c; + common = grub-core/kern/misc.c; + common = grub-core/kern/partition.c; + common = grub-core/lib/crypto.c; + common = grub-core/lib/json/json.c; + common = grub-core/disk/luks.c; + common = grub-core/disk/luks2.c; + common = grub-core/disk/geli.c; + common = grub-core/disk/cryptodisk.c; + common = grub-core/disk/AFSplitter.c; + common = grub-core/lib/pbkdf2.c; + common = grub-core/commands/extcmd.c; + common = grub-core/lib/arg.c; + common = grub-core/disk/ldm.c; + common = grub-core/disk/diskfilter.c; + common = grub-core/partmap/gpt.c; + common = grub-core/partmap/msdos.c; + common = grub-core/fs/proc.c; + common = grub-core/fs/archelp.c; +}; + library = { name = libgrubmods.a; cflags = '-fno-builtin -Wno-undef'; @@ -1409,3 +1466,24 @@ program = { ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; + +program = { + name = grub-fuzz-png; + + nostrip = common; + + common = grub-core/video/readers/png.c; + common = grub-core/video/bitmap.c; + common = grub-core/io/bufio.c; + + extra_dist = grub-core/tests/fuzz/imageXX.c; + common = grub-core/tests/fuzz/png.c; + + ldadd = 'libfuzzkern.a grub-core/lib/gnulib/libgnu.a $(LIBDEVMAPPER)'; + + cppflags = '-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION'; + cflags='-fsanitize=fuzzer-no-link'; + ldflags='-fsanitize=fuzzer'; + + condition = COND_ENABLE_FUZZERS; +}; diff --git a/grub-core/tests/fuzz/imageXX.c b/grub-core/tests/fuzz/imageXX.c new file mode 100644 index ..4985cc5d0172 --- /dev/null +++ b/grub-core/tests/fuzz/imageXX.c @@ -0,0 +1,75 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2021-2023 Free Software Foundation, Inc. + * Copyright (C) 2021-2022 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
[PATCH 2/6] bitmap.h: set smaller image size limit when fuzzing
Large images mean large memory allocations, which could fail or at least be very slow. Also large images mean large files, which fuzzing generally cannot create. Finally, most parsing bugs (at least that we've found!) don't seem to rely on actually large images. So simply reduce the maximum size of an image to something we're more likely to actually be able to provide. --- include/grub/bitmap.h | 4 1 file changed, 4 insertions(+) diff --git a/include/grub/bitmap.h b/include/grub/bitmap.h index 431048936132..1e0c2666bc10 100644 --- a/include/grub/bitmap.h +++ b/include/grub/bitmap.h @@ -25,7 +25,11 @@ #include #include +#ifdef FUZZING_BUILD_MODE_NOT_SAFE_FOR_PRODUCTION +#define IMAGE_HW_MAX_PX512 +#else #define IMAGE_HW_MAX_PX16384 +#endif struct grub_video_bitmap { -- 2.25.1 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 4/6] tests: create a fuzzer for the jpeg image format
As with png, but this time testing jpeg. Signed-off-by: Daniel Axtens --- .gitignore | 1 + Makefile.util.def | 21 + grub-core/tests/fuzz/jpeg.c | 3 +++ 3 files changed, 25 insertions(+) create mode 100644 grub-core/tests/fuzz/jpeg.c diff --git a/.gitignore b/.gitignore index 05cb43189156..1e0340662033 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ grub-emu grub-emu-lite grub-emu-lite.exe grub-emu.exe +grub-fuzz-jpeg grub-fuzz-png grub-macho2img grub_emu_init.c diff --git a/Makefile.util.def b/Makefile.util.def index decced46ec19..49d2c67a29f1 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -1487,3 +1487,24 @@ program = { condition = COND_ENABLE_FUZZERS; }; + +program = { + name = grub-fuzz-jpeg; + + nostrip = common; + + common = grub-core/video/readers/jpeg.c; + common = grub-core/video/bitmap.c; + common = grub-core/io/bufio.c; + + extra_dist = grub-core/tests/fuzz/imageXX.c; + common = grub-core/tests/fuzz/jpeg.c; + + ldadd = 'libfuzzkern.a grub-core/lib/gnulib/libgnu.a $(LIBDEVMAPPER)'; + + cppflags = '-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION'; + cflags='-fsanitize=fuzzer-no-link'; + ldflags='-fsanitize=fuzzer'; + + condition = COND_ENABLE_FUZZERS; +}; diff --git a/grub-core/tests/fuzz/jpeg.c b/grub-core/tests/fuzz/jpeg.c new file mode 100644 index ..f23923d91789 --- /dev/null +++ b/grub-core/tests/fuzz/jpeg.c @@ -0,0 +1,3 @@ +#define IMG_EXTENSION "jpg" +#define MODULE_INIT grub_jpeg_init +#include "imageXX.c" -- 2.25.1 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 6/6] docs: document fuzzer support
This is basic documentation. There are a few extra, super-hacky things we can do to get asan or afl++ going which are a bit too messy at the moment to commit to the docs. But, so as they are not lost to time, here's the invocations that currently work for me: libfuzzer + ASan: ./configure CC=clang --with-platform=emu --enable-fuzzers=yes; make clean ASAN_OPTIONS=detect_leaks=0 make CFLAGS='-fsanitize=address -Wl,--allow-multiple-definition' -j4 -k || \ echo "the compile is expected to fail eventually, but the fuzzers should still build" AFL++: ./configure CC=clang --with-platform=emu --enable-fuzzers=yes; make clean make CC=/path/to/afl-cc CFLAGS="-Wl,--allow-multiple-definition" -j4 -k || \ echo "the compile is expected to fail eventually, but the fuzzers should still build" AFL++ + ASan: ./configure CC=clang --with-platform=emu --enable-fuzzers=yes; make clean AFL_USE_ASAN=1 ASAN_OPTIONS=detect_leaks=0 make CC=/path/to/afl-cc CFLAGS="-Wl,--allow-multiple-definition" -j4 -k || \ echo "the compile is expected to fail eventually, but the fuzzers should still build" In these cases the compilation of grub-emu(-lite) will fail, but the fuzzers themselves will be built and can be run as desired. --- docs/grub-dev.texi | 20 1 file changed, 20 insertions(+) diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi index 31eb99ea2994..11a92d04eda0 100644 --- a/docs/grub-dev.texi +++ b/docs/grub-dev.texi @@ -88,6 +88,7 @@ This edition documents version @value{VERSION}. * Graphical Menu Software Design:: * Verifiers framework:: * Lockdown framework:: +* Fuzzing the GRUB:: * Copying This Manual:: Copying This Manual * Index:: @end menu @@ -2165,6 +2166,25 @@ when the GRUB is in lockdown mode. @end itemize +@node Fuzzing the GRUB +@chapter Fuzzing the GRUB + +The GRUB has support for in-process fuzzing of various image format +parsers, based on libfuzzer. + +Fuzzers are compiled by default if the host compiler supports the +@code{-fsanitize=fuzzer} compile flag. Fuzzers can be explictly enabled with +@code{./configure --enable-fuzzers=yes}, such that configuration will not +succeed unless they can be built. Fuzzers are built as @code{grub-fuzz-XXX} +binaries in the top-level directory. + +These fuzzers build with clang out of the box. When built with clang they +can be run against a corpus as e.g. @code{./grub-fuzz-jpeg jpeg-corpus}. +Consult the LLVM libfuzzer documentation for more details and options. + +Building the fuzzers with other sanitizers (such as AddressSanitizer) or +with AFL++ can provide better results, but the process is not yet stable. + @node Copying This Manual @appendix Copying This Manual -- 2.25.1 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 0/6] Support fuzzing grub's image file parsers
This is a cleaned up version of the fuzzers that I used to find CVE-2021-3695, CVE-2021-3696 and CVE-2021-3697. We're releasing this now because the techniques are not novel, the code is not hard to independently replicate, and it's hard to see what is gained by not releasing them. (I should add that the grub security working group has been supportive of this for some time - any and all responsibility for the delay in getting this posted rests with me.) Obivously the techniques here are extensible and I'd be very happy to see people add more fuzzers to increase coverage based on this infrastructure. Kind regards, Daniel ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 1/6] configure.ac: detect if compiler supports -fsanitize=fuzzer
If detected, COND_ENABLE_FUZZERS is set, which can be used in Makefile templates. This allows us to build libfuzzer fuzzers for parts of grub. --- configure.ac | 32 1 file changed, 32 insertions(+) diff --git a/configure.ac b/configure.ac index ca42ff8f7318..f7f305482e59 100644 --- a/configure.ac +++ b/configure.ac @@ -1922,6 +1922,31 @@ fi AC_SUBST([LIBZFS]) AC_SUBST([LIBNVPAIR]) +AC_ARG_ENABLE([fuzzers], + [AS_HELP_STRING([--enable-fuzzers], + [enable fuzzers (default=guessed)])]) +if test x"$enable_fuzzers" = xno ; then + fuzzers_excuse="explicitly disabled" +fi + +if test x"$fuzzers_excuse" = x ; then + SAVED_CFLAGS="$CFLAGS" + SAVED_CC="$CC" + CC="$HOST_CC" + CFLAGS="$HOST_CFLAGS -fsanitize=fuzzer" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#include +#include +int LLVMFuzzerTestOneInput(const uint8_t Data, size_t Size) {return 0;}]], [[]])], + [], + [fuzzers_excuse="-fsanitize=fuzzer not supported by host compiler"]) + CFLAGS="$SAVED_CFLAGS" + CC="$SAVED_CC" +fi + +if test x"$enable_fuzzers" = xyes && test x"$fuzzers_excuse" != x ; then + AC_MSG_ERROR([fuzzers were explicitly requested but requirements are not satisfied ($fuzzers_excuse)]) +fi + LIBS="" AC_SUBST([FONT_SOURCE]) @@ -2054,6 +2079,8 @@ AM_CONDITIONAL([COND_STARFIELD], [test "x$starfield_excuse" = x]) AM_CONDITIONAL([COND_HAVE_EXEC], [test "x$have_exec" = xy]) AM_CONDITIONAL([COND_HAVE_PCI], [test "x$have_pci" = xy]) +AM_CONDITIONAL([COND_ENABLE_FUZZERS], [test "x$fuzzers_excuse" = x]) + test "x$prefix" = xNONE && prefix="$ac_default_prefix" test "x$exec_prefix" = xNONE && exec_prefix="${prefix}" datarootdir="$(eval echo "$datarootdir")" @@ -2189,5 +2216,10 @@ echo "With stack smashing protector: Yes" else echo "With stack smashing protector: No" fi +if [ x"$fuzzers_excuse" = x ]; then +echo With fuzzers: Yes +else +echo With fuzzers: No "($fuzzers_excuse)" +fi echo "***" ] -- 2.25.1 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 5/6] tests: create a fuzzer for the tga image format
TGA, the only parser where I didn't find any memory-corruption bugs. Yet. Signed-off-by: Daniel Axtens --- .gitignore | 1 + Makefile.util.def | 21 + grub-core/tests/fuzz/tga.c | 3 +++ 3 files changed, 25 insertions(+) create mode 100644 grub-core/tests/fuzz/tga.c diff --git a/.gitignore b/.gitignore index 1e0340662033..f148cfaf9a75 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ grub-emu-lite.exe grub-emu.exe grub-fuzz-jpeg grub-fuzz-png +grub-fuzz-tga grub-macho2img grub_emu_init.c grub_emu_init.h diff --git a/Makefile.util.def b/Makefile.util.def index 49d2c67a29f1..a5107e48ed42 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -1508,3 +1508,24 @@ program = { condition = COND_ENABLE_FUZZERS; }; + +program = { + name = grub-fuzz-tga; + + nostrip = common; + + common = grub-core/video/readers/tga.c; + common = grub-core/video/bitmap.c; + common = grub-core/io/bufio.c; + + extra_dist = grub-core/tests/fuzz/imageXX.c; + common = grub-core/tests/fuzz/tga.c; + + ldadd = 'libfuzzkern.a grub-core/lib/gnulib/libgnu.a $(LIBDEVMAPPER)'; + + cppflags = '-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION'; + cflags='-fsanitize=fuzzer-no-link'; + ldflags='-fsanitize=fuzzer'; + + condition = COND_ENABLE_FUZZERS; +}; diff --git a/grub-core/tests/fuzz/tga.c b/grub-core/tests/fuzz/tga.c new file mode 100644 index ..66ae9b32a584 --- /dev/null +++ b/grub-core/tests/fuzz/tga.c @@ -0,0 +1,3 @@ +#define IMG_EXTENSION "tga" +#define MODULE_INIT grub_tga_init +#include "imageXX.c" -- 2.25.1 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH] f2fs: fix off-by-one error in nat journal entries check
Oops. You're allowed to have up to n = NAT_JOURNAL_ENTRIES entries _inclusive_, because the loop below uses i < n, not i <= n. D'oh. Fixes: 4bd9877f6216 ("fs/f2fs: Do not read past the end of nat journal entries") Reported-by: программист нект Tested-by: программист нект Signed-off-by: Daniel Axtens --- grub-core/fs/f2fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c index df6beb544cbd..855e24618c2b 100644 --- a/grub-core/fs/f2fs.c +++ b/grub-core/fs/f2fs.c @@ -650,7 +650,7 @@ get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid, grub_uint16_t n = grub_le_to_cpu16 (data->nat_j.n_nats); grub_uint16_t i; - if (n >= NAT_JOURNAL_ENTRIES) + if (n > NAT_JOURNAL_ENTRIES) return grub_error (GRUB_ERR_BAD_FS, "invalid number of nat journal entries"); -- 2.25.1 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [programmer11...@programist.ru: Bug#1021846: grub-install is broken since 2.06-3: error: unknown filesystem]
Steve McIntyre writes: > Hi all! > > программист некто (in CC) reported this bug a few weeks back in > Debian. Since I applied the bundle of filesystem bounds-checking fixes > a few months back, he can't run grub-install. He's done the work to > determine that the patch that breaks things for him is > > 2d014248d540c7e087934a94b6e7a2aa7fc2c704 fs/f2fs: Do not read past the end of > nat journal entries > > The full thread of our discussion is at https://bugs.debian.org/1021846 > > I don't have any knowledge of f2fs to go any further here. Help please! :-) Ergh, apologies for the regression. [somewhat off-topic: The fix came from a crash derived from fuzzing. I am not really knowledgeable about f2fs either - I was just trying to do my best based on what we could derive from the existing driver. In general, filesystems are a nightmare for fuzzing fixes because testing beyond the (quite decent!) tests that the grub test-suite runs is very challenging. There is usually no-one who is both involved in grub security and an expert on any given file system either. We do the best we can. Sadly our regression rate has been climbing, so we may need to come up with some other way to secure file systems or get access to sufficient expertise in the future.] I had a massive, massive work-in-progress spiel where I looked at this code and compared the linux code and counted sizes and so on and so forth. I was getting nowhere. But eventually I realised I had just made an off-by-one error in the test. You're allowed to have up to n = NAT_JOURNAL_ENTRIES entries _inclusive_, because the loop below uses i < n, not i <= n. D'oh. Please try the following: diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c index df6beb544cbd..855e24618c2b 100644 --- a/grub-core/fs/f2fs.c +++ b/grub-core/fs/f2fs.c @@ -650,7 +650,7 @@ get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid, grub_uint16_t n = grub_le_to_cpu16 (data->nat_j.n_nats); grub_uint16_t i; - if (n >= NAT_JOURNAL_ENTRIES) + if (n > NAT_JOURNAL_ENTRIES) return grub_error (GRUB_ERR_BAD_FS, "invalid number of nat journal entries"); If for some reason that doesn't work, please add the following debug code and report the results: diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c index 855e24618c2b..6e49a6d17b7a 100644 --- a/grub-core/fs/f2fs.c +++ b/grub-core/fs/f2fs.c @@ -643,6 +643,10 @@ get_nat_journal (struct grub_f2fs_data *data) return err; } +#ifdef GRUB_UTIL +#include +#endif + static grub_err_t get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid, grub_uint32_t *blkaddr) @@ -650,6 +654,10 @@ get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid, grub_uint16_t n = grub_le_to_cpu16 (data->nat_j.n_nats); grub_uint16_t i; +#ifdef GRUB_UTIL + fprintf(stderr, "%s: n = %hu\n", __func__, n); +#endif + if (n > NAT_JOURNAL_ENTRIES) return grub_error (GRUB_ERR_BAD_FS, "invalid number of nat journal entries"); Amusingly the debug code shows that the grub-fs-tester tests always have n = 0, which makes sense for a test that doesn't really stress the file-system, and also explains why we didn't catch the bug when it was introduced. Kind regards, Daniel > > - Forwarded message from программист некто > - > > From: программист некто > To: sub...@bugs.debian.org > Date: Sat, 15 Oct 2022 23:54:36 +0300 > Subject: Bug#1021846: grub-install is broken since 2.06-3: error: unknown > filesystem > Message-Id: <3168731665867...@wf4nrjvtssjecb53.iva.yp-c.yandex.net> > > Package: grub-pc > Version: 2.06-3~deb11u1 > Severity: critical > > Hello. Since version 2.06-3, grub-install is broken: it fails with "error: > unknown filesystem". > I test command /usr/sbin/grub-install -v /dev/sda > in some versions. Results in mail attachments. > Versions older than 2.06-3 works without error (2.06-2 and lower). > Tested versions: 2.04-20, 2.06-1, 2.06-2, 2.06-3~deb10u1, 2.06-3~deb11u1, > 2.06-4. > > Disk partitions: > > # fdisk --list-details > Disk /dev/sda: 29,82 GiB, 32017047552 bytes, 62533296 sectors > Disk model: TS32GSSD370S > Units: sectors of 1 * 512 = 512 bytes > Sector size (logical/physical): 512 bytes / 512 bytes > I/O size (minimum/optimal): 512 bytes / 512 bytes > Disklabel type: dos > Disk identifier: 0xc7177f7e > > Device Boot Start End Sectors Id Type Start-C/H/S End-C/H/S Attrs > /dev/sda1 2048 22763519 22761472 83 Linux 4/4/1 1023/254/2 > /dev/sda2 * 25866240 62531583 36665344 7 HPFS/ 1023/254/2 1023/254/2 80 > > $ disktype /dev/sda1 > --- /dev/sda1 > Block device, size 10.85 GiB (11653873664 bytes) > F2FS file system (version 1.14) > > $ disktype /dev/sda2 > --- /dev/sda2 > Block device, size 17.48 GiB (18772656128 bytes) > NTFS file system > Volume size 17.48 GiB (18772652032 bytes, 36665336 sectors) > > > > > > > > > - End forwarded message - > -- >
Re: [PATCH 2/2] video/readers/jpeg: Check next_marker is within file size
Alec Brown writes: > In grub-core/video/readers/jpeg.c, the function grub_jpeg_decode_huff_table() > has the variable next_marker which reads data from grub_jpeg_get_word() and > then uses it as an upper limit in a while loop. However, the function isn't > checking that next_marker is within the file size, so this check is being > added > to the function. > > Signed-off-by: Alec Brown > --- > grub-core/video/readers/jpeg.c | 6 ++ > 1 file changed, 6 insertions(+) > > diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c > index 0eeea0e63..c0f95fbf9 100644 > --- a/grub-core/video/readers/jpeg.c > +++ b/grub-core/video/readers/jpeg.c > @@ -199,6 +199,12 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data) >next_marker = data->file->offset; >next_marker += grub_jpeg_get_word (data); > > + if (next_marker > data->file->size) > +{ > + /* Should never be set beyond the size of the file. */ > + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid next > reference"); > +} > + This is a good idea. I briefly wondered why this didn't lead to issues detected in fuzzing. It'll be because the code reads byte by byte until we get an EOF and then the loop will bail. Your change is still good, I just wanted to double check that you hadn't accidentally found and fixed a more serious bug. The fuller context: while (data->file->offset + sizeof (count) + 1 <= next_marker) { id = grub_jpeg_get_byte (data); if (grub_errno != GRUB_ERR_NONE) return grub_errno; >while (data->file->offset + sizeof (count) + 1 <= next_marker) > { >id = grub_jpeg_get_byte (data); > -- > 2.27.0 > > > ___ > Grub-devel mailing list > Grub-devel@gnu.org > https://lists.gnu.org/mailman/listinfo/grub-devel ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH] diskfilter: don't make a RAID array with more than 1024 disks
This is 'belt and braces' with commit 12e20a6a695f ("disk/diskfilter: Check calloc() result for NULL"): we end up trying to use too much memory in situations like corrupted Linux software raid setups purporting to use a huge number of disks. Simply refuse to permit such configurations. 1024 is a bit arbitrary, yes, and I feel a bit like I'm tempting fate here, but I think 1024 disks in an array (that grub has to read to boot!) should be enough for anyone. Signed-off-by: Daniel Axtens --- v2: add a minimum of 1 disk as nmemb is a signed integer. Tested with `./grub-fs-tester` using mdraid12_raid1 and mdraid12_raid5. Hopefully that means things work; I don't have software raid set up locally. --- grub-core/disk/diskfilter.c | 7 +++ 1 file changed, 7 insertions(+) diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c index 4ac50320ef4e..24de8e6c6521 100644 --- a/grub-core/disk/diskfilter.c +++ b/grub-core/disk/diskfilter.c @@ -1046,6 +1046,13 @@ grub_diskfilter_make_raid (grub_size_t uuidlen, char *uuid, int nmemb, struct grub_diskfilter_pv *pv; grub_err_t err; + /* We choose not to support more than 1024 disks */ + if (nmemb < 1 || nmemb > 1024) +{ + grub_free (uuid); + return NULL; +} + switch (level) { case 1: -- 2.25.1 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH] efi: Increase default memory allocation to 32MB
Patrick Steinhardt writes: > On Thu, Sep 22, 2022 at 05:59:34PM +0200, Daniel Kiper wrote: >> Adding some folks who may be interested in this thing too... >> >> On Tue, Sep 20, 2022 at 12:30:30AM +1000, Daniel Axtens wrote: >> > We have multiple reports of things being slower with a 1MB initial static >> > allocation, and a report (more difficult to nail down) of a boot failure >> > as a result of the smaller initial allocation. >> > >> > Make the initial memory allocation 32MB. >> > >> > Signed-off-by: Daniel Axtens >> >> Reviewed-by: Daniel Kiper >> >> However, I think we should consider [1] patch set too. I will be >> looking at it in the following days. >> >> Daniel >> >> [1] https://lists.gnu.org/archive/html/grub-devel/2022-09/msg00080.html > > Agreed, we should definitely merge some form of fixes to improve the > page request patterns. I'm also happy with bumping the default heap size > in addition. Agreed also. > > Out of curiosity: do we have any kind of minimum system requirements > documented somewhere that would allow us to come up with a default heap > size? > Heh. That'd be nice, and I think valuable, but my experience trying to drop HFS suggests that it might be very controversial. Kind regards, Daniel > Patrick > >> >> > --- >> > grub-core/kern/efi/mm.c | 2 +- >> > 1 file changed, 1 insertion(+), 1 deletion(-) >> > >> > diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c >> > index d290c9a76270..3705b8b1b465 100644 >> > --- a/grub-core/kern/efi/mm.c >> > +++ b/grub-core/kern/efi/mm.c >> > @@ -39,7 +39,7 @@ >> > #define MEMORY_MAP_SIZE 0x3000 >> > >> > /* The default heap size for GRUB itself in bytes. */ >> > -#define DEFAULT_HEAP_SIZE 0x10 >> > +#define DEFAULT_HEAP_SIZE 0x200 >> > >> > static void *finish_mmap_buf = 0; >> > static grub_efi_uintn_t finish_mmap_size = 0; ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH] efi: Increase default memory allocation to 32MB
We have multiple reports of things being slower with a 1MB initial static allocation, and a report (more difficult to nail down) of a boot failure as a result of the smaller initial allocation. Make the initial memory allocation 32MB. Signed-off-by: Daniel Axtens --- grub-core/kern/efi/mm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c index d290c9a76270..3705b8b1b465 100644 --- a/grub-core/kern/efi/mm.c +++ b/grub-core/kern/efi/mm.c @@ -39,7 +39,7 @@ #define MEMORY_MAP_SIZE0x3000 /* The default heap size for GRUB itself in bytes. */ -#define DEFAULT_HEAP_SIZE 0x10 +#define DEFAULT_HEAP_SIZE 0x200 static void *finish_mmap_buf = 0; static grub_efi_uintn_t finish_mmap_size = 0; -- 2.25.1 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH] Remove HFS support
"Vladimir 'phcoder' Serbinenko" writes: > Le ven. 26 août 2022, 15:47, Daniel Axtens a écrit : > >> Let me answer this out of order. >> >> > I understand the need to sometimes get rid of old code, but since the HFS >> > module can be blacklisted as Vladimir explains, I don't really understand >> > the reasoning in this particular case. >> >> I want _all_ grub code to reach a minimum standard of not crashing or >> corrupting memory in the presence of malicious input. HFS does not reach >> that standard. >> > That is a very high standard. Products with a huge security team like > Chrome don't reach this standard. It's reasonable that you submit the > improvements. Also it's reasonable for you to blacklist code that gets in > the way of security. E.g. all compressors that are not used should be > blacklisted. ext and fat file systems (and several other more obsure file systems) and all our image parsers reach this standard, best as I can tell. As far as I can tell the grub IPv4 networking stack does too, although I am not as certain that my coverage was very thorough. Several of us are actively working to get all of grub to this standard. grub is a lot simpler than Chrome, so I am optimistic. >> If you or someone else (someone from Gentoo, perhaps?) want make it fuzz >> clean, then that'd be great. If no-one is able to bring it up to what is >> *not* an especially high standard, then it should be considered >> abandoned by developers and therefore removed. >> > Show me the fuzzes that create problems and I'll improve the code The following two files cause crashes on stock grub-fstest stack overflow (unbounded recursion): files.intermittent.network/grub/hfs.stack-overflow stack buffer overflow -> eventual segv: files.intermittent.network/grub/hfs.stack-buffer-overflow There are an additional set of files that cause crashes when grub is compiled with ASAN: files.intermittent.network/grub/hfs.tar.xz (18MB, 210MB uncompressed) There are 222 files. The corpus is not de-duplicated (there are not 222 unique bugs) and includes the two files called out above, plus other some different heap buffer overflows. I compile grub with ASAN using: ASAN_OPTIONS=detect_leaks=0 make CFLAGS="-fsanitize=address" -j8 Modern gcc works fine. grub-emu will fail to link, but grub-fstest should build fine. In all cases, the crashes reproduce with: ./grub-fstest ls '(loop0)/' Good luck, the stack-overflow one in particular looks especially painful. I will leave your other points for others to address. Kind regards, Daniel ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH] Remove HFS support
Let me answer this out of order. > I understand the need to sometimes get rid of old code, but since the HFS > module can be blacklisted as Vladimir explains, I don't really understand > the reasoning in this particular case. I want _all_ grub code to reach a minimum standard of not crashing or corrupting memory in the presence of malicious input. HFS does not reach that standard. Whether or not the HFS module could be omitted from a signed binary doesn't really bear on the fact that there are bugs in the code, the presence of bugs has been publicly known for over 18 months (see commit 1c15848838d9) and no-one has shown any intention of fixing the bugs. If you or someone else (someone from Gentoo, perhaps?) want make it fuzz clean, then that'd be great. If no-one is able to bring it up to what is *not* an especially high standard, then it should be considered abandoned by developers and therefore removed. (And as I said in another email, HFS has in fact been built in to a signed binary recently. Module-based protection is great in theory but this example demonstrates that it falls down in practice.) >> Have you checked that you can't boot them with HFS+? Because HFS+ >> came in 1998, which was (AFAICT) pretty early on in the G3 lifecycle. So >> I'd be really surprised if the firmware didn't support booting from >> HFS+. I'd be very keen to hear. > > I have not tested that due to lack of time. The problem is that some early > firmware versions might have issues with HFS+ that we haven't verified > yet. Any approach that says 'we must wait for test results for very old macs' puts the grub community in a bind. I'm not aware of anyone else stepping up to contribute test results on old macs, and I can't go across to an apple store and buy one. So in order to test this, the entire grub upstream stalls on (AFAICT) you personally. This not the first time we find ourselves in this situation either. For example, RH is carrying the 'powerpc-ieee1275: support larger core.elf images' series out of tree because they need it to boot on modern Power boxes. It broke on your machine in a way no-one else has reproduced, and I last emailled you asking for more information to debug the failure in May. For me, this is not a desirable, sustainable, or acceptable situation. For the project to sustainably support 24 year old macs, we need more than the tests you do in your free time. Finally and in conclusion: > What's wrong with retrocomputing? Debian's popcon currently reports more > machines running the 32-bit big-endian Debian port than the 64-bit little > endian port, see [1]. I have no complaint with running _old_ software on old hardware. That's a cool hobby and an important part of preserving the history of computing. My complaint about running _new_ grub on very old hardware is that the inaccessibility of said hardware and the lack of a well-resourced community or company to do the work are all getting in the way of people trying to make grub a modern bootloader, reaching modern security standards, for modern systems. Kind regards, Daniel ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH] kern/efi/mm: Double the default heap size
Hector Martin writes: > On 21/08/2022 21.35, Daniel Axtens wrote: >> Hi Hector, >> >> Thanks for your patch and for taking the trouble to put it together. >> >>> GRUB is already running out of memory on Apple M1 systems, causing >>> graphics init to fail, as of the latest Git changes. Since dynamic >>> growing of the heap isn't done yet, double the default heap size for >>> now. >> >> Huh, weird - those changes have landed in git, see commit 887f98f0db43 >> ("mm: Allow dynamically requesting additional memory regions") for the >> overarching support and commit 1df2934822df ("kern/efi/mm: Implement >> runtime addition of pages"). It's not done on PowerPC, but if you're in >> EFI-land then it should complete. >> >> The only reason I can think of off the top of my head where you would be >> having issues that your patch fixes is if we somehow need more memory to >> even get to the point where we can ask firmware for more memory. I >> suppose that's within the realm of possibility. > > Interesting. I missed the indirection through the function pointer... > but either way, I do indeed have those commits in the broken tree that > Arch Linux ARM started shipping yesterday (0c6c1aff2a, which isn't > actually current master but it's from a couple weeks ago). The previous > version was 2f4430cc0, which doesn't have it, so I wonder if there was > actually a regression involved? Hmm. So I wonder if you're hitting an edge case which I tried to fix for powerpc but apparently didn't fix for EFI (or, on reflection, in the generic code where I should have tried to fix it). If you look at kern/mm.c, we request `size` bytes from firmware: case 1: /* Request additional pages, contiguous */ count++; if (grub_mm_add_region_fn != NULL && grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_CONSECUTIVE) == GRUB_ERR_NONE) goto again; but the problem is that we need some of those `size` bytes for grub mm metadata. (We also don't respect `align`, eek.) The mm code doesn't account for this (which it should, my bad) and the EFI code doesn't seem to account for this either: (kern/efi/mm.c::grub_efi_mm_add_regions, which is the function exposed as grub_mm_add_region_fn). /* Allocate memory regions for GRUB's memory management. */ err = add_memory_regions (filtered_memory_map, desc_size, filtered_memory_map_end, BYTES_TO_PAGES (required_bytes), flags); Would you be able to try doing something like this instead? modified grub-core/kern/efi/mm.c @@ -621,7 +621,7 @@ grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags) /* Allocate memory regions for GRUB's memory management. */ err = add_memory_regions (filtered_memory_map, desc_size, filtered_memory_map_end, - BYTES_TO_PAGES (required_bytes), + BYTES_TO_PAGES (required_bytes) + 1, flags); if (err != GRUB_ERR_NONE) return err; > What I see is that GRUB briefly flashes an out of memory error and fails > to set the graphics mode, then ends up in text mode. My best guess > without digging further is that it fails to allocate a framebuffer or > console text buffer (since these machines have higher resolution screens > than most, this might not have come up elsewhere). But I don't see why > that would have to happen before it's allowed? > Yeah that doesn't make much sense to me either. Being a high dpi screen might make it more likely to line up with a page size, thus hitting the edge case where we don't allocate metadata space? That is one hypothesis. Another would be whether the EFI implementation uses the page size grub expects (which is 0x1000 - ISTR you're using 16k pages in the kernel?) But I figure things would probably have broken in more interesting ways if that was wrong... >> I f my maths are right, this bumps up the initial allocation from 1M to >> 2M. > > Correct. > >> I think your experience tends to disprove the hypothesis that we >> could get away with a very small initial allocation (which was the >> thinking when the initial dynamic allocation patch set went in), so I'm >> wondering if we should take this opportunity to allocate 16M or 32M or >> something. My powerpc proposal kept the initial allocation at 32MB, I >> think that's probably sane for EFI too? > > I think that makes sense. (I still think this is worth doing even if it turns out that you just got unlucky and hit the edge case.) Kind regards, Daniel ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH 2/2] diskfilter: don't make a RAID array with more than 1024 disks
Daniel Axtens writes: > This is 'belt and braces' with the last fix: we end up trying to use > too much memory in situations like corrupted Linux software raid setups > purporting to usew a huge number of disks. Simply refuse to permit such > configurations. > > 1024 is a bit arbitrary, yes, and I feel a bit like I'm tempting fate > here, but I think 1024 disks in an array (that grub has to read to boot!) > should be enough for anyone. > > Signed-off-by: Daniel Axtens > --- > grub-core/disk/diskfilter.c | 7 +++ > 1 file changed, 7 insertions(+) > > diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c > index 4ac50320ef4e..79c5f4db940a 100644 > --- a/grub-core/disk/diskfilter.c > +++ b/grub-core/disk/diskfilter.c > @@ -1046,6 +1046,13 @@ grub_diskfilter_make_raid (grub_size_t uuidlen, char > *uuid, int nmemb, >struct grub_diskfilter_pv *pv; >grub_err_t err; > > + /* We choose not to support more than 1024 disks */ > + if (nmemb > 1024) Ergh, nmemb is an int; I will do a v2 that also checks that it's greater than 0 (or 1, given that it's RAID? I will do some tests.) -- d ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH] kern/efi/mm: Double the default heap size
Hi Hector, Thanks for your patch and for taking the trouble to put it together. > GRUB is already running out of memory on Apple M1 systems, causing > graphics init to fail, as of the latest Git changes. Since dynamic > growing of the heap isn't done yet, double the default heap size for > now. Huh, weird - those changes have landed in git, see commit 887f98f0db43 ("mm: Allow dynamically requesting additional memory regions") for the overarching support and commit 1df2934822df ("kern/efi/mm: Implement runtime addition of pages"). It's not done on PowerPC, but if you're in EFI-land then it should complete. The only reason I can think of off the top of my head where you would be having issues that your patch fixes is if we somehow need more memory to even get to the point where we can ask firmware for more memory. I suppose that's within the realm of possibility. I f my maths are right, this bumps up the initial allocation from 1M to 2M. I think your experience tends to disprove the hypothesis that we could get away with a very small initial allocation (which was the thinking when the initial dynamic allocation patch set went in), so I'm wondering if we should take this opportunity to allocate 16M or 32M or something. My powerpc proposal kept the initial allocation at 32MB, I think that's probably sane for EFI too? Patrick, EFI is much more your area than it is mine, what do you think? Kind regards, Daniel > > Signed-off-by: Hector Martin > --- > grub-core/kern/efi/mm.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c > index d290c9a76270..377d8d3a1c1b 100644 > --- a/grub-core/kern/efi/mm.c > +++ b/grub-core/kern/efi/mm.c > @@ -39,7 +39,7 @@ > #define MEMORY_MAP_SIZE 0x3000 > > /* The default heap size for GRUB itself in bytes. */ > -#define DEFAULT_HEAP_SIZE0x10 > +#define DEFAULT_HEAP_SIZE0x20 > > static void *finish_mmap_buf = 0; > static grub_efi_uintn_t finish_mmap_size = 0; > -- > 2.35.1 > > > ___ > Grub-devel mailing list > Grub-devel@gnu.org > https://lists.gnu.org/mailman/listinfo/grub-devel ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 2/2] diskfilter: don't make a RAID array with more than 1024 disks
This is 'belt and braces' with the last fix: we end up trying to use too much memory in situations like corrupted Linux software raid setups purporting to usew a huge number of disks. Simply refuse to permit such configurations. 1024 is a bit arbitrary, yes, and I feel a bit like I'm tempting fate here, but I think 1024 disks in an array (that grub has to read to boot!) should be enough for anyone. Signed-off-by: Daniel Axtens --- grub-core/disk/diskfilter.c | 7 +++ 1 file changed, 7 insertions(+) diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c index 4ac50320ef4e..79c5f4db940a 100644 --- a/grub-core/disk/diskfilter.c +++ b/grub-core/disk/diskfilter.c @@ -1046,6 +1046,13 @@ grub_diskfilter_make_raid (grub_size_t uuidlen, char *uuid, int nmemb, struct grub_diskfilter_pv *pv; grub_err_t err; + /* We choose not to support more than 1024 disks */ + if (nmemb > 1024) +{ + grub_free (uuid); + return NULL; +} + switch (level) { case 1: -- 2.25.1 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 1/2] diskfilter: check calloc() result for NULL
With wildly corrupt inputs, we can end up trying to calloc a very large amount of memory, which will fail and give us a NULL pointer. We need to check that to avoid a crash. (And, even if we blocked such inputs, it is good practice to check the results of allocations anyway.) Signed-off-by: Daniel Axtens --- grub-core/disk/diskfilter.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c index 2edcff6e8987..4ac50320ef4e 100644 --- a/grub-core/disk/diskfilter.c +++ b/grub-core/disk/diskfilter.c @@ -1163,6 +1163,9 @@ grub_diskfilter_make_raid (grub_size_t uuidlen, char *uuid, int nmemb, array->lvs->segments->raid_member_size = disk_size; array->lvs->segments->nodes = grub_calloc (nmemb, sizeof (array->lvs->segments->nodes[0])); + if (array->lvs->segments->nodes == NULL) +goto fail; + array->lvs->segments->stripe_size = stripe_size; for (i = 0; i < nmemb; i++) { -- 2.25.1 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH] Remove HFS support
"Vladimir 'phcoder' Serbinenko" writes: > No go from me either. Older macs may not be able to read HFS+ /boot. Also > HFS+ presents couple of problems the biggest one is that in case of sudden > reboot HFS+ often needs to be mounted by OSX or cleaning dirty flag > manually before it becomes writeable. I don't understand what you mean about the HFS+ dirtying issue. Aren't grub's accesses to the file-system read-only anyway? I'd really genuinely like to know how old a mac has to be not to support booting from HFS+, a filesystem that came out around 1998, ~24 years ago. I'd also like to know what use people have for running modern grub on a machine that old. Kind regards, Daniel ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH] Remove HFS support
>> As Daniel Axtens has been finding out, the HFS code is terrible in >> terms of security. If you still need it for old/semi-dead machines, >> maybe you should fork an older grub release and stay with that? > > I don't know what should be the deal with the security of a boot loader > to be honest. If someone has access to your hardware so they can control > your bootloader, you have much worse problems anyway. > > Forking is also a terrible idea as every forked package means having to > track it manually. Not to engage in the Debian specific parts of this, but fwiw the threat model isn't hardware access. Firmware-enforced secure boot (e.g. UEFI, AIX and Linux on PowerVM, whatever modern macs do) basically goes: - assume an attacker gets root on a running system - prevent the attacker from compromising the kernel On Linux this takes 2 parts: some form of signing grub that gets validated by firmware, and lockdown mode once Linux is booted. Now I haven't really used a PowerMac since I was a kid, but if memory serves, they had no concept of this. If you got access to Mac OS (or if you got root on linux), there is no way to protect the kernel. There is, in effect, no security boundary between root and the kernel. Kind regards, Daniel > > Adrian > > -- > .''`. John Paul Adrian Glaubitz > : :' : Debian Developer > `. `' Physicist >`-GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH] Remove HFS support
"Vladimir 'phcoder' Serbinenko" writes: > Le ven. 19 août 2022, 21:05, Dimitri John Ledkov < > dimitri.led...@canonical.com> a écrit : > >> There is no need for that code on any signed grubs or upstream. Ports that >> want to support this patch can have it conditionally compiled / enabled >> only on that arch, but not other. >> >> For example, in Ubuntu we already use separate builds for signed & >> unsigned bootloaders. Or one may keep grub-2.06 as separate source package. >> It's not like those old platforms need any new features in the bootloader >> ever again. >> >> The issue of insecure code is for signed bootloaders. Because there is a >> separate level of protection that prevents replacing arbitrary bootloaders >> (whilst potentially allow downgrade/upgrade attacks). Thus a responsible >> upstream should drop this code. >> > > This kind of consideration was taken into account when designing security > system and even when GRUB2 itself was designed. The solution is modules > whitelist. There are many modules that can be dropped from signed build not > just filesystems but also commands or loaders. There is no need to cut old > systems from new grub if existing infrastructure can handle it. At least one grub binary signed as part of the UEFI shim process contains the HFS code. (I'm not involved in the process that signs off on what should be permitted in a signed grub.) Fortunately, the patch I wrote earlier to disable HFS in lockdown should be sufficient to protect the users of that binary. That binary comes from one of the larger software companies in the world, and passed the shim signing process. If they got a shim signed that trusts a grub with HFS built in, I'm not sure we can really trust a module whitelist as a good way to protect end users. You ask in your other email what my concerns with the HFS code are and how it could be fixed. The HFS code crashes when fuzz tested: that is, you can construct a number of HFS images such that `grub-fstest hfs.img ls '(loop0)/'` crashes. (There is public information on fuzzing grub now, and that information is sufficient to reproduce the crashes I've found. I can also provide sample crashing inputs.) It would be really nice if the file systems in grub could survive malicious input, even if ideally they would not be built into a signed grub binary. Kind regards, Daniel > > >> On Fri, 19 Aug 2022, 20:39 John Paul Adrian Glaubitz, < >> glaub...@physik.fu-berlin.de> wrote: >> >>> On 8/19/22 20:09, Steve McIntyre wrote: >>> > On Fri, Aug 19, 2022 at 04:03:38PM +0200, John Paul Adrian Glaubitz >>> wrote: >>> >>> On Aug 19, 2022, at 3:59 PM, Daniel Kiper >>> wrote: >>> >>> >>> >>> If I do not hear any major objections in the following weeks I will >>> >>> merge this patch or a variant of it in the second half of September. >>> >> >>> >> We’re still formatting our /boot partitions for Debian PowerPC for >>> >> PowerMacs using HFS, so this change would be a breaking change for >>> >> us. >>> >> >>> >> So, that would be a no from Debian’s side. >>> > >>> > Not so fast please, Adrian. At the risk of sounding harsh, non-release >>> > old ports like powerpc *really* don't get to dictate things in Debian >>> > terms. >>> >>> Add "Ports" to this. >>> >>> > As Daniel Axtens has been finding out, the HFS code is terrible in >>> > terms of security. If you still need it for old/semi-dead machines, >>> > maybe you should fork an older grub release and stay with that? >>> >>> I don't know what should be the deal with the security of a boot loader >>> to be honest. If someone has access to your hardware so they can control >>> your bootloader, you have much worse problems anyway. >>> >>> Forking is also a terrible idea as every forked package means having to >>> track it manually. >>> >>> Adrian >>> >>> -- >>> .''`. John Paul Adrian Glaubitz >>> : :' : Debian Developer >>> `. `' Physicist >>>`-GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913 >>> >>> >>> ___ >>> Grub-devel mailing list >>> Grub-devel@gnu.org >>> https://lists.gnu.org/mailman/listinfo/grub-devel >>> >> ___ >> Grub-devel mailing list >> Grub-devel@gnu.org >> https://lists.gnu.org/mailman/listinfo/grub-devel >> > ___ > Grub-devel mailing list > Grub-devel@gnu.org > https://lists.gnu.org/mailman/listinfo/grub-devel ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH] Remove HFS support
John Paul Adrian Glaubitz writes: >> On Aug 19, 2022, at 3:59 PM, Daniel Kiper wrote: >> >> On Fri, Aug 19, 2022 at 11:38:26PM +1000, Daniel Axtens wrote: >>> HFS is so so very old now. According to Wikipedia, HFS was >>> introduced in 1985 and the successor HFS+ came out in January >>> 1998. Mac OS dropped support for writing HFS in 2009 and dropped >>> support for reading HFS in 2019 with macOS 10.15. >>> >>> Grub's support for it doesn't survive contact with a fuzzer, and >>> the issues involve some horrible mess of mutual recursion that >>> would be time-consuming to sort out. >>> >>> HFS has been disabled under lockdown since commit 1c15848838d9 >>> ("fs/hfs: Disable under lockdown") which was part of an earlier >>> spin of security fixes. >>> >>> I think it's time to consign HFS to the dustbin of history. It's >>> firmly in the category of retrocomputing at this stage. >>> >>> This should not affect HFS+. >>> >>> There's a little bit of mess remaining: the macbless runtime >>> command and HFS+ need the HFS headers for embedded volume support. >>> I don't think that's really deployed any more, as it would have >>> been part of the HFS->HFS+ transition, but I'm not really game to >>> mess with either, in particular as macbless writes(!) to disk live. >>> (I'm fairly sure the grub-macbless tool invokes code from the >>> macbless module as well.) >>> >>> Signed-off-by: Daniel Axtens >> >> Reviewed-by: Daniel Kiper >> >> Daniel, thank you for preparing this patch! >> >> If I do not hear any major objections in the following weeks I will >> merge this patch or a variant of it in the second half of September. > > We’re still formatting our /boot partitions for Debian PowerPC for PowerMacs > using HFS, so this change would be a breaking change for us. > Really, plain HFS, not HFS+? Wowsers! Just to be clear, by PowerMacs you mean Macs with PowerPC chips, so machines last produced around 2006? Have you checked that you can't boot them with HFS+? Because HFS+ came in 1998, which was (AFAICT) pretty early on in the G3 lifecycle. So I'd be really surprised if the firmware didn't support booting from HFS+. I'd be very keen to hear. Anyway, if I've understood correctly, the _most recent_ PowerMacs date from around 16 years ago, and potentially the machines broken by this would be even older. I still think that's in the domain of retrocomputing and I don't understand the use case for running modern software on something where the performance per watt is worse than a recent raspberry pi. Kind regards, Daniel ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH] Remove HFS support
HFS is so so very old now. According to Wikipedia, HFS was introduced in 1985 and the successor HFS+ came out in January 1998. Mac OS dropped support for writing HFS in 2009 and dropped support for reading HFS in 2019 with macOS 10.15. Grub's support for it doesn't survive contact with a fuzzer, and the issues involve some horrible mess of mutual recursion that would be time-consuming to sort out. HFS has been disabled under lockdown since commit 1c15848838d9 ("fs/hfs: Disable under lockdown") which was part of an earlier spin of security fixes. I think it's time to consign HFS to the dustbin of history. It's firmly in the category of retrocomputing at this stage. This should not affect HFS+. There's a little bit of mess remaining: the macbless runtime command and HFS+ need the HFS headers for embedded volume support. I don't think that's really deployed any more, as it would have been part of the HFS->HFS+ transition, but I'm not really game to mess with either, in particular as macbless writes(!) to disk live. (I'm fairly sure the grub-macbless tool invokes code from the macbless module as well.) Signed-off-by: Daniel Axtens --- `make check` is unchanged except for not running the hfs test any more. However, I don't have any macs set up to boot linux with HFS+, so I can't say much more for certain. If anyone can check grub-macbless in particular that would be wonderful. --- .gitignore|1 - INSTALL |2 +- Makefile.util.def |7 - docs/grub.texi| 14 +- grub-core/Makefile.core.def |5 - grub-core/commands/gptsync.c |3 +- grub-core/commands/macbless.c |7 +- grub-core/fs/hfs.c| 1446 - tests/gettext_strings_test.in |2 +- tests/hfs_test.in | 23 - tests/util/grub-fs-tester.in | 44 +- util/grub-install-common.c|2 +- util/grub-install.c | 11 +- util/grub-macbless.c |2 +- 14 files changed, 31 insertions(+), 1538 deletions(-) delete mode 100644 grub-core/fs/hfs.c delete mode 100644 tests/hfs_test.in diff --git a/.gitignore b/.gitignore index f6a1bd051752..b475a8b27062 100644 --- a/.gitignore +++ b/.gitignore @@ -218,7 +218,6 @@ widthspec.bin /gzcompress_test /hddboot_test /help_test -/hfs_test /hfsplus_test /include/grub/cpu /include/grub/gcrypt/g10lib.h diff --git a/INSTALL b/INSTALL index 7bca64f69881..a815d87ba39f 100644 --- a/INSTALL +++ b/INSTALL @@ -73,7 +73,7 @@ Prerequisites for make-check: * If running a Linux kernel the following modules must be loaded: - fuse, loop - - btrfs, ext4, f2fs, fat, hfs, hfsplus, jfs, mac-roman, minix, nilfs2, + - btrfs, ext4, f2fs, fat, hfsplus, jfs, mac-roman, minix, nilfs2, reiserfs, udf, xfs - On newer kernels, the exfat kernel modules may be used instead of the exfat FUSE filesystem diff --git a/Makefile.util.def b/Makefile.util.def index d919c562c4d1..8a66c8299ead 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -103,7 +103,6 @@ library = { common = grub-core/fs/exfat.c; common = grub-core/fs/f2fs.c; common = grub-core/fs/fshelp.c; - common = grub-core/fs/hfs.c; common = grub-core/fs/hfsplus.c; common = grub-core/fs/hfspluscomp.c; common = grub-core/fs/iso9660.c; @@ -840,12 +839,6 @@ script = { common = tests/udf_test.in; }; -script = { - testcase = native; - name = hfs_test; - common = tests/hfs_test.in; -}; - script = { testcase = native; name = jfs_test; diff --git a/docs/grub.texi b/docs/grub.texi index af119dea3b51..42fd1c874113 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -361,7 +361,7 @@ Fast FileSystem (AFFS)}, @dfn{AtheOS fs}, @dfn{BeFS}, @dfn{BtrFS} (including raid0, raid1, raid10, gzip and lzo), @dfn{cpio} (little- and big-endian bin, odc and newc variants), @dfn{Linux ext2/ext3/ext4}, @dfn{DOS FAT12/FAT16/FAT32}, -@dfn{exFAT}, @dfn{F2FS}, @dfn{HFS}, @dfn{HFS+}, +@dfn{exFAT}, @dfn{F2FS}, @dfn{HFS+}, @dfn{ISO9660} (including Joliet, Rock-ridge and multi-chunk files), @dfn{JFS}, @dfn{Minix fs} (versions 1, 2 and 3), @dfn{nilfs2}, @dfn{NTFS} (including compression), @dfn{ReiserFS}, @dfn{ROMFS}, @@ -846,7 +846,7 @@ not use any additional partition maps to access @file{/boot} @item @file{/boot} must be on one of following filesystems: AFFS, AFS, BFS, cpio, newc, odc, ext2/3/4, FAT, exFAT, - F2FS, HFS, uncompressed HFS+, ISO9660, JFS, Minix, Minix2, Minix3, NILFS2, + F2FS, uncompressed HFS+, ISO9660, JFS, Minix, Minix2, Minix3, NILFS2, NTFS, ReiserFS, ROMFS, SFS, tar, UDF, UFS1, UFS2, XFS @end itemize @@ -5925,8 +5925,8 @@ GRUB shell may provide more information on parameters and usage. @item @command{lspci} - List PCI devices. @item @command{lssal} - Display SAL system table. @item @command{lsspd} - Print Memory information. -@item @command{macppcbless} - Bless DIR of HFS or HFS+ partition for PPC macs. -@item @command{mactelbless}
Re: [PATCH 6/6] ieee1275: implement vec5 for cas negotiation
Diego Domingos writes: > As a legacy support, if the vector 5 is not implemented, Power Hypervisor will > consider the max CPUs as 64 instead 256 currently supported during > client-architecture-support negotiation. > > This patch implements the vector 5 and set the MAX CPUs to 256 while setting > the > others values to 0 (default). Ergh, CAS. I'm sorry I didn't check the defaults more carefully when I was at IBM! Anyway, this looks sane to me. I'm not in a position to test it any more, but it certainly follows the pattern I'd expect. And it is only likely to affect IBM machines anyway, so I think it's safe to add. > +struct option_vector5 { > +grub_uint8_t byte1; > +grub_uint8_t byte2; > +grub_uint8_t byte3; > +grub_uint8_t cmo; > +grub_uint8_t associativity; > +grub_uint8_t bin_opts; > +grub_uint8_t micro_checkpoint; > +grub_uint8_t reserved0; > +grub_uint32_t max_cpus; > +} __attribute__((packed)); > + I think the indent here should be 2 spaces? > + > struct pvr_entry { >grub_uint32_t mask; >grub_uint32_t entry; > @@ -512,6 +525,8 @@ struct cas_vector { >grub_uint16_t vec3; >grub_uint8_t vec4_size; >grub_uint16_t vec4; > + grub_uint8_t vec5_size; > + struct option_vector5 vec5; > } __attribute__((packed)); > > /* > @@ -534,7 +549,7 @@ grub_ieee1275_ibm_cas (void) >} args; >struct cas_vector vector = { > .pvr_list = { { 0x, 0x } }, /* any processor */ > -.num_vecs = 4 - 1, > +.num_vecs = 5 - 1, > .vec1_size = 0, > .vec1 = 0x80, /* ignore */ > .vec2_size = 1 + sizeof(struct option_vector2) - 2, > @@ -545,6 +560,10 @@ grub_ieee1275_ibm_cas (void) > .vec3 = 0x00e0, /* ask for FP + VMX + DFP but don't halt if unsatisfied > */ > .vec4_size = 2 - 1, > .vec4 = 0x0001, /* set required minimum capacity % to the lowest value */ > +.vec5_size = 1 + sizeof(struct option_vector5) - 2, > +.vec5 = { > + 0, 0, 0, 0, 0, 0, 0, 0, 256 This maybe should be indented 6 spaces instead of 1 tab? But I wouldn't do a whole new revision just for this. Acked-by: Daniel Axtens Kind regards, Daniel ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH 0/2] powerpc-ieee1275: support larger core.elf images
Hi, Sorry, I missed this as well - my otherwise lovely threaded email client doesn't sort on the basis of most recent message, but thread start date. > root@ibook-g4-14:/home/glaubitz/grub# grub-install -d ./grub-core > --macppc-directory=/boot/grub --no-nvram > Installing for powerpc-ieee1275 platform. > grub-install: warning: cannot open directory `/usr/local/share/locale': No > such file or directory. > Installation finished. No error reported. > root@ibook-g4-14:/home/glaubitz/grub# > > However, after rebooting the machine, the machine is now unbootable. The > firmware > is unable to even load GRUB. I'm just getting the question mark sign which > indicates > that the firmware cannot find the bootloader. That's really irritating. (and apologies for rendering your machine unbootable!) I don't have a good idea what the cause of that would be. I don't think I saw anything similar under qemu's mac99 model. Is there any chance you could dump the `available` property of the /memory node before grub is loaded? I don't think it's likely to be very revealing but it's my best idea so far... I've also since left IBM so I'm not likely to have a heap of time to follow it up, unfortnately. The patch does solve a real issue on Power systems, so I guess the next best thing if we can't root-cause it is to make the link address compile-time configurable :/ Kind regards, Daniel ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH v3 15/19] appended signatures: parse PKCS#7 signedData and X.509 certificates
Hi Michael, apologies for the delay, I've left IBM and am taking a while to get back on my feet. > On Thu, Apr 21, 2022 at 09:32:41PM +1000, Daniel Axtens wrote: >> Hi, >> >> >> This code allows us to parse: >> >> >> >> - PKCS#7 signedData messages. Only a single signerInfo is supported, >> >>which is all that the Linux sign-file utility supports creating >> >>out-of-the-box. Only RSA, SHA-256 and SHA-512 are supported. >> >>Any certificate embedded in the PKCS#7 message will be ignored. >> >> >> >> - X.509 certificates: at least enough to verify the signatures on the >> >>PKCS#7 messages. We expect that the certificates embedded in grub will >> >>be leaf certificates, not CA certificates. The parser enforces this. >> > >> > Doesn't grub support CA certificates for EFI? >> > >> For EFI, the verification isn't done by grub, it's done by either the >> shim or by firmware. They do - per the spec - support certificate >> chaining. So you could validly put a CA cert into db or MokList and have >> a signature on an Authenticode signature chain back to that. >> >> > Why limit to leaf certificates here? >> >> Conventionally, appended signatures don't include embedded certificates >> whereas Authenticode signatures do. There's nothing stopping you putting >> one into the PKCS#7 message for an appended signature - it's just not >> the way they are used on kernel modules or kernel binaries. So if >> there's not an embedded certificate that can chain back to a CA >> certificate, grub has to have access to the leaf certificate. >> >> > If this is technical limitation of the code in question could you fail >> > the build when CA certificate is used rather than crashing the >> > bootloader when it boots? >> >> I guess. I think IBM has been reasonably open in saying that static key >> secure boot is not the end of the road for Power, so we expect that >> ultimately keys could be loaded from somewhere other than the binary >> like firmware storage. So even if we added this check in grub-mkimage, >> we'd still need to keep it at runtime as well. >> >> >> - X.509 certificates support the Extended Key Usage extension and handle >> >>it by verifying that the certificate has a single purpose, that is code >> > ^^ >> > This should be updated I suppose. >> >> So this is - surprisingly - still accurate! We still only support 1 >> _Extended_ Key Usage. The change that we made as a result of SUSE's bug > > It is unclear to me OpenFirmware enforces such restriction as well ? My > understanding is that the (single purpose) restriction is lifed in > firmware becuase it happily accepts our cert and boots SUSE signed grub > in secure boot without complaining Key Usage. If so I wonder why it is > necessary for having the stricter check in grub ? I suppose it depends on the particular OpenFirmware implementation. You would have to ask IBM via official channels what restrictions the proprietary firmware imposes. The SLOF prototype probably imposes no restrictions because it was thrown together very very quickly as a proof of concept and development tool. I do still want to tease out (or repeat ad nauseum) the difference between Key Usage and Extended Key Usage. The original code permitted a Key Usage of only Digitial Signature and no critical Extended Key Usages. Subsequent versions, such as this one, support multiple Key Usages, so long as the Digital Signature Usage is present, and either zero or one Extended Key Usage sections, which permit only the Code Signing EKU. AIUI/IIRC, SUSE OBS keys have Digital Signature and another Key Usage set - which was where we ran into issues with your keys. >> report was to support additional regular, non-extended key >> usages. Here's the change broken out: > > Would this change be used next version ? > The next proprietary firmware version, or the next revision of this series? I don't have any insights into the future firmware development. For grub, that change is part of this v3 series already. Kind regards, Daniel > Thanks, > Michael > >> >> commit 6056d5fc59907c486309c401135757f00ebf7760 >> Author: Daniel Axtens >> Date: Tue Nov 30 15:00:57 2021 +1100 >> >> x509: allow Digitial Signature plus other Key Usages >> >> Currently the x509 certificate parser for appended signature >> verification requires that the certificate have the Digitial Signature >> key usage and _only_ the Digitial Signat
Re: [PATCH v3 15/19] appended signatures: parse PKCS#7 signedData and X.509 certificates
Hi, >> This code allows us to parse: >> >> - PKCS#7 signedData messages. Only a single signerInfo is supported, >>which is all that the Linux sign-file utility supports creating >>out-of-the-box. Only RSA, SHA-256 and SHA-512 are supported. >>Any certificate embedded in the PKCS#7 message will be ignored. >> >> - X.509 certificates: at least enough to verify the signatures on the >>PKCS#7 messages. We expect that the certificates embedded in grub will >>be leaf certificates, not CA certificates. The parser enforces this. > > Doesn't grub support CA certificates for EFI? > For EFI, the verification isn't done by grub, it's done by either the shim or by firmware. They do - per the spec - support certificate chaining. So you could validly put a CA cert into db or MokList and have a signature on an Authenticode signature chain back to that. > Why limit to leaf certificates here? Conventionally, appended signatures don't include embedded certificates whereas Authenticode signatures do. There's nothing stopping you putting one into the PKCS#7 message for an appended signature - it's just not the way they are used on kernel modules or kernel binaries. So if there's not an embedded certificate that can chain back to a CA certificate, grub has to have access to the leaf certificate. > If this is technical limitation of the code in question could you fail > the build when CA certificate is used rather than crashing the > bootloader when it boots? I guess. I think IBM has been reasonably open in saying that static key secure boot is not the end of the road for Power, so we expect that ultimately keys could be loaded from somewhere other than the binary like firmware storage. So even if we added this check in grub-mkimage, we'd still need to keep it at runtime as well. >> - X.509 certificates support the Extended Key Usage extension and handle >>it by verifying that the certificate has a single purpose, that is code > ^^ > This should be updated I suppose. So this is - surprisingly - still accurate! We still only support 1 _Extended_ Key Usage. The change that we made as a result of SUSE's bug report was to support additional regular, non-extended key usages. Here's the change broken out: commit 6056d5fc59907c486309c401135757f00ebf7760 Author: Daniel Axtens Date: Tue Nov 30 15:00:57 2021 +1100 x509: allow Digitial Signature plus other Key Usages Currently the x509 certificate parser for appended signature verification requires that the certificate have the Digitial Signature key usage and _only_ the Digitial Signature use. This is overly strict and becomes policy enforcement rather than a security property. Require that the Digitial Signature usage is present, but do not require that it is the only usage present. Reported-by: Michal Suchanek Signed-off-by: Daniel Axtens diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c index 70480aa73c9d..6ae985b30ff8 100644 --- a/grub-core/commands/appendedsig/x509.c +++ b/grub-core/commands/appendedsig/x509.c @@ -547,7 +547,7 @@ cleanup: /* * Verify the Key Usage extension. - * We only permit the Digital signature usage. + * We require the Digital signature usage. */ static grub_err_t verify_key_usage (grub_uint8_t *value, int value_size) @@ -586,10 +586,10 @@ verify_key_usage (grub_uint8_t *value, int value_size) goto cleanup; } - if (usage != digitalSignatureUsage) + if (!(usage & digitalSignatureUsage)) { err = - grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected Key Usage value: %x", + grub_error (GRUB_ERR_BAD_FILE_TYPE, "Key Usage (0x%x) missing Digital Signature usage", usage); goto cleanup; } Kind regards, Daniel ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 18/19] appended signatures: documentation
This explains how appended signatures can be used to form part of a secure boot chain, and documents the commands and variables introduced. Signed-off-by: Daniel Axtens Reviewed-by: Stefan Berger --- v3: fix CR->LF, thanks Stefan Berger. v2: fix a grammar issue, thanks Stefan Berger. --- docs/grub.texi | 193 - 1 file changed, 176 insertions(+), 17 deletions(-) diff --git a/docs/grub.texi b/docs/grub.texi index a7f5f6cd154c..605cac768e28 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -3251,6 +3251,7 @@ These variables have special meaning to GRUB. @menu * biosnum:: +* check_appended_signatures:: * check_signatures:: * chosen:: * cmdpath:: @@ -3310,11 +3311,18 @@ For an alternative approach which also changes BIOS drive mappings for the chain-loaded system, @pxref{drivemap}. +@node check_appended_signatures +@subsection check_appended_signatures + +This variable controls whether GRUB enforces appended signature validation on +certain loaded files. @xref{Using appended signatures}. + + @node check_signatures @subsection check_signatures -This variable controls whether GRUB enforces digital signature -validation on loaded files. @xref{Using digital signatures}. +This variable controls whether GRUB enforces GPG-style digital signature +validation on loaded files. @xref{Using GPG-style digital signatures}. @node chosen @subsection chosen @@ -4038,6 +4046,7 @@ you forget a command, you can run the command @command{help} * date::Display or set current date and time * devicetree:: Load a device tree blob * distrust::Remove a pubkey from trusted keys +* distrust_certificate::Remove a certificate from the list of trusted certificates * drivemap::Map a drive to another * echo::Display a line of text * eval::Evaluate agruments as GRUB commands @@ -4054,6 +4063,7 @@ you forget a command, you can run the command @command{help} * keystatus:: Check key modifier status * linux:: Load a Linux kernel * linux16:: Load a Linux kernel (16-bit mode) +* list_certificates:: List trusted certificates * list_env::List variables in environment block * list_trusted::List trusted public keys * load_env::Load variables from environment block @@ -4091,8 +4101,10 @@ you forget a command, you can run the command @command{help} * test::Check file types and compare values * true::Do nothing, successfully * trust:: Add public key to list of trusted keys +* trust_certificate:: Add an x509 certificate to the list of trusted certificates * unset:: Unset an environment variable @comment * vbeinfo:: List available video modes +* verify_appended:: Verify appended digital signature * verify_detached:: Verify detached digital signature * videoinfo:: List available video modes @comment * xen_*:: Xen boot commands for AArch64 @@ -4422,9 +4434,28 @@ These keys are used to validate signatures when environment variable @code{check_signatures} is set to @code{enforce} (@pxref{check_signatures}), and by some invocations of @command{verify_detached} (@pxref{verify_detached}). @xref{Using -digital signatures}, for more information. +GPG-style digital signatures}, for more information. +@end deffn + + +@node distrust_certificate +@subsection distrust_certificate + +@deffn Command distrust_certificate cert_number +Remove the x509 certificate numbered @var{cert_number} from GRUB's keyring of +trusted x509 certificates for verifying appended signatures. + +@var{cert_number} is the certificate number as listed by +@command{list_certificates} (@pxref{list_certificates}). + +These certificates are used to validate appended signatures when environment +variable @code{check_appended_signatures} is set to @code{enforce} +(@pxref{check_appended_signatures}), and by @command{verify_appended} +(@pxref{verify_appended}). See @xref{Using appended signatures} for more +information. @end deffn + @node drivemap @subsection drivemap @@ -4682,6 +4713,21 @@ This command is only available on x86 systems. @end deffn +@node list_certificates +@subsection list_certificates + +@deffn Command list_certificates +List all x509 certificates trusted by GRUB for validating appended signatures. +The output is a numbered list of certificates, showing the certificate's serial +number and Common Name. + +The certificate number can be used as an argument to +@command{distrust_certificate} (@pxref{distrust_certificate}). + +See @xref{Using appended signatures} for more information. +@end deffn + + @node list_env @subsection list_
[PATCH v3 17/19] appended signatures: verification tests
These tests are run through all_functional_test and test a range of commands and behaviours. Signed-off-by: Daniel Axtens Reviewed-by: Stefan Berger --- v3: clean up error codes at the start, fix copyright headers. v2 changes: - add a test for EKU - add tests for files signed with multiple signers - add a test of padded PKCS#7 messages - use macros to reduce duplication for exposing certificate files to the test via procfs - more useful comments --- grub-core/Makefile.core.def | 6 + grub-core/tests/appended_signature_test.c | 275 ++ grub-core/tests/appended_signatures.h | 975 ++ grub-core/tests/lib/functional_test.c | 1 + 4 files changed, 1257 insertions(+) create mode 100644 grub-core/tests/appended_signature_test.c create mode 100644 grub-core/tests/appended_signatures.h diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 2dc450a83398..3bc10095d0fa 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -2136,6 +2136,12 @@ module = { common = tests/setjmp_test.c; }; +module = { + name = appended_signature_test; + common = tests/appended_signature_test.c; + common = tests/appended_signatures.h; +}; + module = { name = signature_test; common = tests/signature_test.c; diff --git a/grub-core/tests/appended_signature_test.c b/grub-core/tests/appended_signature_test.c new file mode 100644 index ..5d145fcdc7d8 --- /dev/null +++ b/grub-core/tests/appended_signature_test.c @@ -0,0 +1,275 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2020, 2022 Free Software Foundation, Inc. + * Copyright (C) 2020, 2022 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "appended_signatures.h" + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define PROC_FILE(identifier, file_name) \ +static char * \ +get_ ## identifier (grub_size_t *sz) \ +{ \ + char *ret; \ + \ + *sz = identifier ## _len; \ + ret = grub_malloc (*sz); \ + if (ret) \ +grub_memcpy (ret, identifier, *sz); \ + return ret; \ +} \ +\ +static struct grub_procfs_entry identifier ## _entry = \ +{ \ + .name = file_name, \ + .get_contents = get_ ## identifier \ +}; + +#define DEFINE_TEST_CASE(case_name) PROC_FILE(case_name, #case_name) + +#define DO_TEST(case_name, is_valid) \ +{ \ + grub_procfs_register (#case_name, _name ## _entry); \ + do_verify ("(proc)/" #case_name, is_valid); \ + grub_procfs_unregister (_name ## _entry); \ +} + + +DEFINE_TEST_CASE (hi_signed); +DEFINE_TEST_CASE (hi_signed_sha256); +DEFINE_TEST_CASE (hj_signed); +DEFINE_TEST_CASE (short_msg); +DEFINE_TEST_CASE (unsigned_msg); +DEFINE_TEST_CASE (hi_signed_2nd); +DEFINE_TEST_CASE (hi_double); +DEFINE_TEST_CASE (hi_double_extended); + +PROC_FILE (certificate_der, "certificate.der") +PROC_FILE (certificate2_der, "certificate2.der") +PROC_FILE (certificate_printable_der, "certificate_printable.der") +PROC_FILE (certificate_eku_der, "certificate_eku.der") + +static void +do_verify (const char *f, int is_valid) +{ + grub_command_t cmd; + char *args[] = { (char *) f, NULL }; + grub_err_t err; + + cmd = grub_command_find ("verify_appended"); + if (!cmd) +{ + grub_test_assert (0, "can't find command `%s'", "verify_appended"); + return; +} + err = (cmd->func) (cmd, 1, args); + if (is_valid) +{ + grub_test_assert (err == GRUB_ERR_NONE, + "verification of %s failed: %d: %s", f, grub_errno, + grub_errmsg); +} + else +{ + grub_test_assert (err == GRUB_ERR_BAD_SIGNATURE, + "verification of %s unexpectedly succeeded", f); +} + grub_errno = GRUB_ERR_NONE; + +} + +static void +appended_signature_test (void) +{ + grub_command_t cmd_trust, cmd_distrust; + char *trust_args[] = { (char *) "(proc)/certificate.der", NULL }; + char *trust_args2[] = { (char *) "(proc)/certificate2.der", NULL }; + char *trust_args_printable[] = { (char *) "(proc)/certificate_printable.der", + NULL }; + char *trust_args_eku[] = { (char *)
[PATCH v3 14/19] appended signatures: import GNUTLS's ASN.1 description files
In order to parse PKCS#7 messages and X.509 certificates with libtasn1, we need some information about how they are encoded. We get these from GNUTLS, which has the benefit that they support the features we need and are well tested. The GNUTLS files are from: - https://github.com/gnutls/gnutls/blob/857543cc24114431dd5dde0e83c2c44b9b7e6050/lib/gnutls_asn1_tab.c - https://github.com/gnutls/gnutls/blob/857543cc24114431dd5dde0e83c2c44b9b7e6050/lib/pkix_asn1_tab.c The GNUTLS license is LGPLv2.1+, which is GPLv3 compatible, allowing us to import it without issue. Signed-off-by: Daniel Axtens Reviewed-by: Stefan Berger --- v3: Include links to GNUTLS source, thanks Stefan. --- .../commands/appendedsig/gnutls_asn1_tab.c| 121 + .../commands/appendedsig/pkix_asn1_tab.c | 484 ++ 2 files changed, 605 insertions(+) create mode 100644 grub-core/commands/appendedsig/gnutls_asn1_tab.c create mode 100644 grub-core/commands/appendedsig/pkix_asn1_tab.c diff --git a/grub-core/commands/appendedsig/gnutls_asn1_tab.c b/grub-core/commands/appendedsig/gnutls_asn1_tab.c new file mode 100644 index ..ddd1314e63b6 --- /dev/null +++ b/grub-core/commands/appendedsig/gnutls_asn1_tab.c @@ -0,0 +1,121 @@ +#include +#include + +const asn1_static_node 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 }, + { "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"}, + { NU
[PATCH v3 04/19] dl: provide a fake grub_dl_set_persistent for the emu target
Trying to start grub-emu with a module that calls grub_dl_set_persistent will crash because grub-emu fakes modules and passes NULL to the module init function. Provide an empty function for the emu case. Fixes: ee7808e2197c (dl: Add support for persistent modules) Signed-off-by: Daniel Axtens Reviewed-by: Stefan Berger --- include/grub/dl.h | 11 +++ 1 file changed, 11 insertions(+) diff --git a/include/grub/dl.h b/include/grub/dl.h index acb4d42327d7..ff1e291243a7 100644 --- a/include/grub/dl.h +++ b/include/grub/dl.h @@ -242,11 +242,22 @@ grub_dl_get (const char *name) return 0; } +#ifdef GRUB_MACHINE_EMU +/* + * Under grub-emu, modules are faked and NULL is passed to GRUB_MOD_INIT. + * So we fake this out to avoid a NULL deref. + */ +static inline void +grub_dl_set_persistent (grub_dl_t mod __attribute__((unused))) +{ +} +#else static inline void grub_dl_set_persistent (grub_dl_t mod) { mod->persistent = 1; } +#endif static inline int grub_dl_is_persistent (grub_dl_t mod) -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 09/19] libtasn1: disable code not needed in grub
We don't expect to be able to write ASN.1, only read it, so we can disable some code. Do that with #if 0/#endif, rather than deletion. This means that the difference between upstream and grub is smaller, which should make updating libtasn1 easier in the future. With these exclusions we also avoid the need for minmax.h, which is convenient because it means we don't have to import it from gnulib. Signed-off-by: Daniel Axtens Reviewed-by: Stefan Berger --- grub-core/lib/libtasn1/lib/coding.c| 12 ++-- grub-core/lib/libtasn1/lib/decoding.c | 2 ++ grub-core/lib/libtasn1/lib/element.c | 4 ++-- grub-core/lib/libtasn1/lib/errors.c| 3 +++ grub-core/lib/libtasn1/lib/structure.c | 10 ++ include/grub/libtasn1.h| 15 +++ 6 files changed, 38 insertions(+), 8 deletions(-) diff --git a/grub-core/lib/libtasn1/lib/coding.c b/grub-core/lib/libtasn1/lib/coding.c index 671104f63f56..b3d82671016d 100644 --- a/grub-core/lib/libtasn1/lib/coding.c +++ b/grub-core/lib/libtasn1/lib/coding.c @@ -30,11 +30,11 @@ #include "parser_aux.h" #include #include "element.h" -#include "minmax.h" #include #define MAX_TAG_LEN 16 +#if 0 /**/ /* Function : _asn1_error_description_value_not_found */ /* Description: creates the ErrorDescription string */ @@ -58,6 +58,7 @@ _asn1_error_description_value_not_found (asn1_node node, Estrcat (ErrorDescription, "' not found"); } +#endif /** * asn1_length_der: @@ -244,6 +245,7 @@ asn1_encode_simple_der (unsigned int etype, const unsigned char *str, return ASN1_SUCCESS; } +#if 0 /**/ /* Function : _asn1_time_der */ /* Description: creates the DER coding for a TIME */ @@ -278,7 +280,7 @@ _asn1_time_der (unsigned char *str, int str_len, unsigned char *der, return ASN1_SUCCESS; } - +#endif /* void @@ -519,6 +521,7 @@ asn1_bit_der (const unsigned char *str, int bit_len, } +#if 0 /**/ /* Function : _asn1_complete_explicit_tag */ /* Description: add the length coding to the EXPLICIT */ @@ -595,6 +598,7 @@ _asn1_complete_explicit_tag (asn1_node node, unsigned char *der, return ASN1_SUCCESS; } +#endif const tag_and_class_st _asn1_tags[] = { [ASN1_ETYPE_GENERALSTRING] = @@ -647,6 +651,8 @@ const tag_and_class_st _asn1_tags[] = { unsigned int _asn1_tags_size = sizeof (_asn1_tags) / sizeof (_asn1_tags[0]); + +#if 0 /**/ /* Function : _asn1_insert_tag_der*/ /* Description: creates the DER coding of tags of one */ @@ -1423,3 +1429,5 @@ error: asn1_delete_structure (); return err; } + +#endif \ No newline at end of file diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c index b1a35356f88e..b8130b956459 100644 --- a/grub-core/lib/libtasn1/lib/decoding.c +++ b/grub-core/lib/libtasn1/lib/decoding.c @@ -1620,6 +1620,7 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, return asn1_der_decoding2 (element, ider, _len, 0, errorDescription); } +#if 0 /** * asn1_der_decoding_element: * @structure: pointer to an ASN1 structure @@ -1650,6 +1651,7 @@ asn1_der_decoding_element (asn1_node * structure, const char *elementName, { return asn1_der_decoding (structure, ider, len, errorDescription); } +#endif /** * asn1_der_decoding_startEnd: diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c index 86e64f2cfc63..8cd6b662cc6b 100644 --- a/grub-core/lib/libtasn1/lib/element.c +++ b/grub-core/lib/libtasn1/lib/element.c @@ -191,7 +191,7 @@ _asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache) return ASN1_SUCCESS; } - +#if 0 /** * asn1_write_value: * @node_root: pointer to a structure @@ -646,7 +646,7 @@ asn1_write_value (asn1_node node_root, const char *name, return ASN1_SUCCESS; } - +#endif #define PUT_VALUE( ptr, ptr_size, data, data_size) \ *len = data_size; \ diff --git a/grub-core/lib/libtasn1/lib/errors.c b/grub-core/lib/libtasn1/lib/errors.c index 4dadbd96d6b4..41921d813620 100644 --- a/grub-core/lib/libtasn1/lib/errors.c +++ b/grub-core/lib/libtasn1/lib/errors.c @@ -57,6 +57,8 @@ static const libtasn1_error_entry error_algorithms[] = { {0, 0} }; + +#if 0 /** * asn1_perror: * @error: is an error returned by a libtasn1 function. @@ -73,6 +75,7 @@ asn1_perror (int error) const char *str = asn1_strerror (error); fprintf (stderr, "LIBTASN1 ERROR: %s\n", str ? str : "(null)"); } +#endif /** * asn1_strerror: diff --git a/grub-core/lib/libtasn1/lib/structure.c b/grub-core/lib/libtasn1/lib/structure.c index c0802202e5b0..45435732ce90 100644 --- a/grub-core/lib/libtasn1/
[PATCH v3 03/19] docs/grub: Document signing grub with an appended signature
Signing grub for firmware that verifies an appended signature is a bit fiddly. I don't want people to have to figure it out from scratch so document it here. Signed-off-by: Daniel Axtens Reviewed-by: Stefan Berger --- docs/grub.texi | 42 ++ 1 file changed, 42 insertions(+) diff --git a/docs/grub.texi b/docs/grub.texi index fdf2884b814f..a7f5f6cd154c 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -6119,6 +6119,48 @@ image works under UEFI secure boot and can maintain the secure-boot chain. It will also be necessary to enrol the public key used into a relevant firmware key database. +@section Signing GRUB with an appended signature + +The @file{core.img} itself can be signed with a Linux kernel module-style +appended signature. + +To support IEEE1275 platforms where the boot image is often loaded directly +from a disk partition rather than from a file system, the @file{core.img} +can specify the size and location of the appended signature with an ELF +note added by @command{grub-install}. + +An image can be signed this way using the @command{sign-file} command from +the Linux kernel: + +@example +@group +# grub.key is your private key and certificate.der is your public key + +# Determine the size of the appended signature. It depends on the signing +# certificate and the hash algorithm +touch empty +sign-file SHA256 grub.key certificate.der empty empty.sig +SIG_SIZE=`stat -c '%s' empty.sig` +rm empty empty.sig + +# Build a grub image with $SIG_SIZE reserved for the signature +grub-install --appended-signature-size $SIG_SIZE --modules="..." ... + +# Replace the reserved size with a signature: +# cut off the last $SIG_SIZE bytes with truncate's minus modifier +truncate -s -$SIG_SIZE /boot/grub/powerpc-ieee1275/core.elf core.elf.unsigned +# sign the trimmed file with an appended signature, restoring the correct size +sign-file SHA256 grub.key certificate.der core.elf.unsigned core.elf.signed + +# Don't forget to install the signed image as required +# (e.g. on powerpc-ieee1275, to the PReP partition) +@end group +@end example + +As with UEFI secure boot, it is necessary to build in the required modules, +or sign them separately. + + @node Platform limitations @chapter Platform limitations -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 07/19] posix_wrap: tweaks in preparation for libtasn1
- Define SIZEOF_UNSIGNED_LONG_INT, it's the same as SIZEOF_UNSIGNED_LONG. - Define WORD_BIT, the size in bits of an int. This is a defined in the Single Unix Specification and in gnulib's limits.h. gnulib assumes it's 32 bits on all our platforms, including 64 bit platforms, so we also use that value. - Provide strto[u]l[l] preprocessor macros that resolve to grub_strto[u]l[l]. To avoid gcrypt redefining strtoul, we also define HAVE_STRTOUL here. Signed-off-by: Daniel Axtens Reviewed-by: Stefan Berger --- grub-core/lib/posix_wrap/limits.h| 1 + grub-core/lib/posix_wrap/stdlib.h| 8 grub-core/lib/posix_wrap/sys/types.h | 1 + 3 files changed, 10 insertions(+) diff --git a/grub-core/lib/posix_wrap/limits.h b/grub-core/lib/posix_wrap/limits.h index 26918c8a01bc..4be7b4080633 100644 --- a/grub-core/lib/posix_wrap/limits.h +++ b/grub-core/lib/posix_wrap/limits.h @@ -41,5 +41,6 @@ #define LONG_MAX GRUB_LONG_MAX #define CHAR_BIT 8 +#define WORD_BIT 32 #endif diff --git a/grub-core/lib/posix_wrap/stdlib.h b/grub-core/lib/posix_wrap/stdlib.h index 148e9d94bde0..e5093a9ee545 100644 --- a/grub-core/lib/posix_wrap/stdlib.h +++ b/grub-core/lib/posix_wrap/stdlib.h @@ -58,4 +58,12 @@ abs (int c) return (c >= 0) ? c : -c; } +#define strtol grub_strtol + +/* for libgcrypt */ +#define HAVE_STRTOUL +#define strtoul grub_strtoul + +#define strtoull grub_strtoull + #endif diff --git a/grub-core/lib/posix_wrap/sys/types.h b/grub-core/lib/posix_wrap/sys/types.h index eeda543c47e2..2f3e865495ae 100644 --- a/grub-core/lib/posix_wrap/sys/types.h +++ b/grub-core/lib/posix_wrap/sys/types.h @@ -50,6 +50,7 @@ typedef grub_uint8_t byte; typedef grub_addr_t uintptr_t; #define SIZEOF_UNSIGNED_LONG GRUB_CPU_SIZEOF_LONG +#define SIZEOF_UNSIGNED_LONG_INT GRUB_CPU_SIZEOF_LONG #define SIZEOF_UNSIGNED_INT 4 #define SIZEOF_UNSIGNED_LONG_LONG 8 #define SIZEOF_UNSIGNED_SHORT 2 -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 02/19] docs/grub: Document signing grub under UEFI
Before adding information about how grub is signed with an appended signature scheme, it's worth adding some information about how it can currently be signed for UEFI. Signed-off-by: Daniel Axtens Reviewed-by: Stefan Berger --- docs/grub.texi | 22 +- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/grub.texi b/docs/grub.texi index 9835c878affc..fdf2884b814f 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -5859,6 +5859,7 @@ environment variables and commands are listed in the same order. * Secure Boot Advanced Targeting:: Embedded information for generation number based revocation * Measured Boot::Measuring boot components * Lockdown:: Lockdown when booting on a secure setup +* Signing GRUB itself:: Ensuring the integrity of the GRUB core image @end menu @node Authentication and authorisation @@ -5937,7 +5938,7 @@ commands. GRUB's @file{core.img} can optionally provide enforcement that all files subsequently read from disk are covered by a valid digital signature. -This document does @strong{not} cover how to ensure that your +This section does @strong{not} cover how to ensure that your platform's firmware (e.g., Coreboot) validates @file{core.img}. If environment variable @code{check_signatures} @@ -6099,6 +6100,25 @@ be restricted and some operations/commands cannot be executed. The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down. Otherwise it does not exit. +@node Signing GRUB itself +@section Signing GRUB itself + +To ensure a complete secure-boot chain, there must be a way for the code that +loads GRUB to verify the integrity of the core image. + +This is ultimately platform-specific and individual platforms can define their +own mechanisms. However, there are general-purpose mechanisms that can be used +with GRUB. + +@section Signing GRUB for UEFI secure boot + +On UEFI platforms, @file{core.img} is a PE binary. Therefore, it can be signed +with a tool such as @command{pesign} or @command{sbsign}. Refer to the +suggestions in @pxref{UEFI secure boot and shim} to ensure that the final +image works under UEFI secure boot and can maintain the secure-boot chain. It +will also be necessary to enrol the public key used into a relevant firmware +key database. + @node Platform limitations @chapter Platform limitations -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 05/19] pgp: factor out rsa_pad
rsa_pad does the PKCS#1 v1.5 padding for the RSA signature scheme. We want to use it in other RSA signature verification applications. I considered and rejected putting it in lib/crypto.c. That file doesn't currently require any MPI functions, but rsa_pad does. That's not so much of a problem for the grub kernel and modules, but crypto.c also gets built into all the grub utilities. So - despite the utils not using any asymmetric ciphers - we would need to built the entire MPI infrastructure in to them. A better and simpler solution is just to spin rsa_pad out into its own PKCS#1 v1.5 module. Signed-off-by: Daniel Axtens Reviewed-by: Stefan Berger --- grub-core/Makefile.core.def | 8 + grub-core/commands/pgp.c| 28 ++ grub-core/lib/pkcs1_v15.c | 59 + include/grub/pkcs1_v15.h| 27 + 4 files changed, 96 insertions(+), 26 deletions(-) create mode 100644 grub-core/lib/pkcs1_v15.c create mode 100644 include/grub/pkcs1_v15.h diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 7159948721e1..5af8b780c2a1 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -2474,6 +2474,14 @@ module = { cppflags = '$(CPPFLAGS_GCRY)'; }; +module = { + name = pkcs1_v15; + common = lib/pkcs1_v15.c; + + cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare'; + cppflags = '$(CPPFLAGS_GCRY)'; +}; + module = { name = all_video; common = lib/fake_module.c; diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c index c6766f044aaa..b084dc9a22f5 100644 --- a/grub-core/commands/pgp.c +++ b/grub-core/commands/pgp.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -411,32 +412,7 @@ static int rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval, const gcry_md_spec_t *hash, struct grub_public_subkey *sk) { - grub_size_t tlen, emlen, fflen; - grub_uint8_t *em, *emptr; - unsigned nbits = gcry_mpi_get_nbits (sk->mpis[0]); - int ret; - tlen = hash->mdlen + hash->asnlen; - emlen = (nbits + 7) / 8; - if (emlen < tlen + 11) -return 1; - - em = grub_malloc (emlen); - if (!em) -return 1; - - em[0] = 0x00; - em[1] = 0x01; - fflen = emlen - tlen - 3; - for (emptr = em + 2; emptr < em + 2 + fflen; emptr++) -*emptr = 0xff; - *emptr++ = 0x00; - grub_memcpy (emptr, hash->asnoid, hash->asnlen); - emptr += hash->asnlen; - grub_memcpy (emptr, hval, hash->mdlen); - - ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0); - grub_free (em); - return ret; + return grub_crypto_rsa_pad(hmpi, hval, hash, sk->mpis[0]); } struct grub_pubkey_context diff --git a/grub-core/lib/pkcs1_v15.c b/grub-core/lib/pkcs1_v15.c new file mode 100644 index ..dbacd563d014 --- /dev/null +++ b/grub-core/lib/pkcs1_v15.c @@ -0,0 +1,59 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2013 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 +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +/* + * Given a hash value 'hval', of hash specification 'hash', perform + * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod' + * (see RFC 8017 s 9.2) and place the result in 'hmpi'. + */ +gcry_err_code_t +grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval, +const gcry_md_spec_t * hash, gcry_mpi_t mod) +{ + grub_size_t tlen, emlen, fflen; + grub_uint8_t *em, *emptr; + unsigned nbits = gcry_mpi_get_nbits (mod); + int ret; + tlen = hash->mdlen + hash->asnlen; + emlen = (nbits + 7) / 8; + if (emlen < tlen + 11) +return GPG_ERR_TOO_SHORT; + + em = grub_malloc (emlen); + if (!em) +return 1; + + em[0] = 0x00; + em[1] = 0x01; + fflen = emlen - tlen - 3; + for (emptr = em + 2; emptr < em + 2 + fflen; emptr++) +*emptr = 0xff; + *emptr++ = 0x00; + grub_memcpy (emptr, hash->asnoid, hash->asnlen); + emptr += hash->asnlen; + grub_memcpy (emptr, hval, hash->mdlen); + + ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0); + grub_free (em); + return ret; +} diff --git a/include/grub/pkcs1_v15.h b/include/grub/pkcs1_v15.h new file mode 100644 index ..5c338c84a158 --- /dev/null +++ b/include/grub/pkcs1_v15.h @@ -0,0 +1,27 @@ +/* + * GRU
[PATCH v3 01/19] Add suport for signing grub with an appended signature
From: Rashmica Gupta Add infrastructure to allow firmware to verify the integrity of grub by use of a Linux-kernel-module-style appended signature. We initially target powerpc-ieee1275, but the code should be extensible to other platforms. Usually these signatures are appended to a file without modifying the ELF file itself. (This is what the 'sign-file' tool does, for example.) The verifier loads the signed file from the file system and looks at the end of the file for the appended signature. However, on powerpc-ieee1275 platforms, the bootloader is often stored directly in the PReP partition as raw bytes without a file-system. This makes determining the location of an appended signature more difficult. To address this, we add a new ELF note. The name field of shall be the string "Appended-Signature", zero-padded to 4 byte alignment. The type field shall be 0x41536967 (the ASCII values for the string "ASig"). It must be the final section in the ELF binary. The description shall contain the appended signature structure as defined by the Linux kernel. The description will also be padded to be a multiple of 4 bytes. The padding shall be added before the appended signature structure (not at the end) so that the final bytes of a signed ELF file are the appended signature magic. A subsequent patch documents how to create a grub core.img validly signed under this scheme. Signed-off-by: Daniel Axtens Signed-off-by: Rashmica Gupta --- You can experiment with this code with a patched version of SLOF that verifies these signatures. You can find one at: https://github.com/daxtens/SLOF I will be proposing this for inclusion in a future Power Architecture Platform Reference (PAPR). v3: Fix a nit, thanks Stefan. --- include/grub/util/install.h | 8 ++-- include/grub/util/mkimage.h | 4 ++-- util/grub-install-common.c | 15 +++--- util/grub-mkimage.c | 11 +++ util/grub-mkimagexx.c | 39 - util/mkimage.c | 13 +++-- 6 files changed, 76 insertions(+), 14 deletions(-) diff --git a/include/grub/util/install.h b/include/grub/util/install.h index 7d7445af9815..fadcce0fea7e 100644 --- a/include/grub/util/install.h +++ b/include/grub/util/install.h @@ -67,6 +67,9 @@ N_("SBAT metadata"), 0 }, \ { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, \ N_("disable shim_lock verifier"), 0 }, \ + { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\ +"SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \ +1}, \ { "verbose", 'v', 0, 0, \ N_("print verbose messages."), 1 } @@ -128,7 +131,8 @@ enum grub_install_options { GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS, GRUB_INSTALL_OPTIONS_DTB, GRUB_INSTALL_OPTIONS_SBAT, - GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK + GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, + GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE }; extern char *grub_install_source_directory; @@ -188,7 +192,7 @@ grub_install_generate_image (const char *dir, const char *prefix, size_t npubkeys, char *config_path, const struct grub_install_image_target_desc *image_target, -int note, +int note, size_t appsig_size, grub_compression_t comp, const char *dtb_file, const char *sbat_path, const int disable_shim_lock); diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h index 3819a67441c8..6f1da89b9b65 100644 --- a/include/grub/util/mkimage.h +++ b/include/grub/util/mkimage.h @@ -51,12 +51,12 @@ grub_mkimage_load_image64 (const char *kernel_path, const struct grub_install_image_target_desc *image_target); void grub_mkimage_generate_elf32 (const struct grub_install_image_target_desc *image_target, -int note, char **core_img, size_t *core_size, +int note, size_t appsig_size, char **core_img, size_t *core_size, Elf32_Addr target_addr, struct grub_mkimage_layout *layout); void grub_mkimage_generate_elf64 (const struct grub_install_image_target_desc *image_target, -int note, char **core_img, size_t *core_size, +int note, size_t appsig_size, char **core_img, size_t *core_size, Elf64_Addr target_addr, struct grub_mkimage_layout *layout); diff --git a/util/grub-i
[PATCH v3 00/19] Appended signature secure boot support
This patch set contains the long-awaited v3 for secure boot using appended signatures on powerpc. The v2 series is at https://lists.gnu.org/archive/html/grub-devel/2021-06/msg00044.html This series is based on the latest memory rework series I sent (https://lists.gnu.org/archive/html/grub-devel/2022-04/msg00064.html) minus the RFC. (See github.com/daxtens/grub branch mem+appsig-2204 for precise patches.) I have not included those patches in this posting. The series consists of 3 main parts: 1) Patches 1-3: signing grub.elf with an appended signature Part of a secure boot chain is allowing boot firmware to verify the grub core image. For UEFI platforms, this is done by signing the PE binary with a tool like pesign or sb-sign. However, for platforms that don't implement UEFI, an alternative scheme is required. These patches provide some infrastructure and documentation for signing grub's core.elf with a Linux-kernel-module style appended signature. An appended signature is a 'dumb' signature over the contents of a file. (It is distinct from schemes like Authenticode that are aware of the structure of the file and only sign certain parts.) The signature is wrapped in a PKCS#7 message, and is appended to the signed file along with some metadata and a magic string. The signatures are validated against a public key which is usually provided as an x509 certificate. Because some platforms, such as powerpc-ieee1275, may load grub from a raw disk partition rather than a filesystem, we extend grub-install to add an ELF note that allows us to specify the size and location of the signature. 2) Patches 4 - 18: Teach grub to verify appended signatures Part of a secure boot chain is allowing grub to verify the boot kernel. For UEFI platforms, this is usually delegated to the shim. However, for platforms that do not implement UEFI, an alternative scheme is required. This part teaches grub how to verify Linux kernel-style appended signatures. Kernels on powerpc are already signed with this scheme and can be verified by IMA for kexec. As PKCS#7 messages and x509 certificates are both based on ASN.1, we import libtasn1 to parse them. Because ASN.1 isn't self-documenting, we import from GNUTLS the information we need to navigate their structure. This section is composed of the following patches: - patch 4 is a small fix to allow persistent modules to work on the emu target. - patches 5 and 6 are small refactorings. - patch 7 prepares posix_wrap for importing libtasn1 - patches 8 through 12 import libtasn1 and add tests. I've taken a different approach from gcrypt. We import gcrypt via a script that transforms the code into something that works for grub. Rather than taking that approach, we import libtasn1 through first just copying a subset of the code in (patch 8), then disabling parts we don't need for grub (patch 9), making changes for grub compatibility (patch 10) and then compiling it into a module (patch 11) and testing it (patch 12). This means that should we want to upgrade our version of libtasn1, we should be able to copy the new files in (repeat the process in patch 8) and then just cherry-pick/reapply patches 9 and 10 to repeat the process of disabling unused code and making grub compatiblity fixes. - patch 13 allows x509 certificates to be built in to the grub core in much the same way as PGP keys. - patch 14 brings in the code from GNUTLS that allows us to parse PKCS#7 and x509 with libtasn1. - patch 15 is our PKCS#7 and x509 parser. They're minimal and fairly strict parsers that extract only the bits we need to verify the signatures. - patch 16 is the guts of the appended signature verifier. It uses the verifier infrastructure like pgp, and adds a number of user-friendly commands that mirror the pgp module. - patch 17 adds tests, and patch 18 adds documentation. 3) Patch 19: Enter lockdown if in powerpc secure boot Detect if the DT property advertising SB is set, and enter lockdown if it is. The main appended signature module now tests for lockdown to enter 'forced' mode. Thanks to Stefan Berger for providing further review comments on v2. I've pushed this all to https://github.com/daxtens/grub/tree/mem+appsig-2204 This patch series is easy to experiment with. In particular, the appended signature verifier doesn't require any particular platform. Alastair D'Silva (1): grub-install: support embedding x509 certificates Daniel Axtens (17): docs/grub: Document signing grub under UEFI docs/grub: Document signing grub with an appended signature dl: provide a fake grub_dl_set_persistent for the emu target pgp: factor out rsa_pad crypto: move storage for grub_crypto_pk_* to crypto.c posix_wrap: tweaks in preparation for libtasn1 libtasn1: import libtasn1-4.18.0 libtasn1: disable code not needed in grub libtasn1: changes for grub compatibility libtasn1: compile into asn1 module test_asn1: test
[PATCH v3 13/19] grub-install: support embedding x509 certificates
From: Alastair D'Silva To support verification of appended signatures, we need a way to embed the necessary public keys. Existing appended signature schemes in the Linux kernel use X.509 certificates, so allow certificates to be embedded in the grub core image in the same way as PGP keys. Signed-off-by: Alastair D'Silva Signed-off-by: Daniel Axtens Reviewed-by: Stefan Berger --- grub-core/commands/pgp.c| 2 +- include/grub/kernel.h | 3 ++- include/grub/util/install.h | 7 +-- util/grub-install-common.c | 22 +++- util/grub-mkimage.c | 15 -- util/mkimage.c | 41 ++--- 6 files changed, 80 insertions(+), 10 deletions(-) diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c index a45c2213c4ac..847a5046a5c4 100644 --- a/grub-core/commands/pgp.c +++ b/grub-core/commands/pgp.c @@ -944,7 +944,7 @@ GRUB_MOD_INIT(pgp) grub_memset (_file, 0, sizeof (pseudo_file)); /* Not an ELF module, skip. */ -if (header->type != OBJ_TYPE_PUBKEY) +if (header->type != OBJ_TYPE_GPG_PUBKEY) continue; pseudo_file.fs = _fs; diff --git a/include/grub/kernel.h b/include/grub/kernel.h index abbca5ea3359..d3aafc8848d2 100644 --- a/include/grub/kernel.h +++ b/include/grub/kernel.h @@ -28,7 +28,8 @@ enum OBJ_TYPE_MEMDISK, OBJ_TYPE_CONFIG, OBJ_TYPE_PREFIX, - OBJ_TYPE_PUBKEY, + OBJ_TYPE_GPG_PUBKEY, + OBJ_TYPE_X509_PUBKEY, OBJ_TYPE_DTB, OBJ_TYPE_DISABLE_SHIM_LOCK }; diff --git a/include/grub/util/install.h b/include/grub/util/install.h index fadcce0fea7e..bfaba0d09f33 100644 --- a/include/grub/util/install.h +++ b/include/grub/util/install.h @@ -67,6 +67,8 @@ N_("SBAT metadata"), 0 }, \ { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, \ N_("disable shim_lock verifier"), 0 }, \ + { "x509key", 'x', N_("FILE"), 0, \ + N_("embed FILE as an x509 certificate for signature checking"), 0}, \ { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\ "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \ 1}, \ @@ -188,8 +190,9 @@ void grub_install_generate_image (const char *dir, const char *prefix, FILE *out, const char *outname, char *mods[], -char *memdisk_path, char **pubkey_paths, -size_t npubkeys, +char *memdisk_path, +char **pubkey_paths, size_t npubkeys, +char **x509key_paths, size_t nx509keys, char *config_path, const struct grub_install_image_target_desc *image_target, int note, size_t appsig_size, diff --git a/util/grub-install-common.c b/util/grub-install-common.c index b552808df70f..cbd868152457 100644 --- a/util/grub-install-common.c +++ b/util/grub-install-common.c @@ -460,6 +460,8 @@ static char **pubkeys; static size_t npubkeys; static char *sbat; static int disable_shim_lock; +static char **x509keys; +static size_t nx509keys; static grub_compression_t compression; static size_t appsig_size; @@ -501,6 +503,12 @@ grub_install_parse (int key, char *arg) case GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK: disable_shim_lock = 1; return 1; +case 'x': + x509keys = xrealloc (x509keys, + sizeof (x509keys[0]) + * (nx509keys + 1)); + x509keys[nx509keys++] = xstrdup (arg); + return 1; case GRUB_INSTALL_OPTIONS_VERBOSITY: verbosity++; @@ -627,6 +635,9 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, for (pk = pubkeys; pk < pubkeys + npubkeys; pk++) slen += 20 + grub_strlen (*pk); + for (pk = x509keys; pk < x509keys + nx509keys; pk++) +slen += 10 + grub_strlen (*pk); + for (md = modules.entries; *md; md++) { slen += 10 + grub_strlen (*md); @@ -655,6 +666,14 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, *p++ = ' '; } + for (pk = x509keys; pk < x509keys + nx509keys; pk++) +{ + p = grub_stpcpy (p, "--x509 '"); + p = grub_stpcpy (p, *pk); + *p++ = '\''; + *p++ = ' '; +} + for (md = modules.entries; *md; md++) { *p++ = '\''; @@ -683,7 +702,8 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, grub_install_generate_image (dir, prefix, fp, outname, modules.entries, memdisk_path, -
[PATCH v3 11/19] libtasn1: compile into asn1 module
Create a wrapper file that specifies the module license. Set up the makefile so it is built. Signed-off-by: Daniel Axtens Reviewed-by: Stefan Berger --- v3: Proper copyright headers. --- grub-core/Makefile.core.def| 15 +++ grub-core/lib/libtasn1_wrap/wrap.c | 27 +++ 2 files changed, 42 insertions(+) create mode 100644 grub-core/lib/libtasn1_wrap/wrap.c diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 5af8b780c2a1..2d73bb41bf42 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -2540,3 +2540,18 @@ module = { common = commands/i386/wrmsr.c; enable = x86; }; + +module = { + name = asn1; + common = lib/libtasn1/lib/decoding.c; + common = lib/libtasn1/lib/coding.c; + common = lib/libtasn1/lib/element.c; + common = lib/libtasn1/lib/structure.c; + common = lib/libtasn1/lib/parser_aux.c; + common = lib/libtasn1/lib/gstr.c; + common = lib/libtasn1/lib/errors.c; + common = lib/libtasn1_wrap/wrap.c; + cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)'; + // -Wno-type-limits comes from libtasn1's configure.ac + cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/libtasn1/lib -Wno-type-limits'; +}; diff --git a/grub-core/lib/libtasn1_wrap/wrap.c b/grub-core/lib/libtasn1_wrap/wrap.c new file mode 100644 index ..8f6bc5c12dff --- /dev/null +++ b/grub-core/lib/libtasn1_wrap/wrap.c @@ -0,0 +1,27 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2020, 2022 Free Software Foundation, Inc. + * Copyright (C) 2020, 2022 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 is provided under LGPL2.1+, which is compatible + * with GPL3+. As Grub as a whole is under GPL3+, this module + * is therefore under GPL3+ also. + */ +GRUB_MOD_LICENSE ("GPLv3+"); -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 19/19] ieee1275: enter lockdown based on /ibm,secure-boot
If the 'ibm,secure-boot' property of the root node is 2 or greater, enter lockdown. Signed-off-by: Daniel Axtens Reviewed-by: Stefan Berger --- docs/grub.texi | 4 ++-- grub-core/Makefile.core.def| 1 + grub-core/kern/ieee1275/init.c | 27 +++ include/grub/lockdown.h| 3 ++- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/docs/grub.texi b/docs/grub.texi index 605cac768e28..f89c1e86214a 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -6253,8 +6253,8 @@ Measured boot is currently only supported on EFI platforms. @section Lockdown when booting on a secure setup The GRUB can be locked down when booted on a secure boot environment, for example -if the UEFI secure boot is enabled. On a locked down configuration, the GRUB will -be restricted and some operations/commands cannot be executed. +if UEFI or Power secure boot is enabled. On a locked down configuration, the +GRUB will be restricted and some operations/commands cannot be executed. The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down. Otherwise it does not exit. diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 3bc10095d0fa..67940de38943 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -319,6 +319,7 @@ kernel = { powerpc_ieee1275 = kern/powerpc/cache.S; powerpc_ieee1275 = kern/powerpc/dl.c; powerpc_ieee1275 = kern/powerpc/compiler-rt.S; + powerpc_ieee1275 = kern/lockdown.c; sparc64_ieee1275 = kern/sparc64/cache.S; sparc64_ieee1275 = kern/sparc64/dl.c; diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c index ec591e6e13ec..f59f08d980a1 100644 --- a/grub-core/kern/ieee1275/init.c +++ b/grub-core/kern/ieee1275/init.c @@ -44,6 +44,7 @@ #ifdef __sparc__ #include #endif +#include /* The maximum heap size we're going to claim at boot. Not used by sparc. */ #ifdef __i386__ @@ -631,6 +632,30 @@ grub_parse_cmdline (void) } } +static void +grub_get_ieee1275_secure_boot (void) +{ + grub_ieee1275_phandle_t root; + int rc; + grub_uint32_t is_sb; + + grub_ieee1275_finddevice ("/", ); + + rc = grub_ieee1275_get_integer_property (root, "ibm,secure-boot", _sb, + sizeof (is_sb), 0); + + /* ibm,secure-boot: + * 0 - disabled + * 1 - audit + * 2 - enforce + * 3 - enforce + OS-specific behaviour + * + * We only support enforce. + */ + if (rc >= 0 && is_sb >= 2) +grub_lockdown (); +} + grub_addr_t grub_modbase; void @@ -656,6 +681,8 @@ grub_machine_init (void) #else grub_install_get_time_ms (grub_rtc_get_time_ms); #endif + + grub_get_ieee1275_secure_boot (); } void diff --git a/include/grub/lockdown.h b/include/grub/lockdown.h index 40531fa823bf..ebfee4bf06e7 100644 --- a/include/grub/lockdown.h +++ b/include/grub/lockdown.h @@ -24,7 +24,8 @@ #define GRUB_LOCKDOWN_DISABLED 0 #define GRUB_LOCKDOWN_ENABLED1 -#ifdef GRUB_MACHINE_EFI +#if defined(GRUB_MACHINE_EFI) || \ +(defined(__powerpc__) && defined(GRUB_MACHINE_IEEE1275)) extern void EXPORT_FUNC (grub_lockdown) (void); extern int -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 06/19] crypto: move storage for grub_crypto_pk_* to crypto.c
The way gcry_rsa and friends (the asymmetric ciphers) are loaded for the pgp module is a bit quirky. include/grub/crypto.h contains: extern struct gcry_pk_spec *grub_crypto_pk_rsa; commands/pgp.c contains the actual storage: struct gcry_pk_spec *grub_crypto_pk_rsa; And the module itself saves to the storage in pgp.c: GRUB_MOD_INIT(gcry_rsa) { grub_crypto_pk_rsa = &_gcry_pubkey_spec_rsa; } This is annoying: gcry_rsa now has a dependency on pgp! We want to be able to bring in gcry_rsa without bringing in PGP, so move the storage to crypto.c. Previously, gcry_rsa depended on pgp and mpi. Now it depends on crypto and mpi. As pgp depends on crypto, this doesn't add any new module dependencies using the PGP verfier. [FWIW, the story is different for the symmetric ciphers. cryptodisk and friends (zfs encryption etc) use grub_crypto_lookup_cipher_by_name() to get a cipher handle. That depends on grub_ciphers being populated by people calling grub_cipher_register. import_gcry.py ensures that the symmetric ciphers call it.] Signed-off-by: Daniel Axtens Reviewed-by: Stefan Berger --- grub-core/commands/pgp.c | 4 grub-core/lib/crypto.c | 4 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c index b084dc9a22f5..a45c2213c4ac 100644 --- a/grub-core/commands/pgp.c +++ b/grub-core/commands/pgp.c @@ -147,10 +147,6 @@ const char *hashes[] = { [0x0b] = "sha224" }; -struct gcry_pk_spec *grub_crypto_pk_dsa; -struct gcry_pk_spec *grub_crypto_pk_ecdsa; -struct gcry_pk_spec *grub_crypto_pk_rsa; - static int dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval, const gcry_md_spec_t *hash, struct grub_public_subkey *sk); diff --git a/grub-core/lib/crypto.c b/grub-core/lib/crypto.c index 396f7641080f..d53ddbe2c441 100644 --- a/grub-core/lib/crypto.c +++ b/grub-core/lib/crypto.c @@ -121,6 +121,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 grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in, grub_size_t inlen) -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 15/19] appended signatures: parse PKCS#7 signedData and X.509 certificates
This code allows us to parse: - PKCS#7 signedData messages. Only a single signerInfo is supported, which is all that the Linux sign-file utility supports creating out-of-the-box. Only RSA, SHA-256 and SHA-512 are supported. Any certificate embedded in the PKCS#7 message will be ignored. - X.509 certificates: at least enough to verify the signatures on the PKCS#7 messages. We expect that the certificates embedded in grub will be leaf certificates, not CA certificates. The parser enforces this. - X.509 certificates support the Extended Key Usage extension and handle it by verifying that the certificate has a single purpose, that is code signing. This is required because Red Hat certificates have both Key Usage and Extended Key Usage extensions present. Signed-off-by: Javier Martinez Canillas # EKU support Reported-by: Michal Suchanek # key usage issue Signed-off-by: Daniel Axtens --- v3 changes: - fix nits from Stefan - correct copyright headers - fixes for libtasn1-4.18.0 - Roll in a fix for a bug reported by Michal: Currently the x509 certificate parser for appended signature verification requires that the certificate have the Digitial Signature key usage and _only_ the Digitial Signature use. This is overly strict and becomes policy enforcement rather than a security property. Require that the Digitial Signature usage is present, but do not require that it is the only usage present. v2 changes: - Handle the Extended Key Usage extension - Fix 2 leaks in x509 cert parsing - Improve x509 parser function name - Constify the data parameter in parser signatures - Support multiple signers in a pkcs7 message. Accept any passing sig. - Allow padding after a pkcs7 message in an appended signature, required to support my model for signers separated in time. - Fix a test that used GRUB_ERR_NONE rather than ASN1_SUCCESS. They're both 0 so no harm was done, but better to be correct. - Various code and comment cleanups. Thanks to Nayna Jain and Stefan Berger for their reviews. --- grub-core/commands/appendedsig/appendedsig.h | 119 ++ grub-core/commands/appendedsig/asn1util.c| 104 ++ grub-core/commands/appendedsig/pkcs7.c | 512 + grub-core/commands/appendedsig/x509.c| 1082 ++ 4 files changed, 1817 insertions(+) create mode 100644 grub-core/commands/appendedsig/appendedsig.h create mode 100644 grub-core/commands/appendedsig/asn1util.c create mode 100644 grub-core/commands/appendedsig/pkcs7.c create mode 100644 grub-core/commands/appendedsig/x509.c diff --git a/grub-core/commands/appendedsig/appendedsig.h b/grub-core/commands/appendedsig/appendedsig.h new file mode 100644 index ..d3dfd4616862 --- /dev/null +++ b/grub-core/commands/appendedsig/appendedsig.h @@ -0,0 +1,119 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2020, 2022 Free Software Foundation, Inc. + * Copyright (C) 2020, 2022 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 +#include + +extern asn1_node _gnutls_gnutls_asn; +extern asn1_node _gnutls_pkix_asn; + +#define MAX_OID_LEN 32 + +/* + * One or more x509 certificates. + * + * We do limited parsing: extracting only the serial, CN and RSA public key. + */ +struct x509_certificate +{ + struct x509_certificate *next; + + grub_uint8_t *serial; + grub_size_t serial_len; + + char *subject; + grub_size_t subject_len; + + /* We only support RSA public keys. This encodes [modulus, publicExponent] */ + gcry_mpi_t mpis[2]; +}; + +/* + * A PKCS#7 signedData signerInfo. + */ +struct pkcs7_signerInfo +{ + const gcry_md_spec_t *hash; + gcry_mpi_t sig_mpi; +}; + +/* + * A PKCS#7 signedData message. + * + * We make no attempt to match intelligently, so we don't save any info about + * the signer. + */ +struct pkcs7_signedData +{ + int signerInfo_count; + struct pkcs7_signerInfo *signerInfos; +}; + + +/* Do libtasn1 init */ +int asn1_init (void); + +/* + * Import a DER-encoded certificate at 'data', of size 'size'. + * + * Place the results into 'results', which must be already allocated. + */ +grub_err_t +parse_x509_certificate (const void *data, grub_size_t size, + struct x509_certificate *results); + +/* + * Release all the storage associated with the x509 certificate. + * If the caller dynamically all
[PATCH v3 16/19] appended signatures: support verifying appended signatures
Building on the parsers and the ability to embed x509 certificates, as well as the existing gcrypt functionality, add a module for verifying appended signatures. This includes a verifier that requires that Linux kernels and grub modules have appended signatures, and commands to manage the list of trusted certificates for verification. Verification must be enabled by setting check_appended_signatures. If GRUB is locked down when the module is loaded, verification will be enabled and locked automatically. As with the PGP verifier, it is not a complete secure-boot solution: other mechanisms, such as a password or lockdown, must be used to ensure that a user cannot drop to the grub shell and disable verification. Signed-off-by: Daniel Axtens --- v3: Correct copyright header, fix some nits from Stefan. v2 changes: - Improve x509 parser function name - Constify data parameters in function signatures - Support multiple signers - Use an enum rather than 0, 1 and 2 for various signature enforcement states. - Spin out a file reading function that was duplicated. - Fix some code style and clarity issues. Thanks to Nayna Jain and Stefan Berger for their reviews. --- grub-core/Makefile.core.def | 14 + grub-core/commands/appendedsig/appendedsig.c | 662 +++ include/grub/file.h | 2 + 3 files changed, 678 insertions(+) create mode 100644 grub-core/commands/appendedsig/appendedsig.c diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index de5c763c64a0..2dc450a83398 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -951,6 +951,20 @@ module = { cppflags = '-I$(srcdir)/lib/posix_wrap'; }; +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; + + // posix wrapper required for gcry to get sys/types.h + cflags = '$(CFLAGS_POSIX)'; + cppflags = '-I$(srcdir)/lib/posix_wrap'; +}; + module = { name = hdparm; common = commands/hdparm.c; diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c new file mode 100644 index ..d2e19c268204 --- /dev/null +++ b/grub-core/commands/appendedsig/appendedsig.c @@ -0,0 +1,662 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2020, 2021, 2022 Free Software Foundation, Inc. + * Copyright (C) 2020, 2021, 2022 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "appendedsig.h" + +GRUB_MOD_LICENSE ("GPLv3+"); + +const char magic[] = "~Module signature appended~\n"; + +/* + * This structure is extracted from scripts/sign-file.c in the linux kernel + * source. It was licensed as LGPLv2.1+, which is GPLv3+ compatible. + */ +struct module_signature +{ + grub_uint8_t algo; /* Public-key crypto algorithm [0] */ + grub_uint8_t hash; /* Digest algorithm [0] */ + grub_uint8_t id_type;/* Key identifier type [PKEY_ID_PKCS7] */ + grub_uint8_t signer_len; /* Length of signer's name [0] */ + grub_uint8_t key_id_len; /* Length of key identifier [0] */ + grub_uint8_t __pad[3]; + grub_uint32_t sig_len; /* Length of signature data */ +} GRUB_PACKED; + + +/* This represents an entire, parsed, appended signature */ +struct grub_appended_signature +{ + grub_size_t signature_len; /* Length of PKCS#7 data + + * metadata + magic */ + + struct module_signature sig_metadata;/* Module signature metadata */ + struct pkcs7_signedData pkcs7; /* Parsed PKCS#7 data */ +}; + +/* Trusted certificates for verifying appended signatures */ +struct x509_certificate *grub_trusted_key; + +/* + * Force gcry_rsa to be a module dependency. + * + * If we use grub_crypto_pk_rsa, then then the gcry_rsa module won't be built + * in if you add 'appendedsig' to grub-install --modules. You would need to + *
[PATCH v3 10/19] libtasn1: changes for grub compatibility
Do a few things to make libtasn1 compile as part of grub: - redefine _asn1_strcat. grub removed strcat so replace it with the appropriate calls to memcpy and strlen. Use this internally where strcat was used. - replace c_isdigit with grub_isdigit (and don't import c-ctype from gnulib) grub_isdigit provides the same functionality as c_isdigit: it determines if the input is an ASCII digit without regard for locale. - replace GL_ATTRIBUTE_PURE with __attribute__((pure)) which been supported since gcc-2.96. This avoids messing around with gnulib. - adjust libtasn1.h: drop the ASN1_API logic, it's not needed for our modules. Unconditionally support const and pure attributes and adjust header paths. - adjust header paths to "grub/libtasn1.h". - replace a 64 bit division with a call to grub_divmod64, preventing creation of __udivdi3 calls on 32 bit platforms. Signed-off-by: Daniel Axtens Reviewed-by: Stefan Berger --- v2: Clean up strcat handling, thanks Stefan Berger. --- grub-core/lib/libtasn1/lib/decoding.c | 11 +- grub-core/lib/libtasn1/lib/element.c| 3 ++- grub-core/lib/libtasn1/lib/gstr.c | 4 ++-- grub-core/lib/libtasn1/lib/int.h| 4 ++-- grub-core/lib/libtasn1/lib/parser_aux.c | 7 +++--- include/grub/libtasn1.h | 29 +++-- 6 files changed, 24 insertions(+), 34 deletions(-) diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c index b8130b956459..beeb6a176d6f 100644 --- a/grub-core/lib/libtasn1/lib/decoding.c +++ b/grub-core/lib/libtasn1/lib/decoding.c @@ -32,7 +32,8 @@ #include #include #include -#include "c-ctype.h" + +#define c_isdigit grub_isdigit #ifdef DEBUG # define warn() fprintf(stderr, "%s: %d\n", __func__, __LINE__) @@ -2016,8 +2017,8 @@ asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element, (p2->type & CONST_ASSIGN)) { strcpy (name, definitions->name); - strcat (name, "."); - strcat (name, p2->name); + _asn1_strcat (name, "."); + _asn1_strcat (name, p2->name); len = sizeof (value); result = asn1_read_value (definitions, name, value, ); @@ -2034,8 +2035,8 @@ asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element, if (p2) { strcpy (name, definitions->name); - strcat (name, "."); - strcat (name, p2->name); + _asn1_strcat (name, "."); + _asn1_strcat (name, p2->name); result = asn1_create_element (definitions, name, ); if (result == ASN1_SUCCESS) diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c index 8cd6b662cc6b..150b9b3772b3 100644 --- a/grub-core/lib/libtasn1/lib/element.c +++ b/grub-core/lib/libtasn1/lib/element.c @@ -30,9 +30,10 @@ #include "parser_aux.h" #include #include "structure.h" -#include "c-ctype.h" #include "element.h" +#define c_isdigit grub_isdigit + void _asn1_hierarchical_name (asn1_node_const node, char *name, int name_size) { diff --git a/grub-core/lib/libtasn1/lib/gstr.c b/grub-core/lib/libtasn1/lib/gstr.c index 1475ed51b74c..b729089db298 100644 --- a/grub-core/lib/libtasn1/lib/gstr.c +++ b/grub-core/lib/libtasn1/lib/gstr.c @@ -36,13 +36,13 @@ _asn1_str_cat (char *dest, size_t dest_tot_size, const char *src) if (dest_tot_size - dest_size > str_size) { - strcat (dest, src); + _asn1_strcat (dest, src); } else { if (dest_tot_size > dest_size) { - strncat (dest, src, (dest_tot_size - dest_size) - 1); + memcpy (dest + dest_size, src, (dest_tot_size - dest_size) - 1); dest[dest_tot_size - 1] = 0; } } diff --git a/grub-core/lib/libtasn1/lib/int.h b/grub-core/lib/libtasn1/lib/int.h index 404cd156232e..edfe84a0e2d6 100644 --- a/grub-core/lib/libtasn1/lib/int.h +++ b/grub-core/lib/libtasn1/lib/int.h @@ -35,7 +35,7 @@ # include # endif -# include +# include "grub/libtasn1.h" # define ASN1_SMALL_VALUE_SIZE 16 @@ -115,7 +115,7 @@ extern const tag_and_class_st _asn1_tags[]; # define _asn1_strtoul(n,e,b) strtoul((const char *) n, e, b) # define _asn1_strcmp(a,b) strcmp((const char *)a, (const char *)b) # define _asn1_strcpy(a,b) strcpy((char *)a, (const char *)b) -# define _asn1_strcat(a,b) strcat((char *)a, (const char *)b) +# define _asn1_strcat(a,b) memcpy((char *)a + strlen((const char *)a), (const char *)b, strlen((const char *)b) + 1) # if SIZEOF_UNSIGNED_LONG_INT == 8 # define _asn1_strtou64(n,e,b) strtoul((const char *) n, e, b) diff --git a/grub-core/lib/libtasn1/lib/parser_aux.c b/grub-core/lib/libtasn1/lib/parser_aux.c index c99c5a4cb0
Re: [PATCH v2 21/22] appended signatures: documentation
>> +@example >> +~Module signature appended~\n >> +@end example >> + >> +where @code{\n} represents the carriage-return character, @code{0x0a}. > > > \n is 0xa but it's called line-feed. D'oh, you're completely right, of course. Fixed. >> + >> +To enable appended signature verification, load the appendedsig module and >> an >> +x509 certificate for verification. Building the appendedsig module into the >> +core grub image is recommended. >> + >> +Certificates can be managed at boot time using the >> @pxref{trust_certificate}, >> +@pxref{distrust_certificate} and @pxref{list_certificates} commands. >> +Certificates can also be built in to the core image using the @code{--x509} >> +parameter to @command{grub-install} or @command{grub-mkimage}. >> + >> +A file can be explictly verified using the @pxref{verify_appended} command. >> + >> +Only signatures made with the SHA-256 or SHA-512 hash algorithm are >> supported, >> +and only RSA signatures are supported. >> + >> +A file can be signed with the @command{sign-file} utility supplied with the >> +Linux kernel source. For example, if you have @code{signing.key} as the >> private >> +key and @code{certificate.der} as the x509 certificate containing the >> public key: >> + >> +@example >> +sign-file SHA256 signing.key certificate.der vmlinux vmlinux.signed >> +@end example >> + >> +Enforcement of signature verification is controlled by the >> +@code{check_appended_signatures} variable. Verification will only take place >> +when files are loaded if the variable is set to @code{enforce}. If a >> +certificate is built into the grub core image with the @code{--x509} >> parameter, >> +the variable will be automatically set to @code{enforce} when the >> appendedsig >> +module is loaded. >> + >> +Unlike GPG-style signatures, not all files loaded by GRUB are required to be >> +signed. Once verification is turned on, the following file types must carry >> +appended signatures: >> + >> +@enumerate >> +@item Linux, Multiboot, BSD, XNU and Plan9 kernels >> +@item Grub modules, except those built in to the core image >> +@item Any new certificate files to be trusted >> +@end enumerate >> + >> +ACPI tables and Device Tree images will not be checked for appended >> signatures >> +but must be verified by another mechanism such as GPG-style signatures >> before >> +they will be loaded. >> + >> +No attempt is made to validate any other file type. In particular, >> +chain-loaded binaries are not verified - if your platform supports >> +chain-loading and this cannot be disabled, consider an alternative secure >> +boot mechanism. >> + >> +As with GPG-style appended signatures, signature checking does @strong{not} >> +stop an attacker with console access from dropping manually to the GRUB >> +console and executing: >> + >> +@example >> +set check_appended_signatures=no >> +@end example >> + >> +Refer to the section on password-protecting GRUB (@pxref{Authentication >> +and authorisation}) for more information on preventing this. >> + >> +Additionally, special care must be taken around the @command{loadenv} >> command, >> +which can be used to turn off @code{check_appended_signature}. >> + >> @node UEFI secure boot and shim >> @section UEFI secure boot and shim support >> > > > With this nit fixed: Reviewed-by: Stefan Berger Thanks! Kind regards, Daniel Axtens ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH v3 06/15] mm: Allow dynamically requesting additional memory regions
I genuinely do not know how I missed this, but we do need one more tweak so as not to break grub-emu builds: diff --git a/include/grub/mm.h b/include/grub/mm.h index 5d916809666c..f3bf87fa0f9a 100644 --- a/include/grub/mm.h +++ b/include/grub/mm.h @@ -42,7 +42,9 @@ typedef grub_err_t (*grub_mm_add_region_func_t) (grub_size_t, unsigned int); * Set this function pointer to enable adding memory-regions at runtime in case * a memory allocation cannot be satisfied with existing regions. */ +#ifndef GRUB_MACHINE_EMU extern grub_mm_add_region_func_t EXPORT_VAR(grub_mm_add_region_fn); +#endif void grub_mm_init_region (void *addr, grub_size_t size); void *EXPORT_FUNC(grub_calloc) (grub_size_t nmemb, grub_size_t size); I've updated by GH branches. Daniel K, are you right to fold this in when you merge this? Kind regards, Daniel Daniel Axtens writes: > From: Patrick Steinhardt > > Currently, all platforms will set up their heap on initialization of the > platform code. While this works mostly fine, it poses some limitations > on memory management on us. Most notably, allocating big chunks of > memory in the gigabyte range would require us to pre-request this many > bytes from the firmware and add it to the heap from the beginning on > some platforms like EFI. As this isn't needed for most configurations, > it is inefficient and may even negatively impact some usecases when, > e.g., chainloading. Nonetheless, allocating big chunks of memory is > required sometimes, where one example is the upcoming support for the > Argon2 key derival function in LUKS2. > > In order to avoid pre-allocating big chunks of memory, this commit > implements a runtime mechanism to add more pages to the system. When a > given allocation cannot be currently satisfied, we'll call a given > callback set up by the platform's own memory management subsystem, > asking it to add a memory area with at least `n` bytes. If this > succeeds, we retry searching for a valid memory region, which should now > succeed. > > If this fails, we try asking for `n` bytes, possibly spread across > multiple regions, in hopes that region merging means that we end up > with enough memory for things to work out. > > Signed-off-by: Patrick Steinhardt > [dja: add this to the documentation at the top of mm.c > v2: fallback to non-contiguous] > Signed-off-by: Daniel Axtens > Tested-by: Stefan Berger > Reviewed-by: Daniel Kiper > --- > grub-core/kern/mm.c | 30 ++ > include/grub/mm.h | 16 > 2 files changed, 46 insertions(+) > > diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c > index 41e5ea07dc5a..ed782e8d1f56 100644 > --- a/grub-core/kern/mm.c > +++ b/grub-core/kern/mm.c > @@ -28,6 +28,9 @@ >- multiple regions may be used as free space. They may not be >contiguous. > > + - if existing regions are insufficient to satisfy an allocation, a new > + region can be requested from firmware. > + >Regions are managed by a singly linked list, and the meta information is >stored in the beginning of each region. Space after the meta information >is used to allocate memory. > @@ -81,6 +84,7 @@ > > > grub_mm_region_t grub_mm_base; > +grub_mm_add_region_func_t grub_mm_add_region_fn; > > /* Get a header from the pointer PTR, and set *P and *R to a pointer > to the header and a pointer to its region, respectively. PTR must > @@ -437,6 +441,32 @@ grub_memalign (grub_size_t align, grub_size_t size) >count++; >goto again; > > +case 1: > + /* Request additional pages, contiguous */ > + count++; > + > + if (grub_mm_add_region_fn != NULL && > + grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_CONSECUTIVE) == > GRUB_ERR_NONE) > + goto again; > + > + /* fallthrough */ > + > +case 2: > + /* Request additional pages, anything at all */ > + count++; > + > + if (grub_mm_add_region_fn != NULL) > +{ > + /* > + * Try again even if this fails, in case it was able to partially > + * satisfy the request > + */ > + grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_NONE); > + goto again; > +} > + > + /* fallthrough */ > + > default: >break; > } > diff --git a/include/grub/mm.h b/include/grub/mm.h > index 44fde7cb9033..5d916809666c 100644 > --- a/include/grub/mm.h > +++ b/include/grub/mm.h > @@ -20,6 +20,7 @@ > #ifndef GRUB_MM_H > #define GRUB_MM_H1 > > +#include > #include > #include > #include > @@ -28,6 +29,21 @@ > # define NULL((void *) 0) > #endif >
Re: [PATCH v2 19/22] appended signatures: support verifying appended signatures
>> +static enum >> +{ check_sigs_no = 0, > > > nit: newline after '{' > fixed > >> + check_sigs_enforce = 1, >> + check_sigs_forced = 2 >> +} check_sigs = check_sigs_no; > > > What does 'forced' mean? It means that it cannot be turned of with `set check_appended_signatures=0` at the grub prompt. I'm open to better names. > >> + >> +static const char * >> +grub_env_read_sec (struct grub_env_var *var __attribute__((unused)), >> + const char *val __attribute__((unused))) >> +{ >> + if (check_sigs == check_sigs_forced) >> +return "forced"; >> + else if (check_sigs == check_sigs_enforce) >> +return "enforce"; >> + else >> +return "no"; >> +} >> + >> +static char * >> +grub_env_write_sec (struct grub_env_var *var __attribute__((unused)), >> +const char *val) >> +{ >> + /* Do not allow the value to be changed if set to forced */ >> + if (check_sigs == check_sigs_forced) >> +return grub_strdup ("forced"); >> + >> + if ((*val == '2') || (*val == 'f')) >> +check_sigs = check_sigs_forced; >> + else if ((*val == '1') || (*val == 'e')) >> +check_sigs = check_sigs_enforce; >> + else if ((*val == '0') || (*val == 'n')) >> +check_sigs = check_sigs_no; >> + >> + return grub_strdup (grub_env_read_sec (NULL, NULL)); >> +} >> + >> +static grub_err_t >> +file_read_all (grub_file_t file, grub_uint8_t **buf, grub_size_t *len) >> +{ >> + grub_off_t full_file_size; >> + grub_size_t file_size, total_read_size = 0; >> + grub_ssize_t read_size; >> + >> + full_file_size = grub_file_size (file); >> + if (full_file_size == GRUB_FILE_SIZE_UNKNOWN) >> +return grub_error (GRUB_ERR_BAD_ARGUMENT, >> + N_("Cannot read a file of unknown size into a buffer")); >> + >> + if (full_file_size > GRUB_SIZE_MAX) >> +return grub_error (GRUB_ERR_OUT_OF_RANGE, >> + N_("File is too large to read: %" PRIuGRUB_UINT64_T >> + " bytes"), full_file_size); >> + >> + file_size = (grub_size_t) full_file_size; >> + >> + *buf = grub_malloc (file_size); >> + if (!*buf) >> +return grub_error (GRUB_ERR_OUT_OF_MEMORY, >> + N_("Could not allocate file data buffer size %" >> + PRIuGRUB_SIZE), file_size); >> + >> + while (total_read_size < file_size) >> +{ >> + read_size = >> +grub_file_read (file, *buf + total_read_size, >> +file_size - total_read_size); >> + >> + if (read_size < 0) >> +{ >> + grub_free (*buf); >> + return grub_errno; >> +} >> + else if (read_size == 0) >> +{ >> + grub_free (*buf); >> + return grub_error (GRUB_ERR_IO, >> + N_("Could not read full file size (%" >> +PRIuGRUB_SIZE "), only %" PRIuGRUB_SIZE >> +" bytes read"), file_size, total_read_size); >> +} >> + >> + total_read_size += read_size; >> +} >> + *len = file_size; >> + return GRUB_ERR_NONE; >> +} >> + >> +static grub_err_t >> +read_cert_from_file (grub_file_t f, struct x509_certificate *certificate) >> +{ >> + grub_err_t err; >> + grub_uint8_t *buf; >> + grub_size_t file_size; >> + >> + err = file_read_all (f, , _size); >> + if (err != GRUB_ERR_NONE) >> +return err; >> + >> + err = parse_x509_certificate (buf, file_size, certificate); >> + if (err != GRUB_ERR_NONE) >> +{ >> + grub_free (buf); >> + return err; >> +} > > forgot grub-free(buf) ? Huh, yeah, seems so. Fixed, thank you. > >> + >> + return GRUB_ERR_NONE; >> +} >> + >> +static grub_err_t >> +extract_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize, >> +struct grub_appended_signature *sig) >> +{ >> + grub_err_t err; >> + grub_size_t pkcs7_size; >> + grub_size_t remaining_len; >> + const grub_uint8_t *appsigdata = buf + bufsize - grub_strlen (magic); >> + >> + if (bufsize < grub_strlen (magic)) >> +return grub_error (GRUB_ERR_BAD_SIGNATURE, >> + N_("File too short for signature magic")); >> + >> + if (grub_memcmp (appsigdata, (grub_uint8_t *) magic, grub_strlen (magic))) >> +return grub_error (GRUB_ERR_BAD_SIGNATURE, >> + N_("Missing or invalid signature magic")); >> + >> + remaining_len = bufsize - grub_strlen (magic); >> + >> + if (remaining_len < sizeof (struct module_signature)) >> +return grub_error (GRUB_ERR_BAD_SIGNATURE, >> + N_("File too short for signature metadata")); >> + >> + appsigdata -= sizeof (struct module_signature); >> + >> + /* extract the metadata */ >> + grub_memcpy (&(sig->sig_metadata), appsigdata, >> + sizeof (struct module_signature)); >> + >> + remaining_len -= sizeof (struct module_signature); >> + >> + if (sig->sig_metadata.id_type != 2) >> +return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("Wrong signature type")); >> + >> + pkcs7_size = grub_be_to_cpu32 (sig->sig_metadata.sig_len); >> + >> +
Re: [PATCH v2 18/22] appended signatures: parse PKCS#7 signedData and X.509 certificates
Stefan Berger writes: > On 6/30/21 4:40 AM, Daniel Axtens wrote: > >> This code allows us to parse: >> >> - PKCS#7 signedData messages. Only a single signerInfo is supported, >> which is all that the Linux sign-file utility supports creating >> out-of-the-box. Only RSA, SHA-256 and SHA-512 are supported. >> Any certificate embedded in the PKCS#7 message will be ignored. >> >> - X.509 certificates: at least enough to verify the signatures on the >> PKCS#7 messages. We expect that the certificates embedded in grub will >> be leaf certificates, not CA certificates. The parser enforces this. >> >> - X.509 certificates support the Extended Key Usage extension and handle >> it by verifying that the certificate has a single purpose, that is code >> signing. This is required because Red Hat certificates have both Key >> Usage and Extended Key Usage extensions present. >> >> Signed-off-by: Javier Martinez Canillas # EKU support >> Signed-off-by: Daniel Axtens > > A few comments below. > > >> >> --- >> >> v2 changes: >> >> - Handle the Extended Key Usage extension >> - Fix 2 leaks in x509 cert parsing >> - Improve x509 parser function name >> - Constify the data parameter in parser signatures >> - Support multiple signers in a pkcs7 message. Accept any passing sig. >> - Allow padding after a pkcs7 message in an appended signature, required >> to support my model for signers separated in time. >> - Fix a test that used GRUB_ERR_NONE rather than ASN1_SUCCESS. They're >> both 0 so no harm was done, but better to be correct. >> - Various code and comment cleanups. >> >> Thanks to Nayna Jain and Stefan Berger for their reviews. >> >> revert >> >> Signed-off-by: Daniel Axtens >> --- >> grub-core/commands/appendedsig/appendedsig.h | 118 ++ >> grub-core/commands/appendedsig/asn1util.c| 103 ++ >> grub-core/commands/appendedsig/pkcs7.c | 509 + >> grub-core/commands/appendedsig/x509.c| 1079 ++ >> 4 files changed, 1809 insertions(+) >> create mode 100644 grub-core/commands/appendedsig/appendedsig.h >> create mode 100644 grub-core/commands/appendedsig/asn1util.c >> create mode 100644 grub-core/commands/appendedsig/pkcs7.c >> create mode 100644 grub-core/commands/appendedsig/x509.c >> >> diff --git a/grub-core/commands/appendedsig/appendedsig.h >> b/grub-core/commands/appendedsig/appendedsig.h >> new file mode 100644 >> index ..327d68ddb1b7 >> --- /dev/null >> +++ b/grub-core/commands/appendedsig/appendedsig.h >> @@ -0,0 +1,118 @@ >> +/* >> + * GRUB -- GRand Unified Bootloader >> + * Copyright (C) 2020 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 >> +#include >> + >> +extern asn1_node _gnutls_gnutls_asn; >> +extern asn1_node _gnutls_pkix_asn; >> + >> +#define MAX_OID_LEN 32 >> + >> +/* >> + * One or more x509 certificates. >> + * >> + * We do limited parsing: extracting only the serial, CN and RSA public key. >> + */ >> +struct x509_certificate >> +{ >> + struct x509_certificate *next; >> + >> + grub_uint8_t *serial; >> + grub_size_t serial_len; >> + >> + char *subject; >> + grub_size_t subject_len; >> + >> + /* We only support RSA public keys. This encodes [modulus, >> publicExponent] */ >> + gcry_mpi_t mpis[2]; >> +}; >> + >> +/* >> + * A PKCS#7 signedData signerInfo. >> + */ >> +struct pkcs7_signerInfo >> +{ >> + const gcry_md_spec_t *hash; >> + gcry_mpi_t sig_mpi; >> +}; >> + >> +/* >> + * A PKCS#7 signedData message. >> + * >> + * We make no attempt to match intelligently, so we do
Re: [PATCH v2 13/22] libtasn1: changes for grub compatibility
Stefan Berger writes: > On 6/30/21 4:40 AM, Daniel Axtens wrote: >> Do a few things to make libtasn1 compile as part of grub: >> >> - redefine _asn1_strcat. grub removed strcat so replace it with the >> appropriate calls to memcpy and strlen. Use this internally where >> strcat was used. >> >> - replace c_isdigit with grub_isdigit (and don't import c-ctype from >> gnulib) grub_isdigit provides the same functionality as c_isdigit: it >> determines if the input is an ASCII digit without regard for locale. >> >> - replace GL_ATTRIBUTE_PURE with __attribute__((pure)) which been >> supported since gcc-2.96. This avoids messing around with gnulib. >> >> - adjust libtasn1.h: drop the ASN1_API logic, it's not needed for our >> modules. Unconditionally support const and pure attributes and adjust >> header paths. >> >> - adjust header paths to "grub/libtasn1.h". >> >> - replace a 64 bit division with a call to grub_divmod64, preventing >> creation of __udivdi3 calls on 32 bit platforms. >> >> Signed-off-by: Daniel Axtens >> >> --- >> >> v2: Clean up strcat handling, thanks Stefan Berger. >> --- >> grub-core/lib/libtasn1/lib/decoding.c | 11 ++- >> grub-core/lib/libtasn1/lib/element.c| 3 ++- >> grub-core/lib/libtasn1/lib/gstr.c | 4 ++-- >> grub-core/lib/libtasn1/lib/int.h| 4 ++-- >> grub-core/lib/libtasn1/lib/parser_aux.c | 7 --- >> include/grub/libtasn1.h | 26 ++--- >> 6 files changed, 22 insertions(+), 33 deletions(-) >> >> diff --git a/grub-core/lib/libtasn1/lib/decoding.c >> b/grub-core/lib/libtasn1/lib/decoding.c >> index 42f9a92b5d44..3406e1832746 100644 >> --- a/grub-core/lib/libtasn1/lib/decoding.c >> +++ b/grub-core/lib/libtasn1/lib/decoding.c >> @@ -32,7 +32,8 @@ >> #include >> #include >> #include >> -#include >> + >> +#define c_isdigit grub_isdigit >> >> #ifdef DEBUG >> # define warn() fprintf(stderr, "%s: %d\n", __func__, __LINE__) >> @@ -2008,8 +2009,8 @@ asn1_expand_octet_string (asn1_node_const definitions, >> asn1_node * element, >>(p2->type & CONST_ASSIGN)) >> { >>strcpy (name, definitions->name); >> - strcat (name, "."); >> - strcat (name, p2->name); >> + _asn1_strcat (name, "."); >> + _asn1_strcat (name, p2->name); >> >>len = sizeof (value); >>result = asn1_read_value (definitions, name, value, ); >> @@ -2026,8 +2027,8 @@ asn1_expand_octet_string (asn1_node_const definitions, >> asn1_node * element, >>if (p2) >> { >>strcpy (name, definitions->name); >> - strcat (name, "."); >> - strcat (name, p2->name); >> + _asn1_strcat (name, "."); >> + _asn1_strcat (name, p2->name); >> >>result = asn1_create_element (definitions, name, ); >>if (result == ASN1_SUCCESS) >> diff --git a/grub-core/lib/libtasn1/lib/element.c >> b/grub-core/lib/libtasn1/lib/element.c >> index 539008d8e949..ed761ff56bd9 100644 >> --- a/grub-core/lib/libtasn1/lib/element.c >> +++ b/grub-core/lib/libtasn1/lib/element.c >> @@ -30,9 +30,10 @@ >> #include "parser_aux.h" >> #include >> #include "structure.h" >> -#include "c-ctype.h" >> #include "element.h" >> >> +#define c_isdigit grub_isdigit >> + >> void >> _asn1_hierarchical_name (asn1_node_const node, char *name, int name_size) >> { >> diff --git a/grub-core/lib/libtasn1/lib/gstr.c >> b/grub-core/lib/libtasn1/lib/gstr.c >> index e91a3a151c0d..a092c9a5a24b 100644 >> --- a/grub-core/lib/libtasn1/lib/gstr.c >> +++ b/grub-core/lib/libtasn1/lib/gstr.c >> @@ -36,13 +36,13 @@ _asn1_str_cat (char *dest, size_t dest_tot_size, const >> char *src) >> >> if (dest_tot_size - dest_size > str_size) >> { >> - strcat (dest, src); >> + _asn1_strcat (dest, src); >> } >> else >> { >> if (dest_tot_size - dest_size > 0) >> { >> - strncat (dest, src, (dest_tot_size - dest_size) - 1); >> + memcpy (dest + dest_size, src, (dest_tot_size - dest_size) - 1); > > > With dest_size = strlen(dest) this is fol
[PATCH v3 10/15] efi: mm: Implement runtime addition of pages
From: Patrick Steinhardt Adjust the interface of `grub_efi_mm_add_regions ()` to take a set of `GRUB_MM_ADD_REGION_*` flags, which most notably is currently only the `CONSECUTVE` flag. This allows us to set the function up as callback for the memory subsystem and have it call out to us in case there's not enough pages available in the current heap. Signed-off-by: Patrick Steinhardt Signed-off-by: Daniel Axtens Reviewed-by: Daniel Kiper --- grub-core/kern/efi/mm.c | 15 +++ 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c index 4e594659a1ff..b5160bdffc67 100644 --- a/grub-core/kern/efi/mm.c +++ b/grub-core/kern/efi/mm.c @@ -482,7 +482,8 @@ static grub_err_t add_memory_regions (grub_efi_memory_descriptor_t *memory_map, grub_efi_uintn_t desc_size, grub_efi_memory_descriptor_t *memory_map_end, - grub_efi_uint64_t required_pages) + grub_efi_uint64_t required_pages, + unsigned int flags) { grub_efi_memory_descriptor_t *desc; @@ -496,6 +497,10 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map, start = desc->physical_start; pages = desc->num_pages; + + if (pages < required_pages && (flags & GRUB_MM_ADD_REGION_CONSECUTIVE)) + continue; + if (pages > required_pages) { start += PAGES_TO_BYTES (pages - required_pages); @@ -561,7 +566,7 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map, #endif static grub_err_t -grub_efi_mm_add_regions (grub_efi_uint64_t required_bytes) +grub_efi_mm_add_regions (grub_efi_uint64_t required_bytes, unsigned int flags) { grub_efi_memory_descriptor_t *memory_map; grub_efi_memory_descriptor_t *memory_map_end; @@ -616,7 +621,8 @@ grub_efi_mm_add_regions (grub_efi_uint64_t required_bytes) /* Allocate memory regions for GRUB's memory management. */ err = add_memory_regions (filtered_memory_map, desc_size, filtered_memory_map_end, - BYTES_TO_PAGES (required_bytes)); + BYTES_TO_PAGES (required_bytes), + flags); if (err != GRUB_ERR_NONE) return err; @@ -643,8 +649,9 @@ grub_efi_mm_add_regions (grub_efi_uint64_t required_bytes) void grub_efi_mm_init (void) { - if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE) != GRUB_ERR_NONE) + if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE, GRUB_MM_ADD_REGION_NONE) != GRUB_ERR_NONE) grub_fatal ("%s", grub_errmsg); + grub_mm_add_region_fn = grub_efi_mm_add_regions; } #if defined (__aarch64__) || defined (__arm__) || defined (__riscv) -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 13/15] ieee1275: support runtime memory claiming
On powerpc-ieee1275, we are running out of memory trying to verify anything. This is because: - we have to load an entire file into memory to verify it. This is difficult to change with appended signatures. - We only have 32MB of heap. - Distro kernels are now often around 30MB. So we want to be able to claim more memory from OpenFirmware for our heap at runtime. There are some complications: - The grub mm code isn't the only thing that will make claims on memory from OpenFirmware: * PFW/SLOF will have claimed some for their own use. * The ieee1275 loader will try to find other bits of memory that we haven't claimed to place the kernel and initrd when we go to boot. * Once we load Linux, it will also try to claim memory. It claims memory without any reference to /memory/available, it just starts at min(top of RMO, 768MB) and works down. So we need to avoid this area. See arch/powerpc/kernel/prom_init.c as of v5.11. - The smallest amount of memory a ppc64 KVM guest can have is 256MB. It doesn't work with distro kernels but can work with custom kernels. We should maintain support for that. (ppc32 can boot with even less, and we shouldn't break that either.) - Even if a VM has more memory, the memory OpenFirmware makes available as Real Memory Area can be restricted. Even with our CAS work, an LPAR on a PowerVM box is likely to have only 512MB available to OpenFirmware even if it has many gigabytes of memory allocated. What should we do? We don't know in advance how big the kernel and initrd are going to be, which makes figuring out how much memory we can take a bit tricky. To figure out how much memory we should leave unused, I looked at: - an Ubuntu 20.04.1 ppc64le pseries KVM guest: vmlinux: ~30MB initrd: ~50MB - a RHEL8.2 ppc64le pseries KVM guest: vmlinux: ~30MB initrd: ~30MB So to give us a little wriggle room, I think we want to leave at least 128MB for the loader to put vmlinux and initrd in memory and leave Linux with space to satisfy its early allocations. Allow other space to be allocated at runtime. Tested-by: Stefan Berger Signed-off-by: Daniel Axtens --- v2: reformat, rework and explain better, add debug prints with grub_dprintf --- docs/grub-dev.texi | 7 +- grub-core/kern/ieee1275/init.c | 267 ++--- 2 files changed, 254 insertions(+), 20 deletions(-) diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi index 8a20a9af2f4b..6f3f5fb1fb14 100644 --- a/docs/grub-dev.texi +++ b/docs/grub-dev.texi @@ -1059,7 +1059,10 @@ space is limited to 4GiB. GRUB allocates pages from EFI for its heap, at most 1.6 GiB. On i386-ieee1275 and powerpc-ieee1275 GRUB uses same stack as IEEE1275. -It allocates at most 32MiB for its heap. + +On i386-ieee1275 and powerpc-ieee1275, GRUB will allocate 32MiB for its heap on +startup. It may allocate more at runtime, as long as at least 128MiB remain free +in OpenFirmware. On sparc64-ieee1275 stack is 256KiB and heap is 2MiB. @@ -1087,7 +1090,7 @@ In short: @item i386-qemu @tab 60 KiB @tab < 4 GiB @item *-efi @tab ? @tab < 1.6 GiB @item i386-ieee1275 @tab ? @tab < 32 MiB -@item powerpc-ieee1275@tab ? @tab < 32 MiB +@item powerpc-ieee1275@tab ? @tab available memory - 128MiB @item sparc64-ieee1275@tab 256KiB @tab 2 MiB @item arm-uboot @tab 256KiB @tab 2 MiB @item mips(el)-qemu_mips @tab 2MiB@tab 253 MiB diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c index 60a49301ba8f..ec591e6e13ec 100644 --- a/grub-core/kern/ieee1275/init.c +++ b/grub-core/kern/ieee1275/init.c @@ -45,13 +45,23 @@ #include #endif -/* The maximum heap size we're going to claim */ +/* The maximum heap size we're going to claim at boot. Not used by sparc. */ #ifdef __i386__ #define HEAP_MAX_SIZE (unsigned long) (64 * 1024 * 1024) -#else +#else // __powerpc__ #define HEAP_MAX_SIZE (unsigned long) (32 * 1024 * 1024) #endif +/* + * The amount of OF space we will not claim here so as to leave space for + * the loader and linux to service early allocations. + * + * In 2021, Daniel Axtens claims that we should leave at least 128MB to + * ensure we can load a stock kernel and initrd on a pseries guest with + * a 512MB real memory area under PowerVM. + */ +#define RUNTIME_MIN_SPACE (128UL * 1024 * 1024) + extern char _start[]; extern char _end[]; @@ -145,16 +155,52 @@ grub_claim_heap (void) + GRUB_KERNEL_MACHINE_STACK_SIZE), 0x20); } #else -/* Helper for grub_claim_heap. */ +/* Helpers for mm on powerpc. */ + +/* + * How much memory does OF believe exists in total? + * + * This isn't necessarily the true total. It can be the total memory + * accessible in real mode for a pseries guest, for example. + */ +static grub_uint
[PATCH v3 14/15] [RFC] Add memtool module with memory allocation stress-test
When working on memory, it's nice to be able to test your work. Add a memtest module. When compiled with --enable-mm-debug, it exposes 3 commands: * lsmem - print all allocations and free space in all regions * lsfreemem - print free space in all regions * stress_big_allocs - stress test large allocations: - how much memory can we allocate in one chunk? - how many 1MB chunks can we allocate? - check that gap-filling works with a 1MB aligned 900kB alloc + a 100kB alloc. Signed-off-by: Daniel Axtens --- I haven't addressed most of the change requests yet. This will need lots of work to get to a mergable state, especially the ability to check MM_DEBUG in template files so that it can only be built if --enable-mm-debug is set, ('enable = mm_debug' or something) and that involves a lot of slow and painful build system hacking. Perhaps later on. But I have sorted out the copyright assignment so at least that is clear if anyone else wants to hack on it. --- grub-core/Makefile.core.def | 5 ++ grub-core/commands/memtools.c | 155 ++ grub-core/kern/mm.c | 4 + 3 files changed, 164 insertions(+) create mode 100644 grub-core/commands/memtools.c diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 7159948721e1..795369155a43 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -2532,3 +2532,8 @@ module = { common = commands/i386/wrmsr.c; enable = x86; }; + +module = { + name = memtools; + common = commands/memtools.c; +}; diff --git a/grub-core/commands/memtools.c b/grub-core/commands/memtools.c new file mode 100644 index ..bb4ad359e013 --- /dev/null +++ b/grub-core/commands/memtools.c @@ -0,0 +1,155 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2021 Free Software Foundation, Inc. + * Copyright (C) 2021 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 +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#ifdef MM_DEBUG + +static grub_err_t +grub_cmd_lsmem (grub_command_t cmd __attribute__ ((unused)), +int argc __attribute__ ((unused)), +char **args __attribute__ ((unused))) + +{ +#ifndef GRUB_MACHINE_EMU + grub_mm_dump(0); +#endif + + return 0; +} + +static grub_err_t +grub_cmd_lsfreemem (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) + +{ +#ifndef GRUB_MACHINE_EMU + grub_mm_dump_free(); +#endif + + return 0; +} + + +static grub_err_t +grub_cmd_stress_big_allocs (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) +{ + int i, max_mb, blocks_alloced; + void *mem; + void **blocklist; + + grub_printf ("Test 1: increasingly sized allocs to 1GB block\n"); + for (i = 1; i < 1024; i++) { +grub_printf ("%d MB . ", i); +mem = grub_malloc (i * 1024 * 1024); +if (mem == NULL) + { + grub_printf ("failed\n"); + break; + } +else + grub_free (mem); + +if (i % 10 == 0) + grub_printf ("\n"); + } + + max_mb = i - 1; + grub_printf ("Max sized allocation we did was %d MB\n", max_mb); + + grub_printf ("Test 2: 1MB at a time, max 4GB\n"); + blocklist = grub_calloc (4096, sizeof (void *)); + for (i = 0; i < 4096; i++) +{ + blocklist[i] = grub_malloc (1024 * 1024); + if (!blocklist[i]) + { + grub_printf ("Ran out of memory at iteration %d\n", i); + break; + } +} + blocks_alloced = i; + for (i = 0; i < blocks_alloced; i++) +grub_free (blocklist[i]); + + grub_printf ("\nTest 3: 1MB aligned 900kB + 100kB\n"); + //grub_mm_debug=1; + for (i = 0; i < 4096; i += 2) +{ + blocklist[i] = grub_memalign (1024 * 1024, 900 * 1024); + if (!blocklist[i]) + { + grub_printf ("Failed big allocation, iteration %d\n", i); + blocks_alloced = i; + break; + } + + blocklist[i + 1] = grub_malloc (100 * 1024); + if (!blocklist[i + 1]) + { + grub_printf ("Fa
[PATCH v3 07/15] efi: mm: Always request a fixed number of pages on init
From: Patrick Steinhardt When initializing the EFI memory subsytem, we will by default request a quarter of the available memory, bounded by a minimum/maximum value. Given that we're about to extend the EFI memory system to dynamically request additional pages from the firmware as required, this scaling of requested memory based on available memory will not make a lot of sense anymore. Remove this logic as a preparatory patch such that we'll instead defer to the runtime memory allocator. Note that ideally, we'd want to change this after dynamic requesting of pages has been implemented for the EFI platform. But because we'll need to split up initialization of the memory subsystem and the request of pages from the firmware, we'd have to duplicate quite some logic at first only to remove it afterwards again. This seems quite pointless, so we instead have patches slightly out of order. Signed-off-by: Patrick Steinhardt Signed-off-by: Daniel Axtens Reviewed-by: Daniel Kiper --- grub-core/kern/efi/mm.c | 35 +++ 1 file changed, 3 insertions(+), 32 deletions(-) diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c index d8e4114541a4..0bccd24f304f 100644 --- a/grub-core/kern/efi/mm.c +++ b/grub-core/kern/efi/mm.c @@ -38,9 +38,8 @@ a multiplier of 4KB. */ #define MEMORY_MAP_SIZE0x3000 -/* The minimum and maximum heap size for GRUB itself. */ -#define MIN_HEAP_SIZE 0x10 -#define MAX_HEAP_SIZE (1600 * 0x10) +/* The default heap size for GRUB itself in bytes. */ +#define DEFAULT_HEAP_SIZE 0x10 static void *finish_mmap_buf = 0; static grub_efi_uintn_t finish_mmap_size = 0; @@ -478,23 +477,6 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, return filtered_desc; } -/* Return the total number of pages. */ -static grub_efi_uint64_t -get_total_pages (grub_efi_memory_descriptor_t *memory_map, -grub_efi_uintn_t desc_size, -grub_efi_memory_descriptor_t *memory_map_end) -{ - grub_efi_memory_descriptor_t *desc; - grub_efi_uint64_t total = 0; - - for (desc = memory_map; - desc < memory_map_end; - desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) -total += desc->num_pages; - - return total; -} - /* Add memory regions. */ static void add_memory_regions (grub_efi_memory_descriptor_t *memory_map, @@ -583,8 +565,6 @@ grub_efi_mm_init (void) grub_efi_memory_descriptor_t *filtered_memory_map_end; grub_efi_uintn_t map_size; grub_efi_uintn_t desc_size; - grub_efi_uint64_t total_pages; - grub_efi_uint64_t required_pages; int mm_status; /* Prepare a memory region to store two memory maps. */ @@ -624,22 +604,13 @@ grub_efi_mm_init (void) filtered_memory_map_end = filter_memory_map (memory_map, filtered_memory_map, desc_size, memory_map_end); - /* By default, request a quarter of the available memory. */ - total_pages = get_total_pages (filtered_memory_map, desc_size, -filtered_memory_map_end); - required_pages = (total_pages >> 2); - if (required_pages < BYTES_TO_PAGES (MIN_HEAP_SIZE)) -required_pages = BYTES_TO_PAGES (MIN_HEAP_SIZE); - else if (required_pages > BYTES_TO_PAGES (MAX_HEAP_SIZE)) -required_pages = BYTES_TO_PAGES (MAX_HEAP_SIZE); - /* Sort the filtered descriptors, so that GRUB can allocate pages from smaller regions. */ sort_memory_map (filtered_memory_map, desc_size, filtered_memory_map_end); /* Allocate memory regions for GRUB's memory management. */ add_memory_regions (filtered_memory_map, desc_size, - filtered_memory_map_end, required_pages); + filtered_memory_map_end, BYTES_TO_PAGES (DEFAULT_HEAP_SIZE)); #if 0 /* For debug. */ -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 12/15] ieee1275: drop len -= 1 quirk in heap_init
This was apparently 'required by some firmware': commit dc9468500919 ("2007-02-12 Hollis Blanchard "). It's not clear what firmware that was, and what platform from 14 years ago which exhibited the bug then is still both in use and buggy now. It doesn't cause issues on qemu (mac99 or pseries) or under PFW for Power8. I don't have access to old Mac hardware, but if anyone feels especially strongly we can put it under some feature flag. I really want to disable it under pseries because it will mess with region merging. Signed-off-by: Daniel Axtens --- grub-core/kern/ieee1275/init.c | 1 - 1 file changed, 1 deletion(-) diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c index cf4bcf2cfbf5..60a49301ba8f 100644 --- a/grub-core/kern/ieee1275/init.c +++ b/grub-core/kern/ieee1275/init.c @@ -166,7 +166,6 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, addr = 0x18; } } - len -= 1; /* Required for some firmware. */ /* Never exceed HEAP_MAX_SIZE */ if (*total + len > HEAP_MAX_SIZE) -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 11/15] ieee1275: request memory with ibm, client-architecture-support
On PowerVM, the first time we boot a Linux partition, we may only get 256MB of real memory area, even if the partition has more memory. This isn't enough to reliably verify a kernel. Fortunately, the Power Architecture Platform Reference (PAPR) defines a method we can call to ask for more memory: the broad and powerful ibm,client-architecture-support (CAS) method. CAS can do an enormous amount of things on a PAPR platform: as well as asking for memory, you can set the supported processor level, the interrupt controller, hash vs radix mmu, and so on. If: - we are running under what we think is PowerVM (compatible property of / begins with "IBM"), and - the full amount of RMA is less than 512MB (as determined by the reg property of /memory) then call CAS as follows: (refer to the Linux on Power Architecture Reference, LoPAR, which is public, at B.5.2.3): - Use the "any" PVR value and supply 2 option vectors. - Set option vector 1 (PowerPC Server Processor Architecture Level) to "ignore". - Set option vector 2 with default or Linux-like options, including a min-rma-size of 512MB. - Set option vector 3 to request Floating Point, VMX and Decimal Floating point, but don't abort the boot if we can't get them. - Set option vector 4 to request a minimum VP percentage to 1%, which is what Linux requests, and is below the default of 10%. Without this, some systems with very large or very small configurations fail to boot. This will cause a CAS reboot and the partition will restart with 512MB of RMA. Importantly, grub will notice the 512MB and not call CAS again. Notes about the choices of parameters: - A partition can be configured with only 256MB of memory, which would mean this request couldn't be satisfied, but PFW refuses to load with only 256MB of memory, so it's a bit moot. SLOF will run fine with 256MB, but we will never call CAS under qemu/SLOF because /compatible won't begin with "IBM".) - unspecified CAS vectors take on default values. Some of these values might restrict the ability of certain hardware configurations to boot. This is why we need to specify the VP percentage in vector 4, which is in turn why we need to specify vector 3. Finally, we should have enough memory to verify a kernel, and we will reach Linux. One of the first things Linux does while still running under OpenFirmware is to call CAS with a much fuller set of options (including asking for 512MB of memory). Linux includes a much more restrictive set of PVR values and processor support levels, and this CAS invocation will likely induce another reboot. On this reboot grub will again notice the higher RMA, and not call CAS. We will get to Linux again, Linux will call CAS again, but because the values are now set for Linux this will not induce another CAS reboot and we will finally boot all the way to userspace. On all subsequent boots, everything will be configured with 512MB of RMA, so there will be no further CAS reboots from grub. (phyp is super sticky with the RMA size - it persists even on cold boots. So if you've ever booted Linux in a partition, you'll probably never have grub call CAS. It'll only ever fire the first time a partition loads grub, or if you deliberately lower the amount of memory your partition has below 512MB.) Signed-off-by: Daniel Axtens --- v2: reformat v3: extend to option vectors 3 & 4 I wrongly assumed that the most compatible way to perform CAS negotiation was to only set the minimum number of vectors required to ask for more memory. It turns out that this messes up booting if the minimum VP capacity would be less than the default 10% in vector 4. --- grub-core/kern/ieee1275/cmain.c | 3 + grub-core/kern/ieee1275/init.c | 152 +++ include/grub/ieee1275/ieee1275.h | 8 ++ 3 files changed, 163 insertions(+) diff --git a/grub-core/kern/ieee1275/cmain.c b/grub-core/kern/ieee1275/cmain.c index 4442b6a83193..b707798ec3fb 100644 --- a/grub-core/kern/ieee1275/cmain.c +++ b/grub-core/kern/ieee1275/cmain.c @@ -123,6 +123,9 @@ grub_ieee1275_find_options (void) break; } } + + if (grub_strncmp (tmp, "IBM,", 4) == 0) + grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY); } if (is_smartfirmware) diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c index 2adf4fdfc0e7..cf4bcf2cfbf5 100644 --- a/grub-core/kern/ieee1275/init.c +++ b/grub-core/kern/ieee1275/init.c @@ -200,11 +200,163 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, return 0; } +/* + * How much memory does OF believe it has? (regardless of whether + * it's accessible or not) + */ +static grub_err_t +grub_ieee1275_total_mem (grub_uint64_t *total) +{ + grub_ieee1275_phandle_t root; + grub_ieee1275_phandle_t memory; + grub_uint32_t reg[4]; + grub_ssize_t reg_size
[PATCH v3 05/15] mm: Drop unused unloading of modules on OOM
From: Patrick Steinhardt In `grub_memalign ()`, there's a commented section which would allow for unloading of unneeded modules in case where there is not enough free memory available to satisfy a request. Given that this code is never compiled in, let's remove it together with `grub_dl_unload_unneeded()` Signed-off-by: Patrick Steinhardt Signed-off-by: Daniel Axtens Reviewed-by: Daniel Kiper --- grub-core/kern/dl.c | 20 grub-core/kern/mm.c | 8 include/grub/dl.h | 1 - 3 files changed, 29 deletions(-) diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c index b1d3a103ec98..e447fd0fab4e 100644 --- a/grub-core/kern/dl.c +++ b/grub-core/kern/dl.c @@ -811,23 +811,3 @@ grub_dl_unload (grub_dl_t mod) grub_free (mod); return 1; } - -/* Unload unneeded modules. */ -void -grub_dl_unload_unneeded (void) -{ - /* Because grub_dl_remove modifies the list of modules, this - implementation is tricky. */ - grub_dl_t p = grub_dl_head; - - while (p) -{ - if (grub_dl_unload (p)) - { - p = grub_dl_head; - continue; - } - - p = p->next; -} -} diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c index a1f47c0616a2..41e5ea07dc5a 100644 --- a/grub-core/kern/mm.c +++ b/grub-core/kern/mm.c @@ -437,14 +437,6 @@ grub_memalign (grub_size_t align, grub_size_t size) count++; goto again; -#if 0 -case 1: - /* Unload unneeded modules. */ - grub_dl_unload_unneeded (); - count++; - goto again; -#endif - default: break; } diff --git a/include/grub/dl.h b/include/grub/dl.h index d0f4115fe736..acb4d42327d7 100644 --- a/include/grub/dl.h +++ b/include/grub/dl.h @@ -203,7 +203,6 @@ grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name); grub_dl_t grub_dl_load_core (void *addr, grub_size_t size); grub_dl_t EXPORT_FUNC(grub_dl_load_core_noinit) (void *addr, grub_size_t size); int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod); -extern void grub_dl_unload_unneeded (void); extern int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod); extern int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod); extern int EXPORT_FUNC(grub_dl_ref_count) (grub_dl_t mod); -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 09/15] efi: mm: Pass up errors from `add_memory_regions ()`
From: Patrick Steinhardt The function `add_memory_regions ()` is currently only called on system initialization to allocate a fixed amount of pages. As such, it didn't need to return any errors: in case it failed, we cannot proceed anyway. This will change with the upcoming support for requesting more memory from the firmware at runtime, where it doesn't make sense anymore to fail hard. Refactor the function to return an error to prepare for this. Note that this does not change the behaviour when initializing the memory system because `grub_efi_mm_init ()` knows to call `grub_fatal ()` in case `grub_efi_mm_add_regions ()` returns an error. Signed-off-by: Patrick Steinhardt [dja: clarify error messages] Signed-off-by: Daniel Axtens Reviewed-by: Daniel Kiper --- v2: Thank you Glenn and Daniel K for the feedback. This and all EFI changes were not tested on real hardware. --- grub-core/kern/efi/mm.c | 22 +++--- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c index c8d3968f7f68..4e594659a1ff 100644 --- a/grub-core/kern/efi/mm.c +++ b/grub-core/kern/efi/mm.c @@ -478,7 +478,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, } /* Add memory regions. */ -static void +static grub_err_t add_memory_regions (grub_efi_memory_descriptor_t *memory_map, grub_efi_uintn_t desc_size, grub_efi_memory_descriptor_t *memory_map_end, @@ -506,9 +506,9 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map, GRUB_EFI_ALLOCATE_ADDRESS, GRUB_EFI_LOADER_CODE); if (! addr) - grub_fatal ("cannot allocate conventional memory %p with %u pages", - (void *) ((grub_addr_t) start), - (unsigned) pages); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "Memory starting at %p (%u pages) marked as free, but EFI would not allocate", + (void *) ((grub_addr_t) start), (unsigned) pages); grub_mm_init_region (addr, PAGES_TO_BYTES (pages)); @@ -518,7 +518,11 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map, } if (required_pages > 0) -grub_fatal ("too little memory"); +return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "could not allocate all requested memory: %" PRIuGRUB_UINT64_T " pages still required after iterating EFI memory map", + required_pages); + + return GRUB_ERR_NONE; } void @@ -565,6 +569,7 @@ grub_efi_mm_add_regions (grub_efi_uint64_t required_bytes) grub_efi_memory_descriptor_t *filtered_memory_map_end; grub_efi_uintn_t map_size; grub_efi_uintn_t desc_size; + grub_err_t err; int mm_status; /* Prepare a memory region to store two memory maps. */ @@ -609,8 +614,11 @@ grub_efi_mm_add_regions (grub_efi_uint64_t required_bytes) sort_memory_map (filtered_memory_map, desc_size, filtered_memory_map_end); /* Allocate memory regions for GRUB's memory management. */ - add_memory_regions (filtered_memory_map, desc_size, - filtered_memory_map_end, BYTES_TO_PAGES (required_bytes)); + err = add_memory_regions (filtered_memory_map, desc_size, + filtered_memory_map_end, + BYTES_TO_PAGES (required_bytes)); + if (err != GRUB_ERR_NONE) +return err; #if 0 /* For debug. */ -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 08/15] efi: mm: Extract function to add memory regions
From: Patrick Steinhardt In preparation of support for runtime-allocating additional memory region, this patch extracts the function to retrieve the EFI memory map and add a subset of it to GRUB's own memory regions. Signed-off-by: Patrick Steinhardt Signed-off-by: Daniel Axtens Reviewed-by: Daniel Kiper --- grub-core/kern/efi/mm.c | 21 +++-- 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c index 0bccd24f304f..c8d3968f7f68 100644 --- a/grub-core/kern/efi/mm.c +++ b/grub-core/kern/efi/mm.c @@ -556,8 +556,8 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map, } #endif -void -grub_efi_mm_init (void) +static grub_err_t +grub_efi_mm_add_regions (grub_efi_uint64_t required_bytes) { grub_efi_memory_descriptor_t *memory_map; grub_efi_memory_descriptor_t *memory_map_end; @@ -570,7 +570,7 @@ grub_efi_mm_init (void) /* Prepare a memory region to store two memory maps. */ memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); if (! memory_map) -grub_fatal ("cannot allocate memory"); +return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for memory map"); /* Obtain descriptors for available memory. */ map_size = MEMORY_MAP_SIZE; @@ -588,14 +588,14 @@ grub_efi_mm_init (void) memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (map_size)); if (! memory_map) - grub_fatal ("cannot allocate memory"); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for new memory map"); mm_status = grub_efi_get_memory_map (_size, memory_map, 0, _size, 0); } if (mm_status < 0) -grub_fatal ("cannot get memory map"); +return grub_error (GRUB_ERR_OUT_OF_MEMORY, "error fetching memory map from EFI"); memory_map_end = NEXT_MEMORY_DESCRIPTOR (memory_map, map_size); @@ -610,7 +610,7 @@ grub_efi_mm_init (void) /* Allocate memory regions for GRUB's memory management. */ add_memory_regions (filtered_memory_map, desc_size, - filtered_memory_map_end, BYTES_TO_PAGES (DEFAULT_HEAP_SIZE)); + filtered_memory_map_end, BYTES_TO_PAGES (required_bytes)); #if 0 /* For debug. */ @@ -628,6 +628,15 @@ grub_efi_mm_init (void) /* Release the memory maps. */ grub_efi_free_pages ((grub_addr_t) memory_map, 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); + + return GRUB_ERR_NONE; +} + +void +grub_efi_mm_init (void) +{ + if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE) != GRUB_ERR_NONE) +grub_fatal ("%s", grub_errmsg); } #if defined (__aarch64__) || defined (__arm__) || defined (__riscv) -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 04/15] mm: debug support for region operations
This is handy for debugging. Enable with `set debug=regions`. Signed-off-by: Daniel Axtens Reviewed-by: Daniel Kiper --- grub-core/kern/mm.c | 19 --- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c index 6e4e8f325a05..a1f47c0616a2 100644 --- a/grub-core/kern/mm.c +++ b/grub-core/kern/mm.c @@ -115,9 +115,8 @@ grub_mm_init_region (void *addr, grub_size_t size) grub_mm_header_t h; grub_mm_region_t r, *p, q; -#if 0 - grub_printf ("Using memory for heap: start=%p, end=%p\n", addr, addr + (unsigned int) size); -#endif + grub_dprintf ("regions", "Using memory for heap: start=%p, end=%p\n", +addr, (char *) addr + (unsigned int) size); /* Exclude last 4K to avoid overflows. */ /* If addr + 0x1000 overflows then whole region is in excluded zone. */ @@ -142,8 +141,14 @@ grub_mm_init_region (void *addr, grub_size_t size) * addr q * |size-|-q->pre_size-|| */ + grub_dprintf ("regions", "Can we extend into region above?" + " %p + %" PRIxGRUB_SIZE " + %" PRIxGRUB_SIZE " ?=? %p\n", + (grub_uint8_t *) addr, size, q->pre_size, (grub_uint8_t *) q); if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q) { + grub_dprintf ("regions", "Yes: extending a region: (%p -> %p) -> (%p -> %p)\n", + q, (grub_uint8_t *) q + sizeof (*q) + q->size, + addr, (grub_uint8_t *) q + sizeof (*q) + q->size); /* * Yes, we can merge the memory starting at addr into the * existing region from below. Align up addr to GRUB_MM_ALIGN @@ -185,9 +190,15 @@ grub_mm_init_region (void *addr, grub_size_t size) * q addr * ||-q->post_size-|size-| */ + grub_dprintf ("regions", "Can we extend into region below?" +" %p + %" PRIxGRUB_SIZE " + %" PRIxGRUB_SIZE " + %" PRIxGRUB_SIZE " ?=? %p\n", +(grub_uint8_t *) q, sizeof(*q), q->size, q->post_size, (grub_uint8_t *) addr); if ((grub_uint8_t *)q + sizeof(*q) + q->size + q->post_size == (grub_uint8_t *) addr) { + grub_dprintf ("regions", "Yes: extending a region: (%p -> %p) -> (%p -> %p)\n", + q, (grub_uint8_t *) q + sizeof (*q) + q->size, + q, (grub_uint8_t *) addr + size); /* * Yes! Follow a similar pattern to above, but simpler. * Our header starts at address - post_size, which should align us @@ -206,6 +217,8 @@ grub_mm_init_region (void *addr, grub_size_t size) } } + grub_dprintf ("regions", "No: considering a new region at %p of size %" PRIxGRUB_SIZE "\n", + addr, size); /* Allocate a region from the head. */ r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN); -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 15/15] ibmvtpm: Add support for trusted boot using a vTPM 2.0
From: Stefan Berger Add support for trusted boot using a vTPM 2.0 on the IBM IEEE1275 PowerPC platform. With this patch grub now measures text and binary data into the TPM's PCRs 8 and 9 in the same way as the x86_64 platform does. This patch requires Daniel Axtens's patches for claiming more memory. For vTPM support to work on PowerVM, system driver levels 1010.30 or 1020.00 are required. Note: Previous versions of firmware levels with the 2hash-ext-log API call have a bug that, once this API call is invoked, has the effect of disabling the vTPM driver under Linux causing an error message to be displayed in the Linux kernel log. Those users will have to update their machines to the firmware levels mentioned above. Cc: Eric Snowberg Signed-off-by: Stefan Berger Signed-off-by: Daniel Axtens --- docs/grub.texi| 3 +- grub-core/Makefile.core.def | 7 ++ grub-core/commands/ieee1275/ibmvtpm.c | 152 ++ include/grub/ieee1275/ieee1275.h | 3 + 4 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 grub-core/commands/ieee1275/ibmvtpm.c diff --git a/docs/grub.texi b/docs/grub.texi index 9835c878affc..fd3790929af4 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -6087,7 +6087,8 @@ tpm module is loaded. As such it is recommended that the tpm module be built into @file{core.img} in order to avoid a potential gap in measurement between @file{core.img} being loaded and the tpm module being loaded. -Measured boot is currently only supported on EFI platforms. +Measured boot is currently only supported on EFI and IBM IEEE1275 PowerPC +platforms. @node Lockdown @section Lockdown when booting on a secure setup diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 795369155a43..b5bb10a5c302 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -1123,6 +1123,13 @@ module = { enable = powerpc_ieee1275; }; +module = { + name = tpm; + common = commands/tpm.c; + ieee1275 = commands/ieee1275/ibmvtpm.c; + enable = powerpc_ieee1275; +}; + module = { name = terminal; common = commands/terminal.c; diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c new file mode 100644 index ..e68b8448bc00 --- /dev/null +++ b/grub-core/commands/ieee1275/ibmvtpm.c @@ -0,0 +1,152 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2021 Free Software Foundation, Inc. + * Copyright (C) 2021 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/>. + * + * IBM vTPM support code. + */ + +#include +#include +#include +#include +#include +#include + +static grub_ieee1275_ihandle_t tpm_ihandle; +static grub_uint8_t tpm_version; + +#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_ihandle_t)0) + +static void +tpm_get_tpm_version (void) +{ + grub_ieee1275_phandle_t vtpm; + char buffer[20]; + + if (!grub_ieee1275_finddevice ("/vdevice/vtpm", ) && + !grub_ieee1275_get_property (vtpm, "compatible", buffer, + sizeof (buffer), NULL) && + !grub_strcmp (buffer, "IBM,vtpm20")) +tpm_version = 2; +} + +static grub_err_t +tpm_init (void) +{ + static int init_success = 0; + + if (!init_success) +{ + if (grub_ieee1275_open ("/vdevice/vtpm", _ihandle) < 0) { +tpm_ihandle = IEEE1275_IHANDLE_INVALID; +return GRUB_ERR_UNKNOWN_DEVICE; + } + + init_success = 1; + + tpm_get_tpm_version (); +} + + return GRUB_ERR_NONE; +} + +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; + } + args; + + INIT_IEEE1275_COMMON (, "call-method", 8, 2
[PATCH v3 02/15] mm: assert that we preserve header vs region alignment
grub_mm_region_init() does: h = (grub_mm_header_t) (r + 1); where h is a grub_mm_header_t and r is a grub_mm_region_t. Cells are supposed to be GRUB_MM_ALIGN aligned, but while grub_mm_dump ensures this vs the region header, grub_mm_region_init() does not. It's better to be explicit than implicit here: rather than changing grub_mm_region_init() to ALIGN_UP(), require that the struct is explictly a multiple of the header size. Signed-off-by: Daniel Axtens Reviewed-by: Daniel Kiper --- v2: Thanks Daniel K for feedback. --- include/grub/mm_private.h | 14 ++ 1 file changed, 14 insertions(+) diff --git a/include/grub/mm_private.h b/include/grub/mm_private.h index 203533cc3d42..d3f2321e14fb 100644 --- a/include/grub/mm_private.h +++ b/include/grub/mm_private.h @@ -20,6 +20,7 @@ #define GRUB_MM_PRIVATE_H 1 #include +#include /* For context, see kern/mm.c */ @@ -89,4 +90,17 @@ typedef struct grub_mm_region extern grub_mm_region_t EXPORT_VAR (grub_mm_base); #endif +static inline void +grub_mm_size_sanity_check (void) { + /* Ensure we preserve alignment when doing h = (grub_mm_header_t) (r + 1) */ + COMPILE_TIME_ASSERT ((sizeof (struct grub_mm_region) % + sizeof (struct grub_mm_header)) == 0); + + /* + * GRUB_MM_ALIGN is supposed to represent cell size, and a mm_header is + * supposed to be 1 cell. + */ + COMPILE_TIME_ASSERT (sizeof (struct grub_mm_header) == GRUB_MM_ALIGN); +} + #endif -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 03/15] mm: when adding a region, merge with region after as well as before
On x86_64-efi (at least) regions seem to be added from top down. The mm code will merge a new region with an existing region that comes immediately before the new region. This allows larger allocations to be satisfied that would otherwise be the case. On powerpc-ieee1275, however, regions are added from bottom up. So if we add 3x 32MB regions, we can still only satisfy a 32MB allocation, rather than the 96MB allocation we might otherwise be able to satisfy. * Define 'post_size' as being bytes lost to the end of an allocation due to being given weird sizes from firmware that are not multiples of GRUB_MM_ALIGN. * Allow merging of regions immediately _after_ existing regions, not just before. As with the other approach, we create an allocated block to represent the new space and the pass it to grub_free() to get the metadata right. Signed-off-by: Daniel Axtens Tested-by: Stefan Berger Reviewed-by: Daniel Kiper --- v2: Thanks Daniel K for feedback. v3: Fix alignment of comments (8 spaces vs tab) --- grub-core/kern/mm.c | 123 +++--- include/grub/mm_private.h | 9 +++ 2 files changed, 85 insertions(+), 47 deletions(-) diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c index 079c28da7cdf..6e4e8f325a05 100644 --- a/grub-core/kern/mm.c +++ b/grub-core/kern/mm.c @@ -130,53 +130,81 @@ grub_mm_init_region (void *addr, grub_size_t size) /* Attempt to merge this region with every existing region */ for (p = _mm_base, q = *p; q; p = &(q->next), q = *p) -/* - * Is the new region immediately below an existing region? That - * is, is the address of the memory we're adding now (addr) + size - * of the memory we're adding (size) + the bytes we couldn't use - * at the start of the region we're considering (q->pre_size) - * equal to the address of q? In other words, does the memory - * looks like this? - * - * addr q - * |size-|-q->pre_size-|| - */ -if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q) - { - /* -* Yes, we can merge the memory starting at addr into the -* existing region from below. Align up addr to GRUB_MM_ALIGN -* so that our new region has proper alignment. -*/ - r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN); - /* Copy the region data across */ - *r = *q; - /* Consider all the new size as pre-size */ - r->pre_size += size; - - /* -* If we have enough pre-size to create a block, create a -* block with it. Mark it as allocated and pass it to -* grub_free (), which will sort out getting it into the free -* list. -*/ - if (r->pre_size >> GRUB_MM_ALIGN_LOG2) - { - h = (grub_mm_header_t) (r + 1); - /* block size is pre-size converted to cells */ - h->size = (r->pre_size >> GRUB_MM_ALIGN_LOG2); - h->magic = GRUB_MM_ALLOC_MAGIC; - /* region size grows by block size converted back to bytes */ - r->size += h->size << GRUB_MM_ALIGN_LOG2; - /* adjust pre_size to be accurate */ - r->pre_size &= (GRUB_MM_ALIGN - 1); - *p = r; - grub_free (h + 1); - } - /* Replace the old region with the new region */ - *p = r; - return; - } +{ + /* + * Is the new region immediately below an existing region? That + * is, is the address of the memory we're adding now (addr) + size + * of the memory we're adding (size) + the bytes we couldn't use + * at the start of the region we're considering (q->pre_size) + * equal to the address of q? In other words, does the memory + * looks like this? + * + * addr q + * |size-|-q->pre_size-|| + */ + if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q) +{ + /* + * Yes, we can merge the memory starting at addr into the + * existing region from below. Align up addr to GRUB_MM_ALIGN + * so that our new region has proper alignment. + */ + r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN); + /* Copy the region data across */ + *r = *q; + /* Consider all the new size as pre-size */ + r->pre_size += size; + + /* + * If we have enough pre-size to create a block, create a + * block with it. Mark it as allocated and pass it to + * grub_free (), which will sort out getting it into the free + * list. + */ + if (r->pre_size >> GRUB_MM_ALIGN_LOG2) +{ + h = (grub_mm_header_t) (r + 1); + /* block size is pre-size converted to cells */ +
[PATCH v3 06/15] mm: Allow dynamically requesting additional memory regions
From: Patrick Steinhardt Currently, all platforms will set up their heap on initialization of the platform code. While this works mostly fine, it poses some limitations on memory management on us. Most notably, allocating big chunks of memory in the gigabyte range would require us to pre-request this many bytes from the firmware and add it to the heap from the beginning on some platforms like EFI. As this isn't needed for most configurations, it is inefficient and may even negatively impact some usecases when, e.g., chainloading. Nonetheless, allocating big chunks of memory is required sometimes, where one example is the upcoming support for the Argon2 key derival function in LUKS2. In order to avoid pre-allocating big chunks of memory, this commit implements a runtime mechanism to add more pages to the system. When a given allocation cannot be currently satisfied, we'll call a given callback set up by the platform's own memory management subsystem, asking it to add a memory area with at least `n` bytes. If this succeeds, we retry searching for a valid memory region, which should now succeed. If this fails, we try asking for `n` bytes, possibly spread across multiple regions, in hopes that region merging means that we end up with enough memory for things to work out. Signed-off-by: Patrick Steinhardt [dja: add this to the documentation at the top of mm.c v2: fallback to non-contiguous] Signed-off-by: Daniel Axtens Tested-by: Stefan Berger Reviewed-by: Daniel Kiper --- grub-core/kern/mm.c | 30 ++ include/grub/mm.h | 16 2 files changed, 46 insertions(+) diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c index 41e5ea07dc5a..ed782e8d1f56 100644 --- a/grub-core/kern/mm.c +++ b/grub-core/kern/mm.c @@ -28,6 +28,9 @@ - multiple regions may be used as free space. They may not be contiguous. + - if existing regions are insufficient to satisfy an allocation, a new + region can be requested from firmware. + Regions are managed by a singly linked list, and the meta information is stored in the beginning of each region. Space after the meta information is used to allocate memory. @@ -81,6 +84,7 @@ grub_mm_region_t grub_mm_base; +grub_mm_add_region_func_t grub_mm_add_region_fn; /* Get a header from the pointer PTR, and set *P and *R to a pointer to the header and a pointer to its region, respectively. PTR must @@ -437,6 +441,32 @@ grub_memalign (grub_size_t align, grub_size_t size) count++; goto again; +case 1: + /* Request additional pages, contiguous */ + count++; + + if (grub_mm_add_region_fn != NULL && + grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_CONSECUTIVE) == GRUB_ERR_NONE) + goto again; + + /* fallthrough */ + +case 2: + /* Request additional pages, anything at all */ + count++; + + if (grub_mm_add_region_fn != NULL) +{ + /* + * Try again even if this fails, in case it was able to partially + * satisfy the request + */ + grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_NONE); + goto again; +} + + /* fallthrough */ + default: break; } diff --git a/include/grub/mm.h b/include/grub/mm.h index 44fde7cb9033..5d916809666c 100644 --- a/include/grub/mm.h +++ b/include/grub/mm.h @@ -20,6 +20,7 @@ #ifndef GRUB_MM_H #define GRUB_MM_H 1 +#include #include #include #include @@ -28,6 +29,21 @@ # define NULL ((void *) 0) #endif +#define GRUB_MM_ADD_REGION_NONE0 +#define GRUB_MM_ADD_REGION_CONSECUTIVE (1 << 0) + +/* + * Function used to request memory regions of `grub_size_t` bytes. The second + * parameter is a bitfield of `GRUB_MM_ADD_REGION` flags. + */ +typedef grub_err_t (*grub_mm_add_region_func_t) (grub_size_t, unsigned int); + +/* + * Set this function pointer to enable adding memory-regions at runtime in case + * a memory allocation cannot be satisfied with existing regions. + */ +extern grub_mm_add_region_func_t EXPORT_VAR(grub_mm_add_region_fn); + void grub_mm_init_region (void *addr, grub_size_t size); void *EXPORT_FUNC(grub_calloc) (grub_size_t nmemb, grub_size_t size); void *EXPORT_FUNC(grub_malloc) (grub_size_t size); -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 01/15] grub-shell: only pass SeaBIOS fw_opt in for x86 BIOS platforms
This breaks the tests on pseries - just restrict it to x86 platforms that don't specify a BIOS. Signed-off-by: Daniel Axtens Reviewed-by: Daniel Kiper --- v2: Thanks Daniel K and Glenn for feedback. --- tests/util/grub-shell.in | 6 +- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/util/grub-shell.in b/tests/util/grub-shell.in index 33590baeb13c..4828afb7cc5a 100644 --- a/tests/util/grub-shell.in +++ b/tests/util/grub-shell.in @@ -376,7 +376,11 @@ if test -z "$debug"; then # workaround unfortunately causes qemu to issue a warning 'externally # provided fw_cfg item names should be prefixed with "opt/"', but there # doesn't seem to be a better option. - qemuopts="${qemuopts} -fw_cfg name=etc/sercon-port,string=0" + # + # SeaBIOS is used for i386, except on EFI. + if [ ${grub_modinfo_target_cpu} == 'i386' ] && [ ${grub_modinfo_platform} != 'efi' ]; then +qemuopts="${qemuopts} -fw_cfg name=etc/sercon-port,string=0" + fi fi if [ x$boot != xnet ] && [ x$boot != xemu ]; then -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v3 00/15] Dynamic allocation of memory regions and IBM vTPM v2
Hi, This is a small update to v2 (https://lists.gnu.org/archive/html/grub-devel/2022-03/msg00242.html) Changes since v2: - A fix to patch 11 that does IBM CAS, as it turns out my old approach caused some more extreme configurations to fail to boot. Oops. - Code style fixes (tabs vs spaces). - Add Daniel's R-Bs. This series is also available on github.com/daxtens/grub branch memrework+vtpm-202204 The v2 cover letter: This is, at long last, an updated version of my series extending Patrick's dynamic memory regions to ieee1275. Noteworthy changes: - reworked debug prints as grub_dprintfs. Folded the ieee1275 ones into the ieee1275 patches. - reworked the ieee1275 runtime memory claiming to be more resilient and better documented. - fixed comment style and hopefully addressed all other change requests. - grub will now try asking for contiguous memory and then, if that fails, for discontiguous memory - in case region merging with the discontiguous memory is sufficient to allow the eventual allocation to succeed. - The ieee1275 code agressively rounds up the size of the region for a dynamic allocation - it will now retry with a more precise size if the larger allocation fails. The memtool module is included as an RFC only and will require more work, as discussed in the patch. I've also included Stefan's vTPM patch - Stefan kindly tested that his patch worked with my memory rework series. I have added his tested-by to relevant Power-specific patches only. Kind regards, Daniel Daniel Axtens (8): grub-shell: only pass SeaBIOS fw_opt in for x86 BIOS platforms mm: assert that we preserve header vs region alignment mm: when adding a region, merge with region after as well as before mm: debug support for region operations ieee1275: request memory with ibm,client-architecture-support ieee1275: drop len -= 1 quirk in heap_init ieee1275: support runtime memory claiming [RFC] Add memtool module with memory allocation stress-test Patrick Steinhardt (6): mm: Drop unused unloading of modules on OOM mm: Allow dynamically requesting additional memory regions efi: mm: Always request a fixed number of pages on init efi: mm: Extract function to add memory regions efi: mm: Pass up errors from `add_memory_regions ()` efi: mm: Implement runtime addition of pages Stefan Berger (1): ibmvtpm: Add support for trusted boot using a vTPM 2.0 docs/grub-dev.texi| 7 +- docs/grub.texi| 3 +- grub-core/Makefile.core.def | 12 + grub-core/commands/ieee1275/ibmvtpm.c | 152 ++ grub-core/commands/memtools.c | 155 ++ grub-core/kern/dl.c | 20 -- grub-core/kern/efi/mm.c | 83 +++--- grub-core/kern/ieee1275/cmain.c | 3 + grub-core/kern/ieee1275/init.c| 410 +- grub-core/kern/mm.c | 178 +++ include/grub/dl.h | 1 - include/grub/ieee1275/ieee1275.h | 11 + include/grub/mm.h | 16 + include/grub/mm_private.h | 23 ++ tests/util/grub-shell.in | 6 +- 15 files changed, 942 insertions(+), 138 deletions(-) create mode 100644 grub-core/commands/ieee1275/ibmvtpm.c create mode 100644 grub-core/commands/memtools.c -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 10/15] efi: mm: Implement runtime addition of pages
From: Patrick Steinhardt Adjust the interface of `grub_efi_mm_add_regions ()` to take a set of `GRUB_MM_ADD_REGION_*` flags, which most notably is currently only the `CONSECUTVE` flag. This allows us to set the function up as callback for the memory subsystem and have it call out to us in case there's not enough pages available in the current heap. Signed-off-by: Patrick Steinhardt Signed-off-by: Daniel Axtens Reviewed-by: Daniel Kiper --- grub-core/kern/efi/mm.c | 15 +++ 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c index 4e594659a1ff..b5160bdffc67 100644 --- a/grub-core/kern/efi/mm.c +++ b/grub-core/kern/efi/mm.c @@ -482,7 +482,8 @@ static grub_err_t add_memory_regions (grub_efi_memory_descriptor_t *memory_map, grub_efi_uintn_t desc_size, grub_efi_memory_descriptor_t *memory_map_end, - grub_efi_uint64_t required_pages) + grub_efi_uint64_t required_pages, + unsigned int flags) { grub_efi_memory_descriptor_t *desc; @@ -496,6 +497,10 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map, start = desc->physical_start; pages = desc->num_pages; + + if (pages < required_pages && (flags & GRUB_MM_ADD_REGION_CONSECUTIVE)) + continue; + if (pages > required_pages) { start += PAGES_TO_BYTES (pages - required_pages); @@ -561,7 +566,7 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map, #endif static grub_err_t -grub_efi_mm_add_regions (grub_efi_uint64_t required_bytes) +grub_efi_mm_add_regions (grub_efi_uint64_t required_bytes, unsigned int flags) { grub_efi_memory_descriptor_t *memory_map; grub_efi_memory_descriptor_t *memory_map_end; @@ -616,7 +621,8 @@ grub_efi_mm_add_regions (grub_efi_uint64_t required_bytes) /* Allocate memory regions for GRUB's memory management. */ err = add_memory_regions (filtered_memory_map, desc_size, filtered_memory_map_end, - BYTES_TO_PAGES (required_bytes)); + BYTES_TO_PAGES (required_bytes), + flags); if (err != GRUB_ERR_NONE) return err; @@ -643,8 +649,9 @@ grub_efi_mm_add_regions (grub_efi_uint64_t required_bytes) void grub_efi_mm_init (void) { - if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE) != GRUB_ERR_NONE) + if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE, GRUB_MM_ADD_REGION_NONE) != GRUB_ERR_NONE) grub_fatal ("%s", grub_errmsg); + grub_mm_add_region_fn = grub_efi_mm_add_regions; } #if defined (__aarch64__) || defined (__arm__) || defined (__riscv) -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 04/15] mm: debug support for region operations
This is handy for debugging. Enable with `set debug=regions`. Signed-off-by: Daniel Axtens --- grub-core/kern/mm.c | 19 --- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c index 94e78f9a910d..f36499865632 100644 --- a/grub-core/kern/mm.c +++ b/grub-core/kern/mm.c @@ -115,9 +115,8 @@ grub_mm_init_region (void *addr, grub_size_t size) grub_mm_header_t h; grub_mm_region_t r, *p, q; -#if 0 - grub_printf ("Using memory for heap: start=%p, end=%p\n", addr, addr + (unsigned int) size); -#endif + grub_dprintf ("regions", "Using memory for heap: start=%p, end=%p\n", +addr, (char *) addr + (unsigned int) size); /* Exclude last 4K to avoid overflows. */ /* If addr + 0x1000 overflows then whole region is in excluded zone. */ @@ -142,8 +141,14 @@ grub_mm_init_region (void *addr, grub_size_t size) * addr q * |size-|-q->pre_size-|| */ + grub_dprintf ("regions", "Can we extend into region above?" +" %p + %" PRIxGRUB_SIZE " + %" PRIxGRUB_SIZE " ?=? %p\n", +(grub_uint8_t *) addr, size, q->pre_size, (grub_uint8_t *) q); if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q) { + grub_dprintf ("regions", "Yes: extending a region: (%p -> %p) -> (%p -> %p)\n", +q, (grub_uint8_t *) q + sizeof (*q) + q->size, +addr, (grub_uint8_t *) q + sizeof (*q) + q->size); /* * Yes, we can merge the memory starting at addr into the * existing region from below. Align up addr to GRUB_MM_ALIGN @@ -185,9 +190,15 @@ grub_mm_init_region (void *addr, grub_size_t size) * q addr * ||-q->post_size-|size-| */ + grub_dprintf ("regions", "Can we extend into region below?" +" %p + %" PRIxGRUB_SIZE " + %" PRIxGRUB_SIZE " + %" PRIxGRUB_SIZE " ?=? %p\n", +(grub_uint8_t *) q, sizeof(*q), q->size, q->post_size, (grub_uint8_t *) addr); if ((grub_uint8_t *)q + sizeof(*q) + q->size + q->post_size == (grub_uint8_t *) addr) { + grub_dprintf ("regions", "Yes: extending a region: (%p -> %p) -> (%p -> %p)\n", +q, (grub_uint8_t *) q + sizeof (*q) + q->size, +q, (grub_uint8_t *) addr + size); /* * Yes! Follow a similar pattern to above, but simpler. * Our header starts at address - post_size, which should align us @@ -206,6 +217,8 @@ grub_mm_init_region (void *addr, grub_size_t size) } } + grub_dprintf ("regions", "No: considering a new region at %p of size %" PRIxGRUB_SIZE "\n", +addr, size); /* Allocate a region from the head. */ r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN); -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 14/15] [RFC] Add memtool module with memory allocation stress-test
When working on memory, it's nice to be able to test your work. Add a memtest module. When compiled with --enable-mm-debug, it exposes 3 commands: * lsmem - print all allocations and free space in all regions * lsfreemem - print free space in all regions * stress_big_allocs - stress test large allocations: - how much memory can we allocate in one chunk? - how many 1MB chunks can we allocate? - check that gap-filling works with a 1MB aligned 900kB alloc + a 100kB alloc. Signed-off-by: Daniel Axtens --- I haven't addressed most of the change requests yet. This will need lots of work to get to a mergable state, especially the ability to check MM_DEBUG in template files so that it can only be built if --enable-mm-debug is set, ('enable = mm_debug' or something) and that involves a lot of slow and painful build system hacking. Perhaps later on. But I have sorted out the copyright assignment so at least that is clear if anyone else wants to hack on it. --- grub-core/Makefile.core.def | 5 ++ grub-core/commands/memtools.c | 155 ++ grub-core/kern/mm.c | 4 + 3 files changed, 164 insertions(+) create mode 100644 grub-core/commands/memtools.c diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index cada67b667ff..ce7d79d38e5b 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -2530,3 +2530,8 @@ module = { common = commands/i386/wrmsr.c; enable = x86; }; + +module = { + name = memtools; + common = commands/memtools.c; +}; diff --git a/grub-core/commands/memtools.c b/grub-core/commands/memtools.c new file mode 100644 index ..bb4ad359e013 --- /dev/null +++ b/grub-core/commands/memtools.c @@ -0,0 +1,155 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2021 Free Software Foundation, Inc. + * Copyright (C) 2021 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 +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#ifdef MM_DEBUG + +static grub_err_t +grub_cmd_lsmem (grub_command_t cmd __attribute__ ((unused)), +int argc __attribute__ ((unused)), +char **args __attribute__ ((unused))) + +{ +#ifndef GRUB_MACHINE_EMU + grub_mm_dump(0); +#endif + + return 0; +} + +static grub_err_t +grub_cmd_lsfreemem (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) + +{ +#ifndef GRUB_MACHINE_EMU + grub_mm_dump_free(); +#endif + + return 0; +} + + +static grub_err_t +grub_cmd_stress_big_allocs (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) +{ + int i, max_mb, blocks_alloced; + void *mem; + void **blocklist; + + grub_printf ("Test 1: increasingly sized allocs to 1GB block\n"); + for (i = 1; i < 1024; i++) { +grub_printf ("%d MB . ", i); +mem = grub_malloc (i * 1024 * 1024); +if (mem == NULL) + { + grub_printf ("failed\n"); + break; + } +else + grub_free (mem); + +if (i % 10 == 0) + grub_printf ("\n"); + } + + max_mb = i - 1; + grub_printf ("Max sized allocation we did was %d MB\n", max_mb); + + grub_printf ("Test 2: 1MB at a time, max 4GB\n"); + blocklist = grub_calloc (4096, sizeof (void *)); + for (i = 0; i < 4096; i++) +{ + blocklist[i] = grub_malloc (1024 * 1024); + if (!blocklist[i]) + { + grub_printf ("Ran out of memory at iteration %d\n", i); + break; + } +} + blocks_alloced = i; + for (i = 0; i < blocks_alloced; i++) +grub_free (blocklist[i]); + + grub_printf ("\nTest 3: 1MB aligned 900kB + 100kB\n"); + //grub_mm_debug=1; + for (i = 0; i < 4096; i += 2) +{ + blocklist[i] = grub_memalign (1024 * 1024, 900 * 1024); + if (!blocklist[i]) + { + grub_printf ("Failed big allocation, iteration %d\n", i); + blocks_alloced = i; + break; + } + + blocklist[i + 1] = grub_malloc (100 * 1024); + if (!blocklist[i + 1]) + { + grub_printf ("Fa
[PATCH v2 13/15] ieee1275: support runtime memory claiming
On powerpc-ieee1275, we are running out of memory trying to verify anything. This is because: - we have to load an entire file into memory to verify it. This is difficult to change with appended signatures. - We only have 32MB of heap. - Distro kernels are now often around 30MB. So we want to be able to claim more memory from OpenFirmware for our heap at runtime. There are some complications: - The grub mm code isn't the only thing that will make claims on memory from OpenFirmware: * PFW/SLOF will have claimed some for their own use. * The ieee1275 loader will try to find other bits of memory that we haven't claimed to place the kernel and initrd when we go to boot. * Once we load Linux, it will also try to claim memory. It claims memory without any reference to /memory/available, it just starts at min(top of RMO, 768MB) and works down. So we need to avoid this area. See arch/powerpc/kernel/prom_init.c as of v5.11. - The smallest amount of memory a ppc64 KVM guest can have is 256MB. It doesn't work with distro kernels but can work with custom kernels. We should maintain support for that. (ppc32 can boot with even less, and we shouldn't break that either.) - Even if a VM has more memory, the memory OpenFirmware makes available as Real Memory Area can be restricted. Even with our CAS work, an LPAR on a PowerVM box is likely to have only 512MB available to OpenFirmware even if it has many gigabytes of memory allocated. What should we do? We don't know in advance how big the kernel and initrd are going to be, which makes figuring out how much memory we can take a bit tricky. To figure out how much memory we should leave unused, I looked at: - an Ubuntu 20.04.1 ppc64le pseries KVM guest: vmlinux: ~30MB initrd: ~50MB - a RHEL8.2 ppc64le pseries KVM guest: vmlinux: ~30MB initrd: ~30MB So to give us a little wriggle room, I think we want to leave at least 128MB for the loader to put vmlinux and initrd in memory and leave Linux with space to satisfy its early allocations. Allow other space to be allocated at runtime. Tested-by: Stefan Berger Signed-off-by: Daniel Axtens --- v2: reformat, rework and explain better, add debug prints with grub_dprintf --- docs/grub-dev.texi | 7 +- grub-core/kern/ieee1275/init.c | 267 ++--- 2 files changed, 254 insertions(+), 20 deletions(-) diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi index 8a20a9af2f4b..6f3f5fb1fb14 100644 --- a/docs/grub-dev.texi +++ b/docs/grub-dev.texi @@ -1059,7 +1059,10 @@ space is limited to 4GiB. GRUB allocates pages from EFI for its heap, at most 1.6 GiB. On i386-ieee1275 and powerpc-ieee1275 GRUB uses same stack as IEEE1275. -It allocates at most 32MiB for its heap. + +On i386-ieee1275 and powerpc-ieee1275, GRUB will allocate 32MiB for its heap on +startup. It may allocate more at runtime, as long as at least 128MiB remain free +in OpenFirmware. On sparc64-ieee1275 stack is 256KiB and heap is 2MiB. @@ -1087,7 +1090,7 @@ In short: @item i386-qemu @tab 60 KiB @tab < 4 GiB @item *-efi @tab ? @tab < 1.6 GiB @item i386-ieee1275 @tab ? @tab < 32 MiB -@item powerpc-ieee1275@tab ? @tab < 32 MiB +@item powerpc-ieee1275@tab ? @tab available memory - 128MiB @item sparc64-ieee1275@tab 256KiB @tab 2 MiB @item arm-uboot @tab 256KiB @tab 2 MiB @item mips(el)-qemu_mips @tab 2MiB@tab 253 MiB diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c index eeb11dd40ded..7805f6c6fcc5 100644 --- a/grub-core/kern/ieee1275/init.c +++ b/grub-core/kern/ieee1275/init.c @@ -45,13 +45,23 @@ #include #endif -/* The maximum heap size we're going to claim */ +/* The maximum heap size we're going to claim at boot. Not used by sparc. */ #ifdef __i386__ #define HEAP_MAX_SIZE (unsigned long) (64 * 1024 * 1024) -#else +#else // __powerpc__ #define HEAP_MAX_SIZE (unsigned long) (32 * 1024 * 1024) #endif +/* + * The amount of OF space we will not claim here so as to leave space for + * the loader and linux to service early allocations. + * + * In 2021, Daniel Axtens claims that we should leave at least 128MB to + * ensure we can load a stock kernel and initrd on a pseries guest with + * a 512MB real memory area under PowerVM. + */ +#define RUNTIME_MIN_SPACE (128UL * 1024 * 1024) + extern char _start[]; extern char _end[]; @@ -145,16 +155,52 @@ grub_claim_heap (void) + GRUB_KERNEL_MACHINE_STACK_SIZE), 0x20); } #else -/* Helper for grub_claim_heap. */ +/* Helpers for mm on powerpc. */ + +/* + * How much memory does OF believe exists in total? + * + * This isn't necessarily the true total. It can be the total memory + * accessible in real mode for a pseries guest, for example. + */ +static grub_uint
[PATCH v2 15/15] ibmvtpm: Add support for trusted boot using a vTPM 2.0
From: Stefan Berger Add support for trusted boot using a vTPM 2.0 on the IBM IEEE1275 PowerPC platform. With this patch grub now measures text and binary data into the TPM's PCRs 8 and 9 in the same way as the x86_64 platform does. This patch requires Daniel Axtens's patches for claiming more memory. For vTPM support to work on PowerVM, system driver levels 1010.30 or 1020.00 are required. Note: Previous versions of firmware levels with the 2hash-ext-log API call have a bug that, once this API call is invoked, has the effect of disabling the vTPM driver under Linux causing an error message to be displayed in the Linux kernel log. Those users will have to update their machines to the firmware levels mentioned above. Cc: Eric Snowberg Signed-off-by: Stefan Berger Signed-off-by: Daniel Axtens --- docs/grub.texi| 3 +- grub-core/Makefile.core.def | 7 ++ grub-core/commands/ieee1275/ibmvtpm.c | 152 ++ include/grub/ieee1275/ieee1275.h | 3 + 4 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 grub-core/commands/ieee1275/ibmvtpm.c diff --git a/docs/grub.texi b/docs/grub.texi index caba8befb4ef..54063430c717 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -6084,7 +6084,8 @@ tpm module is loaded. As such it is recommended that the tpm module be built into @file{core.img} in order to avoid a potential gap in measurement between @file{core.img} being loaded and the tpm module being loaded. -Measured boot is currently only supported on EFI platforms. +Measured boot is currently only supported on EFI and IBM IEEE1275 PowerPC +platforms. @node Lockdown @section Lockdown when booting on a secure setup diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index ce7d79d38e5b..eaf43773 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -1121,6 +1121,13 @@ module = { enable = powerpc_ieee1275; }; +module = { + name = tpm; + common = commands/tpm.c; + ieee1275 = commands/ieee1275/ibmvtpm.c; + enable = powerpc_ieee1275; +}; + module = { name = terminal; common = commands/terminal.c; diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c new file mode 100644 index ..e68b8448bc00 --- /dev/null +++ b/grub-core/commands/ieee1275/ibmvtpm.c @@ -0,0 +1,152 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2021 Free Software Foundation, Inc. + * Copyright (C) 2021 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/>. + * + * IBM vTPM support code. + */ + +#include +#include +#include +#include +#include +#include + +static grub_ieee1275_ihandle_t tpm_ihandle; +static grub_uint8_t tpm_version; + +#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_ihandle_t)0) + +static void +tpm_get_tpm_version (void) +{ + grub_ieee1275_phandle_t vtpm; + char buffer[20]; + + if (!grub_ieee1275_finddevice ("/vdevice/vtpm", ) && + !grub_ieee1275_get_property (vtpm, "compatible", buffer, + sizeof (buffer), NULL) && + !grub_strcmp (buffer, "IBM,vtpm20")) +tpm_version = 2; +} + +static grub_err_t +tpm_init (void) +{ + static int init_success = 0; + + if (!init_success) +{ + if (grub_ieee1275_open ("/vdevice/vtpm", _ihandle) < 0) { +tpm_ihandle = IEEE1275_IHANDLE_INVALID; +return GRUB_ERR_UNKNOWN_DEVICE; + } + + init_success = 1; + + tpm_get_tpm_version (); +} + + return GRUB_ERR_NONE; +} + +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; + } + args; + + INIT_IEEE1275_COMMON (, "call-method", 8, 2
[PATCH v2 11/15] ieee1275: request memory with ibm, client-architecture-support
On PowerVM, the first time we boot a Linux partition, we may only get 256MB of real memory area, even if the partition has more memory. This isn't really enough. Fortunately, the Power Architecture Platform Reference (PAPR) defines a method we can call to ask for more memory. This is part of the broad and powerful ibm,client-architecture-support (CAS) method. CAS can do an enormous amount of things on a PAPR platform: as well as asking for memory, you can set the supported processor level, the interrupt controller, hash vs radix mmu, and so on. We want to touch as little of this as possible because we don't want to step on the toes of the future OS. If: - we are running under what we think is PowerVM (compatible property of / begins with "IBM"), and - the full amount of RMA is less than 512MB (as determined by the reg property of /memory) then call CAS as follows: (refer to the Linux on Power Architecture Reference, LoPAR, which is public, at B.5.2.3): - Use the "any" PVR value and supply 2 option vectors. - Set option vector 1 (PowerPC Server Processor Architecture Level) to "ignore". - Set option vector 2 with default or Linux-like options, including a min-rma-size of 512MB. This will cause a CAS reboot and the partition will restart with 512MB of RMA. Grub will notice the 512MB and not call CAS again. (A partition can be configured with only 256MB of memory, which would mean this request couldn't be satisfied, but PFW refuses to load with only 256MB of memory, so it's a bit moot. SLOF will run fine with 256MB, but we will never call CAS under qemu/SLOF because /compatible won't begin with "IBM".) One of the first things Linux does while still running under OpenFirmware is to call CAS with a much fuller set of options (including asking for 512MB of memory). This includes a much more restrictive set of PVR values and processor support levels, and this will induce another reboot. On this reboot grub will again notice the higher RMA, and not call CAS. We will get to Linux, Linux will call CAS but because the values are now set for Linux this will not induce another CAS reboot and we will finally boot. On all subsequent boots, everything will be configured with 512MB of RMA and all the settings Linux likes, so there will be no further CAS reboots. (phyp is super sticky with the RMA size - it persists even on cold boots. So if you've ever booted Linux in a partition, you'll probably never have grub call CAS. It'll only ever fire the first time a partition loads grub, or if you deliberately lower the amount of memory your partition has below 512MB.) Signed-off-by: Daniel Axtens --- v2: reformat --- grub-core/kern/ieee1275/cmain.c | 3 + grub-core/kern/ieee1275/init.c | 144 +++ include/grub/ieee1275/ieee1275.h | 8 ++ 3 files changed, 155 insertions(+) diff --git a/grub-core/kern/ieee1275/cmain.c b/grub-core/kern/ieee1275/cmain.c index 4442b6a83193..b707798ec3fb 100644 --- a/grub-core/kern/ieee1275/cmain.c +++ b/grub-core/kern/ieee1275/cmain.c @@ -123,6 +123,9 @@ grub_ieee1275_find_options (void) break; } } + + if (grub_strncmp (tmp, "IBM,", 4) == 0) + grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY); } if (is_smartfirmware) diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c index 2adf4fdfc0e7..d44efd99cfca 100644 --- a/grub-core/kern/ieee1275/init.c +++ b/grub-core/kern/ieee1275/init.c @@ -200,11 +200,155 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, return 0; } +/* + * How much memory does OF believe it has? (regardless of whether + * it's accessible or not) + */ +static grub_err_t +grub_ieee1275_total_mem (grub_uint64_t *total) +{ + grub_ieee1275_phandle_t root; + grub_ieee1275_phandle_t memory; + grub_uint32_t reg[4]; + grub_ssize_t reg_size; + grub_uint32_t address_cells = 1; + grub_uint32_t size_cells = 1; + grub_uint64_t size; + + /* If we fail to get to the end, report 0. */ + *total = 0; + + /* Determine the format of each entry in `reg'. */ + grub_ieee1275_finddevice ("/", ); + grub_ieee1275_get_integer_property (root, "#address-cells", _cells, + sizeof address_cells, 0); + grub_ieee1275_get_integer_property (root, "#size-cells", _cells, + sizeof size_cells, 0); + + if (size_cells > address_cells) +address_cells = size_cells; + + /* Load `/memory/reg'. */ + if (grub_ieee1275_finddevice ("/memory", )) +return grub_error (GRUB_ERR_UNKNOWN_DEVICE, + "couldn't find /memory node"); + if (grub_ieee1275_get_integer_property (memory, "reg", reg, + sizeof reg, _size)) +return grub_error (GRUB_ERR_UNKNOWN_DEVICE, +
[PATCH v2 12/15] ieee1275: drop len -= 1 quirk in heap_init
This was apparently 'required by some firmware': commit dc9468500919 ("2007-02-12 Hollis Blanchard "). It's not clear what firmware that was, and what platform from 14 years ago which exhibited the bug then is still both in use and buggy now. It doesn't cause issues on qemu (mac99 or pseries) or under PFW for Power8. I don't have access to old Mac hardware, but if anyone feels especially strongly we can put it under some feature flag. I really want to disable it under pseries because it will mess with region merging. Signed-off-by: Daniel Axtens --- grub-core/kern/ieee1275/init.c | 1 - 1 file changed, 1 deletion(-) diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c index d44efd99cfca..eeb11dd40ded 100644 --- a/grub-core/kern/ieee1275/init.c +++ b/grub-core/kern/ieee1275/init.c @@ -166,7 +166,6 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, addr = 0x18; } } - len -= 1; /* Required for some firmware. */ /* Never exceed HEAP_MAX_SIZE */ if (*total + len > HEAP_MAX_SIZE) -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 09/15] efi: mm: Pass up errors from `add_memory_regions ()`
From: Patrick Steinhardt The function `add_memory_regions ()` is currently only called on system initialization to allocate a fixed amount of pages. As such, it didn't need to return any errors: in case it failed, we cannot proceed anyway. This will change with the upcoming support for requesting more memory from the firmware at runtime, where it doesn't make sense anymore to fail hard. Refactor the function to return an error to prepare for this. Note that this does not change the behaviour when initializing the memory system because `grub_efi_mm_init ()` knows to call `grub_fatal ()` in case `grub_efi_mm_add_regions ()` returns an error. Signed-off-by: Patrick Steinhardt [dja: clarify error messages] Signed-off-by: Daniel Axtens --- v2: Thank you Glenn and Daniel K for the feedback. This and all EFI changes were not tested on real hardware. --- grub-core/kern/efi/mm.c | 22 +++--- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c index c8d3968f7f68..4e594659a1ff 100644 --- a/grub-core/kern/efi/mm.c +++ b/grub-core/kern/efi/mm.c @@ -478,7 +478,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, } /* Add memory regions. */ -static void +static grub_err_t add_memory_regions (grub_efi_memory_descriptor_t *memory_map, grub_efi_uintn_t desc_size, grub_efi_memory_descriptor_t *memory_map_end, @@ -506,9 +506,9 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map, GRUB_EFI_ALLOCATE_ADDRESS, GRUB_EFI_LOADER_CODE); if (! addr) - grub_fatal ("cannot allocate conventional memory %p with %u pages", - (void *) ((grub_addr_t) start), - (unsigned) pages); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "Memory starting at %p (%u pages) marked as free, but EFI would not allocate", + (void *) ((grub_addr_t) start), (unsigned) pages); grub_mm_init_region (addr, PAGES_TO_BYTES (pages)); @@ -518,7 +518,11 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map, } if (required_pages > 0) -grub_fatal ("too little memory"); +return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "could not allocate all requested memory: %" PRIuGRUB_UINT64_T " pages still required after iterating EFI memory map", + required_pages); + + return GRUB_ERR_NONE; } void @@ -565,6 +569,7 @@ grub_efi_mm_add_regions (grub_efi_uint64_t required_bytes) grub_efi_memory_descriptor_t *filtered_memory_map_end; grub_efi_uintn_t map_size; grub_efi_uintn_t desc_size; + grub_err_t err; int mm_status; /* Prepare a memory region to store two memory maps. */ @@ -609,8 +614,11 @@ grub_efi_mm_add_regions (grub_efi_uint64_t required_bytes) sort_memory_map (filtered_memory_map, desc_size, filtered_memory_map_end); /* Allocate memory regions for GRUB's memory management. */ - add_memory_regions (filtered_memory_map, desc_size, - filtered_memory_map_end, BYTES_TO_PAGES (required_bytes)); + err = add_memory_regions (filtered_memory_map, desc_size, + filtered_memory_map_end, + BYTES_TO_PAGES (required_bytes)); + if (err != GRUB_ERR_NONE) +return err; #if 0 /* For debug. */ -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 08/15] efi: mm: Extract function to add memory regions
From: Patrick Steinhardt In preparation of support for runtime-allocating additional memory region, this patch extracts the function to retrieve the EFI memory map and add a subset of it to GRUB's own memory regions. Signed-off-by: Patrick Steinhardt Signed-off-by: Daniel Axtens --- grub-core/kern/efi/mm.c | 21 +++-- 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c index 0bccd24f304f..c8d3968f7f68 100644 --- a/grub-core/kern/efi/mm.c +++ b/grub-core/kern/efi/mm.c @@ -556,8 +556,8 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map, } #endif -void -grub_efi_mm_init (void) +static grub_err_t +grub_efi_mm_add_regions (grub_efi_uint64_t required_bytes) { grub_efi_memory_descriptor_t *memory_map; grub_efi_memory_descriptor_t *memory_map_end; @@ -570,7 +570,7 @@ grub_efi_mm_init (void) /* Prepare a memory region to store two memory maps. */ memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); if (! memory_map) -grub_fatal ("cannot allocate memory"); +return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for memory map"); /* Obtain descriptors for available memory. */ map_size = MEMORY_MAP_SIZE; @@ -588,14 +588,14 @@ grub_efi_mm_init (void) memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (map_size)); if (! memory_map) - grub_fatal ("cannot allocate memory"); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for new memory map"); mm_status = grub_efi_get_memory_map (_size, memory_map, 0, _size, 0); } if (mm_status < 0) -grub_fatal ("cannot get memory map"); +return grub_error (GRUB_ERR_OUT_OF_MEMORY, "error fetching memory map from EFI"); memory_map_end = NEXT_MEMORY_DESCRIPTOR (memory_map, map_size); @@ -610,7 +610,7 @@ grub_efi_mm_init (void) /* Allocate memory regions for GRUB's memory management. */ add_memory_regions (filtered_memory_map, desc_size, - filtered_memory_map_end, BYTES_TO_PAGES (DEFAULT_HEAP_SIZE)); + filtered_memory_map_end, BYTES_TO_PAGES (required_bytes)); #if 0 /* For debug. */ @@ -628,6 +628,15 @@ grub_efi_mm_init (void) /* Release the memory maps. */ grub_efi_free_pages ((grub_addr_t) memory_map, 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); + + return GRUB_ERR_NONE; +} + +void +grub_efi_mm_init (void) +{ + if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE) != GRUB_ERR_NONE) +grub_fatal ("%s", grub_errmsg); } #if defined (__aarch64__) || defined (__arm__) || defined (__riscv) -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 07/15] efi: mm: Always request a fixed number of pages on init
From: Patrick Steinhardt When initializing the EFI memory subsytem, we will by default request a quarter of the available memory, bounded by a minimum/maximum value. Given that we're about to extend the EFI memory system to dynamically request additional pages from the firmware as required, this scaling of requested memory based on available memory will not make a lot of sense anymore. Remove this logic as a preparatory patch such that we'll instead defer to the runtime memory allocator. Note that ideally, we'd want to change this after dynamic requesting of pages has been implemented for the EFI platform. But because we'll need to split up initialization of the memory subsystem and the request of pages from the firmware, we'd have to duplicate quite some logic at first only to remove it afterwards again. This seems quite pointless, so we instead have patches slightly out of order. Signed-off-by: Patrick Steinhardt Signed-off-by: Daniel Axtens Reviewed-by: Daniel Kiper --- grub-core/kern/efi/mm.c | 35 +++ 1 file changed, 3 insertions(+), 32 deletions(-) diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c index d8e4114541a4..0bccd24f304f 100644 --- a/grub-core/kern/efi/mm.c +++ b/grub-core/kern/efi/mm.c @@ -38,9 +38,8 @@ a multiplier of 4KB. */ #define MEMORY_MAP_SIZE0x3000 -/* The minimum and maximum heap size for GRUB itself. */ -#define MIN_HEAP_SIZE 0x10 -#define MAX_HEAP_SIZE (1600 * 0x10) +/* The default heap size for GRUB itself in bytes. */ +#define DEFAULT_HEAP_SIZE 0x10 static void *finish_mmap_buf = 0; static grub_efi_uintn_t finish_mmap_size = 0; @@ -478,23 +477,6 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, return filtered_desc; } -/* Return the total number of pages. */ -static grub_efi_uint64_t -get_total_pages (grub_efi_memory_descriptor_t *memory_map, -grub_efi_uintn_t desc_size, -grub_efi_memory_descriptor_t *memory_map_end) -{ - grub_efi_memory_descriptor_t *desc; - grub_efi_uint64_t total = 0; - - for (desc = memory_map; - desc < memory_map_end; - desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) -total += desc->num_pages; - - return total; -} - /* Add memory regions. */ static void add_memory_regions (grub_efi_memory_descriptor_t *memory_map, @@ -583,8 +565,6 @@ grub_efi_mm_init (void) grub_efi_memory_descriptor_t *filtered_memory_map_end; grub_efi_uintn_t map_size; grub_efi_uintn_t desc_size; - grub_efi_uint64_t total_pages; - grub_efi_uint64_t required_pages; int mm_status; /* Prepare a memory region to store two memory maps. */ @@ -624,22 +604,13 @@ grub_efi_mm_init (void) filtered_memory_map_end = filter_memory_map (memory_map, filtered_memory_map, desc_size, memory_map_end); - /* By default, request a quarter of the available memory. */ - total_pages = get_total_pages (filtered_memory_map, desc_size, -filtered_memory_map_end); - required_pages = (total_pages >> 2); - if (required_pages < BYTES_TO_PAGES (MIN_HEAP_SIZE)) -required_pages = BYTES_TO_PAGES (MIN_HEAP_SIZE); - else if (required_pages > BYTES_TO_PAGES (MAX_HEAP_SIZE)) -required_pages = BYTES_TO_PAGES (MAX_HEAP_SIZE); - /* Sort the filtered descriptors, so that GRUB can allocate pages from smaller regions. */ sort_memory_map (filtered_memory_map, desc_size, filtered_memory_map_end); /* Allocate memory regions for GRUB's memory management. */ add_memory_regions (filtered_memory_map, desc_size, - filtered_memory_map_end, required_pages); + filtered_memory_map_end, BYTES_TO_PAGES (DEFAULT_HEAP_SIZE)); #if 0 /* For debug. */ -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 06/15] mm: Allow dynamically requesting additional memory regions
From: Patrick Steinhardt Currently, all platforms will set up their heap on initialization of the platform code. While this works mostly fine, it poses some limitations on memory management on us. Most notably, allocating big chunks of memory in the gigabyte range would require us to pre-request this many bytes from the firmware and add it to the heap from the beginning on some platforms like EFI. As this isn't needed for most configurations, it is inefficient and may even negatively impact some usecases when, e.g., chainloading. Nonetheless, allocating big chunks of memory is required sometimes, where one example is the upcoming support for the Argon2 key derival function in LUKS2. In order to avoid pre-allocating big chunks of memory, this commit implements a runtime mechanism to add more pages to the system. When a given allocation cannot be currently satisfied, we'll call a given callback set up by the platform's own memory management subsystem, asking it to add a memory area with at least `n` bytes. If this succeeds, we retry searching for a valid memory region, which should now succeed. If this fails, we try asking for `n` bytes, possibly spread across multiple regions, in hopes that region merging means that we end up with enough memory for things to work out. Tested-by: Stefan Berger Signed-off-by: Patrick Steinhardt [dja: add this to the documentation at the top of mm.c v2: fallback to non-contiguous] Signed-off-by: Daniel Axtens --- Daniel K: you had a Reviewed-by based on v1, but as the v2 changes are non-trivial I have not included it. I currently default to a fallback to non-contiguous on all platforms: if anyone objects I'm happy to tweak it. --- grub-core/kern/mm.c | 30 ++ include/grub/mm.h | 16 2 files changed, 46 insertions(+) diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c index 90fa78a06735..c3bf4646f55e 100644 --- a/grub-core/kern/mm.c +++ b/grub-core/kern/mm.c @@ -28,6 +28,9 @@ - multiple regions may be used as free space. They may not be contiguous. + - if existing regions are insufficient to satisfy an allocation, a new + region can be requested from firmware. + Regions are managed by a singly linked list, and the meta information is stored in the beginning of each region. Space after the meta information is used to allocate memory. @@ -81,6 +84,7 @@ grub_mm_region_t grub_mm_base; +grub_mm_add_region_func_t grub_mm_add_region_fn; /* Get a header from the pointer PTR, and set *P and *R to a pointer to the header and a pointer to its region, respectively. PTR must @@ -437,6 +441,32 @@ grub_memalign (grub_size_t align, grub_size_t size) count++; goto again; +case 1: + /* Request additional pages, contiguous */ + count++; + + if (grub_mm_add_region_fn != NULL && + grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_CONSECUTIVE) == GRUB_ERR_NONE) + goto again; + + /* fallthrough */ + +case 2: + /* Request additional pages, anything at all */ + count++; + + if (grub_mm_add_region_fn != NULL) +{ + /* + * Try again even if this fails, in case it was able to partially + * satisfy the request + */ + grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_NONE); + goto again; +} + + /* fallthrough */ + default: break; } diff --git a/include/grub/mm.h b/include/grub/mm.h index 44fde7cb9033..5d916809666c 100644 --- a/include/grub/mm.h +++ b/include/grub/mm.h @@ -20,6 +20,7 @@ #ifndef GRUB_MM_H #define GRUB_MM_H 1 +#include #include #include #include @@ -28,6 +29,21 @@ # define NULL ((void *) 0) #endif +#define GRUB_MM_ADD_REGION_NONE0 +#define GRUB_MM_ADD_REGION_CONSECUTIVE (1 << 0) + +/* + * Function used to request memory regions of `grub_size_t` bytes. The second + * parameter is a bitfield of `GRUB_MM_ADD_REGION` flags. + */ +typedef grub_err_t (*grub_mm_add_region_func_t) (grub_size_t, unsigned int); + +/* + * Set this function pointer to enable adding memory-regions at runtime in case + * a memory allocation cannot be satisfied with existing regions. + */ +extern grub_mm_add_region_func_t EXPORT_VAR(grub_mm_add_region_fn); + void grub_mm_init_region (void *addr, grub_size_t size); void *EXPORT_FUNC(grub_calloc) (grub_size_t nmemb, grub_size_t size); void *EXPORT_FUNC(grub_malloc) (grub_size_t size); -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 05/15] mm: Drop unused unloading of modules on OOM
From: Patrick Steinhardt In `grub_memalign ()`, there's a commented section which would allow for unloading of unneeded modules in case where there is not enough free memory available to satisfy a request. Given that this code is never compiled in, let's remove it together with `grub_dl_unload_unneeded()` Signed-off-by: Patrick Steinhardt Signed-off-by: Daniel Axtens Reviewed-by: Daniel Kiper --- grub-core/kern/dl.c | 20 grub-core/kern/mm.c | 8 include/grub/dl.h | 1 - 3 files changed, 29 deletions(-) diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c index b1d3a103ec98..e447fd0fab4e 100644 --- a/grub-core/kern/dl.c +++ b/grub-core/kern/dl.c @@ -811,23 +811,3 @@ grub_dl_unload (grub_dl_t mod) grub_free (mod); return 1; } - -/* Unload unneeded modules. */ -void -grub_dl_unload_unneeded (void) -{ - /* Because grub_dl_remove modifies the list of modules, this - implementation is tricky. */ - grub_dl_t p = grub_dl_head; - - while (p) -{ - if (grub_dl_unload (p)) - { - p = grub_dl_head; - continue; - } - - p = p->next; -} -} diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c index f36499865632..90fa78a06735 100644 --- a/grub-core/kern/mm.c +++ b/grub-core/kern/mm.c @@ -437,14 +437,6 @@ grub_memalign (grub_size_t align, grub_size_t size) count++; goto again; -#if 0 -case 1: - /* Unload unneeded modules. */ - grub_dl_unload_unneeded (); - count++; - goto again; -#endif - default: break; } diff --git a/include/grub/dl.h b/include/grub/dl.h index d0f4115fe736..acb4d42327d7 100644 --- a/include/grub/dl.h +++ b/include/grub/dl.h @@ -203,7 +203,6 @@ grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name); grub_dl_t grub_dl_load_core (void *addr, grub_size_t size); grub_dl_t EXPORT_FUNC(grub_dl_load_core_noinit) (void *addr, grub_size_t size); int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod); -extern void grub_dl_unload_unneeded (void); extern int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod); extern int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod); extern int EXPORT_FUNC(grub_dl_ref_count) (grub_dl_t mod); -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 01/15] grub-shell: only pass SeaBIOS fw_opt in for x86 BIOS platforms
This breaks the tests on pseries - just restrict it to x86 platforms that don't specify a BIOS. Signed-off-by: Daniel Axtens --- v2: Thanks Daniel K and Glenn for feedback. --- tests/util/grub-shell.in | 6 +- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/util/grub-shell.in b/tests/util/grub-shell.in index 33590baeb13c..4828afb7cc5a 100644 --- a/tests/util/grub-shell.in +++ b/tests/util/grub-shell.in @@ -376,7 +376,11 @@ if test -z "$debug"; then # workaround unfortunately causes qemu to issue a warning 'externally # provided fw_cfg item names should be prefixed with "opt/"', but there # doesn't seem to be a better option. - qemuopts="${qemuopts} -fw_cfg name=etc/sercon-port,string=0" + # + # SeaBIOS is used for i386, except on EFI. + if [ ${grub_modinfo_target_cpu} == 'i386' ] && [ ${grub_modinfo_platform} != 'efi' ]; then +qemuopts="${qemuopts} -fw_cfg name=etc/sercon-port,string=0" + fi fi if [ x$boot != xnet ] && [ x$boot != xemu ]; then -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 03/15] mm: when adding a region, merge with region after as well as before
On x86_64-efi (at least) regions seem to be added from top down. The mm code will merge a new region with an existing region that comes immediately before the new region. This allows larger allocations to be satisfied that would otherwise be the case. On powerpc-ieee1275, however, regions are added from bottom up. So if we add 3x 32MB regions, we can still only satisfy a 32MB allocation, rather than the 96MB allocation we might otherwise be able to satisfy. * Define 'post_size' as being bytes lost to the end of an allocation due to being given weird sizes from firmware that are not multiples of GRUB_MM_ALIGN. * Allow merging of regions immediately _after_ existing regions, not just before. As with the other approach, we create an allocated block to represent the new space and the pass it to grub_free() to get the metadata right. Tested-by: Stefan Berger Signed-off-by: Daniel Axtens --- v2: Thanks Daniel K for feedback. --- grub-core/kern/mm.c | 123 +++--- include/grub/mm_private.h | 9 +++ 2 files changed, 85 insertions(+), 47 deletions(-) diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c index 079c28da7cdf..94e78f9a910d 100644 --- a/grub-core/kern/mm.c +++ b/grub-core/kern/mm.c @@ -130,53 +130,81 @@ grub_mm_init_region (void *addr, grub_size_t size) /* Attempt to merge this region with every existing region */ for (p = _mm_base, q = *p; q; p = &(q->next), q = *p) -/* - * Is the new region immediately below an existing region? That - * is, is the address of the memory we're adding now (addr) + size - * of the memory we're adding (size) + the bytes we couldn't use - * at the start of the region we're considering (q->pre_size) - * equal to the address of q? In other words, does the memory - * looks like this? - * - * addr q - * |size-|-q->pre_size-|| - */ -if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q) - { - /* -* Yes, we can merge the memory starting at addr into the -* existing region from below. Align up addr to GRUB_MM_ALIGN -* so that our new region has proper alignment. -*/ - r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN); - /* Copy the region data across */ - *r = *q; - /* Consider all the new size as pre-size */ - r->pre_size += size; - - /* -* If we have enough pre-size to create a block, create a -* block with it. Mark it as allocated and pass it to -* grub_free (), which will sort out getting it into the free -* list. -*/ - if (r->pre_size >> GRUB_MM_ALIGN_LOG2) - { - h = (grub_mm_header_t) (r + 1); - /* block size is pre-size converted to cells */ - h->size = (r->pre_size >> GRUB_MM_ALIGN_LOG2); - h->magic = GRUB_MM_ALLOC_MAGIC; - /* region size grows by block size converted back to bytes */ - r->size += h->size << GRUB_MM_ALIGN_LOG2; - /* adjust pre_size to be accurate */ - r->pre_size &= (GRUB_MM_ALIGN - 1); - *p = r; - grub_free (h + 1); - } - /* Replace the old region with the new region */ - *p = r; - return; - } +{ + /* + * Is the new region immediately below an existing region? That + * is, is the address of the memory we're adding now (addr) + size + * of the memory we're adding (size) + the bytes we couldn't use + * at the start of the region we're considering (q->pre_size) + * equal to the address of q? In other words, does the memory + * looks like this? + * + * addr q + * |size-|-q->pre_size-|| + */ + if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q) +{ + /* + * Yes, we can merge the memory starting at addr into the + * existing region from below. Align up addr to GRUB_MM_ALIGN + * so that our new region has proper alignment. + */ + r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN); + /* Copy the region data across */ + *r = *q; + /* Consider all the new size as pre-size */ + r->pre_size += size; + + /* + * If we have enough pre-size to create a block, create a + * block with it. Mark it as allocated and pass it to + * grub_free (), which will sort out getting it into the free + * list. + */ + if (r->pre_size >> GRUB_MM_ALIGN_LOG2) +{ + h = (grub_mm_header_t) (r + 1); + /* block size is pre-size converted to cells */ + h->size = (r->pre_size >> GRUB_MM_ALIGN_LOG2); +
[PATCH v2 02/15] mm: assert that we preserve header vs region alignment
grub_mm_region_init() does: h = (grub_mm_header_t) (r + 1); where h is a grub_mm_header_t and r is a grub_mm_region_t. Cells are supposed to be GRUB_MM_ALIGN aligned, but while grub_mm_dump ensures this vs the region header, grub_mm_region_init() does not. It's better to be explicit than implicit here: rather than changing grub_mm_region_init() to ALIGN_UP(), require that the struct is explictly a multiple of the header size. Signed-off-by: Daniel Axtens --- v2: Thanks Daniel K for feedback. --- include/grub/mm_private.h | 14 ++ 1 file changed, 14 insertions(+) diff --git a/include/grub/mm_private.h b/include/grub/mm_private.h index 203533cc3d42..d3f2321e14fb 100644 --- a/include/grub/mm_private.h +++ b/include/grub/mm_private.h @@ -20,6 +20,7 @@ #define GRUB_MM_PRIVATE_H 1 #include +#include /* For context, see kern/mm.c */ @@ -89,4 +90,17 @@ typedef struct grub_mm_region extern grub_mm_region_t EXPORT_VAR (grub_mm_base); #endif +static inline void +grub_mm_size_sanity_check (void) { + /* Ensure we preserve alignment when doing h = (grub_mm_header_t) (r + 1) */ + COMPILE_TIME_ASSERT ((sizeof (struct grub_mm_region) % + sizeof (struct grub_mm_header)) == 0); + + /* + * GRUB_MM_ALIGN is supposed to represent cell size, and a mm_header is + * supposed to be 1 cell. + */ + COMPILE_TIME_ASSERT (sizeof (struct grub_mm_header) == GRUB_MM_ALIGN); +} + #endif -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH v2 00/15] Dynamic allocation of memory regions and IBM vTPM v2
Hi all, This is, at long last, an updated version of my series extending Patrick's dynamic memory regions to ieee1275. Noteworthy changes: - reworked debug prints as grub_dprintfs. Folded the ieee1275 ones into the ieee1275 patches. - reworked the ieee1275 runtime memory claiming to be more resilient and better documented. - fixed comment style and hopefully addressed all other change requests. - grub will now try asking for contiguous memory and then, if that fails, for discontiguous memory - in case region merging with the discontiguous memory is sufficient to allow the eventual allocation to succeed. - The ieee1275 code agressively rounds up the size of the region for a dynamic allocation - it will now retry with a more precise size if the larger allocation fails. The memtool module is included as an RFC only and will require more work, as discussed in the patch. I've also included Stefan's vTPM patch - Stefan kindly tested that his patch worked with my memory rework series. I have added his tested-by to relevant Power-specific patches only. Kind regards, Daniel Daniel Axtens (8): grub-shell: pseries: don't pass fw_opt to qemu mm: assert that we preserve header vs region alignment mm: when adding a region, merge with region after as well as before mm: debug support for region operations ieee1275: request memory with ibm,client-architecture-support ieee1275: drop len -= 1 quirk in heap_init ieee1275: support runtime memory claiming [RFC] Add memtool module with memory allocation stress-test Patrick Steinhardt (6): mm: Drop unused unloading of modules on OOM mm: Allow dynamically requesting additional memory regions efi: mm: Always request a fixed number of pages on init efi: mm: Extract function to add memory regions efi: mm: Pass up errors from `add_memory_regions ()` efi: mm: Implement runtime addition of pages Stefan Berger (1): ibmvtpm: Add support for trusted boot using a vTPM 2.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH 11/19] efi: mm: Extract function to add memory regions
>>/* Prepare a memory region to store two memory maps. */ >>memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES >> (MEMORY_MAP_SIZE)); >>if (! memory_map) >> -grub_fatal ("cannot allocate memory"); >> +return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory"); > > Something more descriptive would be nice, may be even "cannot allocate > memory for memory map" Yes. >> >>/* Obtain descriptors for available memory. */ >>map_size = MEMORY_MAP_SIZE; >> @@ -588,14 +588,14 @@ grub_efi_mm_init (void) >> >>memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES >> (map_size)); >>if (! memory_map) >> -grub_fatal ("cannot allocate memory"); >> +return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory"); > > Ditto. And maybe nice to have it slightly different, perhaps "cannot > re-allocate memory map" Yes. >> >>mm_status = grub_efi_get_memory_map (_size, memory_map, 0, >> _size, 0); >> } >> >>if (mm_status < 0) >> -grub_fatal ("cannot get memory map"); >> +return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot get memory map"); > > What are the range of values that mm_status could be? Would it be > useful to include the status code in the error message? IOW, could a > failure here be affected by a configuration that the user could change > to make this work? Also I like the message "failed to retrieve memory > map (status=%d)". > The function says: /* Get the memory map as defined in the EFI spec. Return 1 if successful, return 0 if partial, or return -1 if an error occurs. */ So no, I don't think we could print anything more interesting without reworking the grub_efi_get_memory_map function. >> >>memory_map_end = NEXT_MEMORY_DESCRIPTOR (memory_map, map_size); >> >> @@ -610,7 +610,7 @@ grub_efi_mm_init (void) >> >>/* Allocate memory regions for GRUB's memory management. */ >>add_memory_regions (filtered_memory_map, desc_size, >> - filtered_memory_map_end, BYTES_TO_PAGES >> (DEFAULT_HEAP_SIZE)); >> + filtered_memory_map_end, BYTES_TO_PAGES (required_bytes)); >> >> #if 0 >>/* For debug. */ > > What about turning this on when MM_DEBUG is on? Seems like it could be > a useful (would been to get rid of/change the grub_fatal calls). > Perhaps, but I'm not sufficiently across EFI to be confident making that sort of change, and I'm not well set up to test EFI systems or evaluate the correctness or usefulness of any output. I think this would be better deferred to another patch from someone with more experience in the field. Kind regards, Daniel ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH 04/19] mm: assert that we preserve header vs region alignment
> s/struct grub_mm_region/grub_mm_region_t/ > s/struct grub_mm_header/grub_mm_header_t/ The problem is that grub_mm_{region,header}_t is a pointer type, not a struct type. So sizeof (grub_mm_region_t) == sizeof(void *). You also can't do sizeof (*grub_mm_region_t), because you can't dereference a type. If there's a better way to express this I am open to it, but for now I will stick with the struct type... > >> + sizeof(struct grub_mm_header)) == 0); > > I think this check is insufficient. The GRUB_MM_ALIGN should be checked > somehow too. E.g. if sizeof(struct grub_mm_region) == 16, > sizeof(struct grub_mm_header) == 8 and GRUB_MM_ALIGN == 32 then assert > above will pass but the GRUB will blow up later. Of course numbers are not > real but I chose them to show the problem. Hmmm... If we could choose > grub_mm_region_t and grub_mm_header_t sizes properly then probably we > could drop GRUB_MM_ALIGN... > I have added that sizeof(struct header) == GRUB_MM_ALIGN. GRUB_MM_ALIGN is supposed to align you to a cell, and a header is supposed to be 1 cell. We probably _could_ do away with the constant but I think that requires a bit more close thought. Kind regards, Daniel ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH] net: check against nb->tail in grub_netbuff_pull
GRUB netbuff structure members track 2 different things: the extent of memory allocated for the packet, and the extent of memory currently being worked on. This works out in the structure as follows: nb->head: beginning of the allocation nb->data: beginning of the working data nb->tail: end of the working data nb->end: end of the allocation The head and end pointers are set in grub_netbuff_alloc and do not change. The data and tail pointers are initialised to point at start of the allocation (that is, head == data == tail initially), and are then manipulated by grub_netbuff_* functions. Key functions are as follows: - grub_netbuff_put: 'Put' more data into the packet - advance nb->tail. - grub_netbuff_unput: trim the tail of the packet - retract nb->tail - grub_netbuff_pull: 'consume' some packet data - advance nb->data - grub_netbuff_reserve: reserve space for future headers - advance nb->data and nb->tail - grub_netbuff_push: 'un-consume' data to allow headers to be written - retract nb->data. Each of those functions does some form of error checking. For example, grub_netbuff_put does not allow nb->tail to exceed nb->end, and grub_netbuff_push does not allow nb->data to be before nb->head. However, grub_netbuff_pull's error checking is a bit weird. It advances nb->data and checks that it does not exceed nb->end. That allows you to get into the situation where nb->data > nb->tail, which should not be. Make grub_netbuff_pull check against both nb->tail and nb->end. In theory just checking against ->tail should be sufficient but the extra check should be cheap and seems like good defensive practice. Signed-off-by: Daniel Axtens --- I'm not aware of any particular bug this fixes. All it can do is prevent you reading uninitialised but still allocated memory. It just seems like a good idea. The netboot test still passses on the pc platform, more testing would be good. --- grub-core/net/netbuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/net/netbuff.c b/grub-core/net/netbuff.c index dbeeefe4783c..72e5296356f0 100644 --- a/grub-core/net/netbuff.c +++ b/grub-core/net/netbuff.c @@ -54,7 +54,7 @@ grub_err_t grub_netbuff_pull (struct grub_net_buff *nb, grub_size_t len) { nb->data += len; - if (nb->data > nb->end) + if (nb->data > nb->end || nb->data > nb->tail) return grub_error (GRUB_ERR_BUG, "pull out of the packet range."); return GRUB_ERR_NONE; -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH] net: fix null pointer dereference when parsing ICMP6_ROUTER_ADVERTISE messages
Hi, I tested this against grub-emu and it fixed the crash I had observed. net_ls_addr reports an address as expected now also. Reviewed-by: Daniel Axtens Kind regards, Daniel Qiumiao Zhang via Grub-devel writes: > During UEFI PXE boot in IPv6 network, if the DHCP server adopts stateful > automatic > configuration, when the client receives the ICMP6_ROUTER_ADVERTISE message > multicast > from the server, it will cause the problem of dereference null pointer and > cause > the grub2 program to crash. > > Fixes bug: https://savannah.gnu.org/bugs/index.php?62072 > --- > grub-core/net/icmp6.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/grub-core/net/icmp6.c b/grub-core/net/icmp6.c > index 2cbd95d..264fc4a 100644 > --- a/grub-core/net/icmp6.c > +++ b/grub-core/net/icmp6.c > @@ -477,7 +477,7 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb, > > /* May not have gotten slaac info, find a global address on this > card. */ > - if (route_inf == NULL) > + if (route_inf == NULL && orig_inf != NULL) > { > FOR_NET_NETWORK_LEVEL_INTERFACES (inf) > { > -- > 2.19.1 > > > ___ > Grub-devel mailing list > Grub-devel@gnu.org > https://lists.gnu.org/mailman/listinfo/grub-devel ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH] Revert "iee1275/datetime: Fix off-by-1 error."
> I suspect its the same on KVM and TCG because the machine definition is > the same and doesn't container either an RTC nor a CMOS. What confusing > to me is, don't these machines have clocks? They do have clocks! Sadly I know very little about the clocks. `date` works fine in Linux, so I suspect there's something where SLOF doesn't expose whatever it is that we need in the form we expect, or something like that. I guess someone should hunt it down but given that timeouts and such work (so I guess we have a working relative timer), I can't say it's likely to be a huge priority for anyone... Kind regards, Daniel > >> >> I also tested an LPAR on a Power8 PowerVM machine. In this case, before >> the patch, grub printed: >> >> grub> date >> 2022-02-09 04:31:10 Wednesday >> >> whereas on booting: >> >> [dja@sauce ~]$ date -u >> Tue Feb 8 04:46:40 UTC 2022 >> >> After applying the patch, grub printed: >> >> grub> date >> 2022-02-08 04:51:27 Tuesday >> >> It seems the patch makes things better. > > Great thanks Daniel for confirming this. > > Glenn > >> >> Tested-by: Daniel Axtens >> >> Kind regards, >> Daniel >> >> Glenn Washburn writes: >> >> > This is causing the test grub_cmd_date to fail because the returned date is >> > one day more than it should be. >> > >> > This reverts commit 607d66116a67e5a13eb0d46076f26dedc988e6a4. >> > >> > Signed-off-by: Glenn Washburn >> > --- >> > Hi all, >> > >> > Reverting this commit allows the grub_cmd_date test to pass. It appears >> > that >> > this commit is (now) causing an off-by-1 error in QEMU and the latest >> > OpenBIOS. >> > What I'm unsure of is if the original commit is actually correct on real >> > hardware and that potentially OpenBIOS has a bug. >> > >> > Adrian and Daniel A, could you test the reverting of this commit on real >> > hardware and see if date does in fact produce the expected date (and do >> > current >> > builds show a date one day ahead of what it should be)? Can anyone point to >> > documentation saying that the original commit is in fact what should >> > be done? If the issue is in OpenBIOS I'd like to have some documentation >> > to back up a bug report. >> > >> > Vladimir, do you have any thoughts on this? >> > >> > Glenn >> > >> > --- >> > grub-core/lib/ieee1275/datetime.c | 4 ++-- >> > 1 file changed, 2 insertions(+), 2 deletions(-) >> > >> > diff --git a/grub-core/lib/ieee1275/datetime.c >> > b/grub-core/lib/ieee1275/datetime.c >> > index b81fba2ed..74578f15a 100644 >> > --- a/grub-core/lib/ieee1275/datetime.c >> > +++ b/grub-core/lib/ieee1275/datetime.c >> > @@ -95,7 +95,7 @@ grub_get_datetime (struct grub_datetime *datetime) >> > >> >datetime->year = args.year; >> >datetime->month = args.month; >> > - datetime->day = args.day + 1; >> > + datetime->day = args.day; >> >datetime->hour = args.hour; >> >datetime->minute = args.minute; >> >datetime->second = args.second; >> > @@ -140,7 +140,7 @@ grub_set_datetime (struct grub_datetime *datetime) >> > >> >args.year = datetime->year; >> >args.month = datetime->month; >> > - args.day = datetime->day - 1; >> > + args.day = datetime->day; >> >args.hour = datetime->hour; >> >args.minute = datetime->minute; >> >args.second = datetime->second; >> > -- >> > 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH] Revert "iee1275/datetime: Fix off-by-1 error."
Hi, I tested a pseries guest under: - qemu + KVM on a Power8 host with a fairly modern qemu - qemu + TCG Here the 'date' command simply reports "error: no cmos found", so this patch will have no impact on those platforms. I also tested an LPAR on a Power8 PowerVM machine. In this case, before the patch, grub printed: grub> date 2022-02-09 04:31:10 Wednesday whereas on booting: [dja@sauce ~]$ date -u Tue Feb 8 04:46:40 UTC 2022 After applying the patch, grub printed: grub> date 2022-02-08 04:51:27 Tuesday It seems the patch makes things better. Tested-by: Daniel Axtens Kind regards, Daniel Glenn Washburn writes: > This is causing the test grub_cmd_date to fail because the returned date is > one day more than it should be. > > This reverts commit 607d66116a67e5a13eb0d46076f26dedc988e6a4. > > Signed-off-by: Glenn Washburn > --- > Hi all, > > Reverting this commit allows the grub_cmd_date test to pass. It appears that > this commit is (now) causing an off-by-1 error in QEMU and the latest > OpenBIOS. > What I'm unsure of is if the original commit is actually correct on real > hardware and that potentially OpenBIOS has a bug. > > Adrian and Daniel A, could you test the reverting of this commit on real > hardware and see if date does in fact produce the expected date (and do > current > builds show a date one day ahead of what it should be)? Can anyone point to > documentation saying that the original commit is in fact what should > be done? If the issue is in OpenBIOS I'd like to have some documentation > to back up a bug report. > > Vladimir, do you have any thoughts on this? > > Glenn > > --- > grub-core/lib/ieee1275/datetime.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/grub-core/lib/ieee1275/datetime.c > b/grub-core/lib/ieee1275/datetime.c > index b81fba2ed..74578f15a 100644 > --- a/grub-core/lib/ieee1275/datetime.c > +++ b/grub-core/lib/ieee1275/datetime.c > @@ -95,7 +95,7 @@ grub_get_datetime (struct grub_datetime *datetime) > >datetime->year = args.year; >datetime->month = args.month; > - datetime->day = args.day + 1; > + datetime->day = args.day; >datetime->hour = args.hour; >datetime->minute = args.minute; >datetime->second = args.second; > @@ -140,7 +140,7 @@ grub_set_datetime (struct grub_datetime *datetime) > >args.year = datetime->year; >args.month = datetime->month; > - args.day = datetime->day - 1; > + args.day = datetime->day; >args.hour = datetime->hour; >args.minute = datetime->minute; >args.second = datetime->second; > -- > 2.27.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
Re: [PATCH 5/6] mm: document grub_mm_init_region
Daniel Kiper writes: > On Thu, Nov 25, 2021 at 02:22:49AM +1100, Daniel Axtens wrote: >> grub_mm_init_region does some things that seem magical, especially >> around region merging. Make it a bit clearer. >> >> Signed-off-by: Daniel Axtens >> --- >> grub-core/kern/mm.c | 30 +- >> 1 file changed, 29 insertions(+), 1 deletion(-) >> >> diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c >> index bec960c18e2b..ef2025f929de 100644 >> --- a/grub-core/kern/mm.c >> +++ b/grub-core/kern/mm.c >> @@ -128,23 +128,51 @@ grub_mm_init_region (void *addr, grub_size_t size) >>if (((grub_addr_t) addr + 0x1000) > ~(grub_addr_t) size) >> size = ((grub_addr_t) -0x1000) - (grub_addr_t) addr; >> >> + /* Attempt to merge this region with every existing region */ >>for (p = _mm_base, q = *p; q; p = &(q->next), q = *p) >> +/* >> + * Is the new region immediately below an existing region? That >> + * is, is the address of the memory we're adding now (addr) + size >> + * of the memory we're adding (size) + the bytes we couldn't use >> + * at the start of the region we're considering (q->pre_size) >> + * equal to the address of q? In other words, does the memory >> + * looks like this? >> + * >> + * addr q >> + * |size-|-q->pre_size-|| >> + */ >> if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q) >>{ >> +/* >> + * Yes, we can merge. r is our new region, it's address is the >> + * first GRUB_MM_ALIGNed address above addr. > > I think s/above/below/... > >> + */ >> r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN); We do r = ALIGN_UP(addr, GRUB_MM_ALIGN), so 'above' is actually correct. But that probably indicates that I'm not explaining it well. How does this sound: /* * Yes, we can merge the memory starting at addr into the * existing region from below. Align up addr to GRUB_MM_ALIGN * so that our new region has proper alignment. */ If you want you can change the comment and apply it, otherwise I will submit a v2. Kind regards, Daniel >> +/* Copy the region data across */ >> *r = *q; >> +/* Consider all the new size as pre-size */ >> r->pre_size += size; >> - >> + >> +/* >> + * If we have enough pre-size to create a block, create a >> + * block with it. Mark it as allocated and pass it to >> + * grub_free (), which will sort out getting it into the free >> + * list. >> + */ >> if (r->pre_size >> GRUB_MM_ALIGN_LOG2) >>{ >> h = (grub_mm_header_t) (r + 1); >> +/* block size is pre-size converted to cells */ >> h->size = (r->pre_size >> GRUB_MM_ALIGN_LOG2); >> h->magic = GRUB_MM_ALLOC_MAGIC; >> +/* region size grows by block size converted back to bytes */ >> r->size += h->size << GRUB_MM_ALIGN_LOG2; >> +/* adjust pre_size to be accurate */ >> r->pre_size &= (GRUB_MM_ALIGN - 1); >> *p = r; >> grub_free (h + 1); >>} >> +/* Replace the old region with the new region */ >> *p = r; >> return; >>} > > Otherwise LGTM... > > If you are OK with the change above then I can make it for you before > applying the patch. > > Daniel ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 3/6] mm: grub_real_malloc: make small allocs comment match code
Small allocations move the region's *first pointer. The comment says that this happens for allocations under 64K. The code says it's for allocations under 32K. Commit 45bf8b3a7549 changed the code intentionally: make the comment match. Fixes: 45bf8b3a7549 (" * grub-core/kern/mm.c (grub_real_malloc): Decrease cut-off of moving the") Signed-off-by: Daniel Axtens --- grub-core/kern/mm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c index 6efabe92df0e..ac41cf4aab15 100644 --- a/grub-core/kern/mm.c +++ b/grub-core/kern/mm.c @@ -306,7 +306,7 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) /* Mark find as a start marker for next allocation to fasten it. This will have side effect of fragmenting memory as small pieces before this will be un-used. */ - /* So do it only for chunks under 64K. */ + /* So do it only for chunks under 32K. */ if (n < (0x8000 >> GRUB_MM_ALIGN_LOG2) || *first == cur) *first = prev; -- 2.32.0 ___ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel
[PATCH 2/6] mm: clarify grub_real_malloc
When iterating through the singly linked list of free blocks, grub_real_malloc uses p and q for the current and previous blocks respectively. This isn't super clear, so swap to using prev and cur. This makes another quirk more obvious. The comment at the top of grub_real_malloc might lead you to believe that the function will allocate from *first if there is space in that block. It actually doesn't do that, and it can't do that with the current data structures. If we used up all of *first, we would need to change the ->next of the previous block to point to *first->next, but we can't do that because it's a singly linked list and we don't have access to *first's previous block. What grub_real_malloc actually does is set *first to the initial previous block, and *first->next is the block we try to allocate from. That allows us to keep all the data structures consistent. Document that. Signed-off-by: Daniel Axtens --- grub-core/kern/mm.c | 76 - 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c index c070afc621f8..6efabe92df0e 100644 --- a/grub-core/kern/mm.c +++ b/grub-core/kern/mm.c @@ -178,13 +178,20 @@ grub_mm_init_region (void *addr, grub_size_t size) } /* Allocate the number of units N with the alignment ALIGN from the ring - buffer starting from *FIRST. ALIGN must be a power of two. Both N and - ALIGN are in units of GRUB_MM_ALIGN. Return a non-NULL if successful, - otherwise return NULL. */ + * buffer given in *FIRST. ALIGN must be a power of two. Both N and + * ALIGN are in units of GRUB_MM_ALIGN. Return a non-NULL if successful, + * otherwise return NULL. + * + * Note: because in certain circumstances we need to adjust the ->next + * pointer of the previous block, we iterate over the singly linked + * list with the pair (prev, cur). *FIRST is our initial previous, and + * *FIRST->next is our initial current pointer. So we will actually + * allocate from *FIRST->next first and *FIRST itself last. + */ static void * grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) { - grub_mm_header_t p, q; + grub_mm_header_t cur, prev; /* When everything is allocated side effect is that *first will have alloc magic marked, meaning that there is no room in this region. */ @@ -192,24 +199,24 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) return 0; /* Try to search free slot for allocation in this memory region. */ - for (q = *first, p = q->next; ; q = p, p = p->next) + for (prev = *first, cur = prev->next; ; prev = cur, cur = cur->next) { grub_off_t extra; - extra = ((grub_addr_t) (p + 1) >> GRUB_MM_ALIGN_LOG2) & (align - 1); + extra = ((grub_addr_t) (cur + 1) >> GRUB_MM_ALIGN_LOG2) & (align - 1); if (extra) extra = align - extra; - if (! p) + if (! cur) grub_fatal ("null in the ring"); - if (p->magic != GRUB_MM_FREE_MAGIC) - grub_fatal ("free magic is broken at %p: 0x%x", p, p->magic); + if (cur->magic != GRUB_MM_FREE_MAGIC) + grub_fatal ("free magic is broken at %p: 0x%x", cur, cur->magic); - if (p->size >= n + extra) + if (cur->size >= n + extra) { - extra += (p->size - extra - n) & (~(align - 1)); - if (extra == 0 && p->size == n) + extra += (cur->size - extra - n) & (~(align - 1)); + if (extra == 0 && cur->size == n) { /* There is no special alignment requirement and memory block is complete match. @@ -222,9 +229,9 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) | alloc, size=n | | +---+ v */ - q->next = p->next; + prev->next = cur->next; } - else if (align == 1 || p->size == n + extra) + else if (align == 1 || cur->size == n + extra) { /* There might be alignment requirement, when taking it into account memory block fits in. @@ -241,23 +248,22 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) | alloc, size=n || +---+v */ - - p->size -= n; - p += p->size; + cur->size -= n; + cur += cur->size; } else if (extra == 0) { grub_mm_header_t r; - r = p + extra + n; + r = cur + extra + n; r->magic = GRUB_MM_FREE_MAGIC; - r->size = p->size - extra - n; - r->next = p->next; -