On Wed, Oct 11, 2023 at 08:40:10PM -0500, Glenn Washburn wrote:
> On Wed, 11 Oct 2023 08:42:20 -0400
> Jason Andryuk <jandr...@gmail.com> wrote:
>
> > Hi, Glenn,
> >
> > On Tue, Oct 10, 2023 at 2:23 PM Glenn Washburn
> > <developm...@efficientek.com> wrote:
> > >
> > > On Tue, 10 Oct 2023 12:24:24 -0400
> > > Jason Andryuk <jandr...@gmail.com> wrote:
> > >
> > > > grub_gzio_read_real() uses grub_errno to identify decompression failures
> > > > when the function completes.  Its callees in gzio.c are void-returning
> > > > functions that set grub_errno on their exit paths.
> > > >
> > > > A Fedora 38 machine was observed to fail `multiboot2 /xen.gz` with
> > > > "premature end of file".  xen.gz was well formed and could be
> > > > successfully gunzip-ed in Linux.
> > > >
> > > > The TPM is flaky and produces errors when the verifier tries to extend
> > > > PCRs with measurements.  Logs show "Unkown TPM error" and grub_errno is
> > > > set to GRUB_ERR_UNKNOWN_DEVICE.  This pre-existing grub_errno causes an
> > > > otherwise successful grub_gzio_read_real() call to return error.
> > > >
> > > > Clear grub_errno at the start of the function to avoid such errors.
> > >
> > > This seems to be a somewhat common theme. This is similar to the issue
> > > that I have seen in grub_disk_read() (see the first patch in the "More
> > > ls improvements" series). I think GRUB should have an explicit policy
> > > about grub_errno usage. Vladimir has stated "We generally prefer to have
> > > grub_print_error() (better) or resetting grib_errno after the error is
> > > produced rather than blanketly reset grub_errno at the beginning". That
> > > then suggests that its the callers responsibility to ensure that
> > > grub_errno is cleared before the call. I don't particularly like that,
> > > as it seems more economical for grub_errno to be cleared in the callee.
> > > Since GRUB seems to try to abide by some POSIX/GNU libc semantics, it
> > > seems reasonable to me to try to offer the same behavior as libc's
> > > errno. So caller's can not expect grub_errno to be preserved across
> > > library calls (ie all exported functions). And the callee is free to
> > > modify grub_errno at will. If the caller wants to preserve grub_errno
> > > across exported function calls, then the caller should save grub_errno
> > > in a local.
> > >
> > > So I'm for this approach in principle.
> > >
> > > > Signed-off-by: Jason Andryuk <jandr...@gmail.com>
> > > > ---
> > > >  grub-core/io/gzio.c | 8 ++++++++
> > > >  1 file changed, 8 insertions(+)
> > > >
> > > > diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c
> > > > index ca9355751..1e31a8255 100644
> > > > --- a/grub-core/io/gzio.c
> > > > +++ b/grub-core/io/gzio.c
> > > > @@ -1294,6 +1294,14 @@ grub_gzio_read_real (grub_gzio_t gzio, 
> > > > grub_off_t offset,
> > > >  {
> > > >    grub_ssize_t ret = 0;
> > > >
> > > > +  /* Avoid spurious failures on exit when grub_errno is already set. */
> > > > +  if (grub_errno != GRUB_ERR_NONE)
> > > > +    {
> > > > +      grub_dprintf ("gzio", "%s: clearing pre-exising errmsg %s\n",
> > > > +                  __func__, grub_errmsg);
> > > > +      grub_errno = GRUB_ERR_NONE;
> > > > +    }
> > >
> > > I think it makes sense to make this an inline called
> > > "grub_print_uncleared_error" or something of the like to be used in
> > > other places where this is appropriate. And the debug conditional
> > > should be "errno" so we can see where this is happening in other areas
> > > like grub_disk_read() to help in debugging. I suspect this type of
> > > issue has caused some strange behavior I've seen in the past. Also
> > > using a different debug conditional allows that type of issue to be
> > > ignored without ignoring other debug messages from, in this case, gzio.
> > >
> > > And, I would have the "grub_errno = GRUB_ERR_NONE;" outside the if
> > > block, which signals the expectation that grub_errno is cleared
> > > unconditionally more clearly (if only slightly). I'm kinda ambivalent
> > > about this though.
> >
> > I think this all sounds good.  However, I think `grub_clear_errno` is
> > a better name since that is the main purpose of the function.  Maybe
> > `grub_reset_errno`.  The dprintf call I mainly added as a debugging
> > aid and isn't the purpose of the function.  In the (hopefully small)
>
> Yeah, I got that. Just having a one line change of "grub_errno =
> GRUB_ERR_NONE;" is all that is needed. And if that were the change, I
> wouldn't have suggested the inline function. For me the main purpose of
> having the function is to have one line to be added to certain grub
> functions that shows the debug statement for those debugging this kind
> of issue. If its as Vladimir says and grub_errno should be cleared after
> its produced, then we want to know when that expectation fails, as its
> has been and I suspect will be the source of errors.
>
> Another option is to have the function just be a macro called
> "grub_debug_errno" defined as something like "if(grub_errno !=
> GRUB_ERR_NONE) { grub_drpintf(...); }" and have always add two
> statements to the start of exported functions, "grub_debug_errno();
> grub_errno = GRUB_ERR_NONE;". This might be more clear to the casual
> reader.

Yeah, I think the grub_debug_errno() macro followed by grub_errno reset
looks like quite good solution in this case. Though I would put only both
in places where we cannot be sure what is the grub_errno value.

Daniel

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to