Re: [PATCH 0/2] Two small fixes to gzip

2024-05-17 Thread Daniel Axtens
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

2024-05-12 Thread Daniel Axtens
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

2024-05-12 Thread Daniel Axtens
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

2024-05-12 Thread Daniel Axtens
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

2024-05-01 Thread Daniel Axtens
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

2023-10-19 Thread Daniel Axtens

> 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

2023-10-05 Thread Daniel Axtens
(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

2023-03-27 Thread Daniel Axtens
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

2023-03-27 Thread Daniel Axtens
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

2023-03-27 Thread Daniel Axtens
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

2023-03-27 Thread Daniel Axtens
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

2023-03-27 Thread Daniel Axtens
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

2023-03-27 Thread Daniel Axtens
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

2023-03-27 Thread Daniel Axtens
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

2023-01-14 Thread Daniel Axtens
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]

2022-12-02 Thread Daniel Axtens
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

2022-10-21 Thread Daniel Axtens
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

2022-10-19 Thread Daniel Axtens
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

2022-09-27 Thread Daniel Axtens
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

2022-09-19 Thread Daniel Axtens
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

2022-09-01 Thread Daniel Axtens
"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

2022-08-26 Thread Daniel Axtens
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

2022-08-22 Thread Daniel Axtens
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

2022-08-22 Thread Daniel Axtens
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

2022-08-21 Thread Daniel Axtens
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

2022-08-21 Thread Daniel Axtens
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

2022-08-21 Thread Daniel Axtens
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

2022-08-20 Thread Daniel Axtens
"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

2022-08-20 Thread Daniel Axtens
>> 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

2022-08-20 Thread Daniel Axtens
"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

2022-08-20 Thread Daniel Axtens
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

2022-08-19 Thread Daniel Axtens
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

2022-08-16 Thread Daniel Axtens
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

2022-05-17 Thread Daniel Axtens
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

2022-05-17 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens
 - 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

2022-04-21 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens

>> +@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

2022-04-21 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens
>> +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

2022-04-21 Thread Daniel Axtens
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

2022-04-21 Thread Daniel Axtens
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

2022-04-20 Thread Daniel Axtens
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

2022-04-20 Thread Daniel Axtens
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

2022-04-20 Thread Daniel Axtens
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

2022-04-20 Thread Daniel Axtens
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

2022-04-20 Thread Daniel Axtens
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

2022-04-20 Thread Daniel Axtens
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

2022-04-20 Thread Daniel Axtens
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 ()`

2022-04-20 Thread Daniel Axtens
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

2022-04-20 Thread Daniel Axtens
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

2022-04-20 Thread Daniel Axtens
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

2022-04-20 Thread Daniel Axtens
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

2022-04-20 Thread Daniel Axtens
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

2022-04-20 Thread Daniel Axtens
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

2022-04-20 Thread Daniel Axtens
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

2022-04-20 Thread Daniel Axtens
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

2022-04-20 Thread Daniel Axtens
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

2022-03-28 Thread Daniel Axtens
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

2022-03-28 Thread Daniel Axtens
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

2022-03-28 Thread Daniel Axtens
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

2022-03-28 Thread Daniel Axtens
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

2022-03-28 Thread Daniel Axtens
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

2022-03-28 Thread Daniel Axtens
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

2022-03-28 Thread Daniel Axtens
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 ()`

2022-03-28 Thread Daniel Axtens
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

2022-03-28 Thread Daniel Axtens
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

2022-03-28 Thread Daniel Axtens
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

2022-03-28 Thread Daniel Axtens
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

2022-03-28 Thread Daniel Axtens
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

2022-03-28 Thread Daniel Axtens
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

2022-03-28 Thread Daniel Axtens
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

2022-03-28 Thread Daniel Axtens
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

2022-03-28 Thread Daniel Axtens
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

2022-03-24 Thread Daniel Axtens
>>/* 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

2022-03-22 Thread Daniel Axtens

> 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

2022-03-04 Thread Daniel Axtens
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

2022-02-17 Thread Daniel Axtens
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."

2022-02-10 Thread Daniel Axtens
> 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."

2022-02-07 Thread Daniel Axtens
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

2021-12-13 Thread Daniel Axtens
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

2021-11-24 Thread Daniel Axtens
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

2021-11-24 Thread Daniel Axtens
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;
-   

  1   2   3   >