diff mbox series

[4/6] riscv: Fix EFI stub usage of KASAN instrumented string functions

Message ID 20221216162141.1701255-5-alexghiti@rivosinc.com
State New
Headers show
Series RISC-V kasan rework | expand

Commit Message

Alexandre Ghiti Dec. 16, 2022, 4:21 p.m. UTC
The EFI stub must not use any KASAN instrumented code as the kernel
proper did not initialize the thread pointer and the mapping for the
KASAN shadow region.

Avoid using generic string functions by copying stub dependencies from
lib/string.c to drivers/firmware/efi/libstub/string.c as RISC-V does
not implement architecture-specific versions of those functions.

Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
---
 arch/riscv/kernel/image-vars.h        |   8 --
 drivers/firmware/efi/libstub/Makefile |   7 +-
 drivers/firmware/efi/libstub/string.c | 133 ++++++++++++++++++++++++++
 3 files changed, 137 insertions(+), 11 deletions(-)

Comments

Conor Dooley Dec. 21, 2022, 2:05 p.m. UTC | #1
Hey Alex!

On Fri, Dec 16, 2022 at 05:21:39PM +0100, Alexandre Ghiti wrote:
> The EFI stub must not use any KASAN instrumented code as the kernel
> proper did not initialize the thread pointer and the mapping for the
> KASAN shadow region.
> 
> Avoid using generic string functions by copying stub dependencies from
> lib/string.c to drivers/firmware/efi/libstub/string.c as RISC-V does
> not implement architecture-specific versions of those functions.

To the unaware among us, how does this interact with Heiko's custom
functions for bitmanip extensions? Is this diametrically opposed to
that, or does it actually help avoid having to have special handling
for the efi stub?

Also, checkpatch seems to be rather unhappy with you here:
https://gist.github.com/conor-pwbot/e5b4c8f2c3b88b4a8fcab4df437613e2

Thanks,
Conor.

> 
> Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
> ---
>  arch/riscv/kernel/image-vars.h        |   8 --
>  drivers/firmware/efi/libstub/Makefile |   7 +-
>  drivers/firmware/efi/libstub/string.c | 133 ++++++++++++++++++++++++++
>  3 files changed, 137 insertions(+), 11 deletions(-)
> 
> diff --git a/arch/riscv/kernel/image-vars.h b/arch/riscv/kernel/image-vars.h
> index d6e5f739905e..15616155008c 100644
> --- a/arch/riscv/kernel/image-vars.h
> +++ b/arch/riscv/kernel/image-vars.h
> @@ -23,14 +23,6 @@
>   * linked at. The routines below are all implemented in assembler in a
>   * position independent manner
>   */
> -__efistub_memcmp		= memcmp;
> -__efistub_memchr		= memchr;
> -__efistub_strlen		= strlen;
> -__efistub_strnlen		= strnlen;
> -__efistub_strcmp		= strcmp;
> -__efistub_strncmp		= strncmp;
> -__efistub_strrchr		= strrchr;
> -
>  __efistub__start		= _start;
>  __efistub__start_kernel		= _start_kernel;
>  __efistub__end			= _end;
> diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
> index b1601aad7e1a..031d2268bab5 100644
> --- a/drivers/firmware/efi/libstub/Makefile
> +++ b/drivers/firmware/efi/libstub/Makefile
> @@ -130,9 +130,10 @@ STUBCOPY_RELOC-$(CONFIG_ARM)	:= R_ARM_ABS
>  # also means that we need to be extra careful to make sure that the stub does
>  # not rely on any absolute symbol references, considering that the virtual
>  # kernel mapping that the linker uses is not active yet when the stub is
> -# executing. So build all C dependencies of the EFI stub into libstub, and do
> -# a verification pass to see if any absolute relocations exist in any of the
> -# object files.
> +# executing. In addition, we need to make sure that the stub does not use KASAN
> +# instrumented code like the generic string functions. So build all C
> +# dependencies of the EFI stub into libstub, and do a verification pass to see
> +# if any absolute relocations exist in any of the object files.
>  #
>  STUBCOPY_FLAGS-$(CONFIG_ARM64)	+= --prefix-alloc-sections=.init \
>  				   --prefix-symbols=__efistub_
> diff --git a/drivers/firmware/efi/libstub/string.c b/drivers/firmware/efi/libstub/string.c
> index 5d13e43869ee..5154ae6e7f10 100644
> --- a/drivers/firmware/efi/libstub/string.c
> +++ b/drivers/firmware/efi/libstub/string.c
> @@ -113,3 +113,136 @@ long simple_strtol(const char *cp, char **endp, unsigned int base)
>  
>  	return simple_strtoull(cp, endp, base);
>  }
> +
> +#ifndef __HAVE_ARCH_STRLEN
> +/**
> + * strlen - Find the length of a string
> + * @s: The string to be sized
> + */
> +size_t strlen(const char *s)
> +{
> +	const char *sc;
> +
> +	for (sc = s; *sc != '\0'; ++sc)
> +		/* nothing */;
> +	return sc - s;
> +}
> +EXPORT_SYMBOL(strlen);
> +#endif
> +
> +#ifndef __HAVE_ARCH_STRNLEN
> +/**
> + * strnlen - Find the length of a length-limited string
> + * @s: The string to be sized
> + * @count: The maximum number of bytes to search
> + */
> +size_t strnlen(const char *s, size_t count)
> +{
> +	const char *sc;
> +
> +	for (sc = s; count-- && *sc != '\0'; ++sc)
> +		/* nothing */;
> +	return sc - s;
> +}
> +EXPORT_SYMBOL(strnlen);
> +#endif
> +
> +#ifndef __HAVE_ARCH_STRCMP
> +/**
> + * strcmp - Compare two strings
> + * @cs: One string
> + * @ct: Another string
> + */
> +int strcmp(const char *cs, const char *ct)
> +{
> +	unsigned char c1, c2;
> +
> +	while (1) {
> +		c1 = *cs++;
> +		c2 = *ct++;
> +		if (c1 != c2)
> +			return c1 < c2 ? -1 : 1;
> +		if (!c1)
> +			break;
> +	}
> +	return 0;
> +}
> +EXPORT_SYMBOL(strcmp);
> +#endif
> +
> +#ifndef __HAVE_ARCH_STRRCHR
> +/**
> + * strrchr - Find the last occurrence of a character in a string
> + * @s: The string to be searched
> + * @c: The character to search for
> + */
> +char *strrchr(const char *s, int c)
> +{
> +	const char *last = NULL;
> +	do {
> +		if (*s == (char)c)
> +			last = s;
> +	} while (*s++);
> +	return (char *)last;
> +}
> +EXPORT_SYMBOL(strrchr);
> +#endif
> +
> +#ifndef __HAVE_ARCH_MEMCMP
> +/**
> + * memcmp - Compare two areas of memory
> + * @cs: One area of memory
> + * @ct: Another area of memory
> + * @count: The size of the area.
> + */
> +#undef memcmp
> +__visible int memcmp(const void *cs, const void *ct, size_t count)
> +{
> +	const unsigned char *su1, *su2;
> +	int res = 0;
> +
> +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
> +	if (count >= sizeof(unsigned long)) {
> +		const unsigned long *u1 = cs;
> +		const unsigned long *u2 = ct;
> +		do {
> +			if (get_unaligned(u1) != get_unaligned(u2))
> +				break;
> +			u1++;
> +			u2++;
> +			count -= sizeof(unsigned long);
> +		} while (count >= sizeof(unsigned long));
> +		cs = u1;
> +		ct = u2;
> +	}
> +#endif
> +	for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
> +		if ((res = *su1 - *su2) != 0)
> +			break;
> +	return res;
> +}
> +EXPORT_SYMBOL(memcmp);
> +#endif
> +
> +#ifndef __HAVE_ARCH_MEMCHR
> +/**
> + * memchr - Find a character in an area of memory.
> + * @s: The memory area
> + * @c: The byte to search for
> + * @n: The size of the area.
> + *
> + * returns the address of the first occurrence of @c, or %NULL
> + * if @c is not found
> + */
> +void *memchr(const void *s, int c, size_t n)
> +{
> +	const unsigned char *p = s;
> +	while (n-- != 0) {
> +		if ((unsigned char)c == *p++) {
> +			return (void *)(p - 1);
> +		}
> +	}
> +	return NULL;
> +}
> +EXPORT_SYMBOL(memchr);
> +#endif
> -- 
> 2.37.2
> 
>
Alexandre Ghiti Dec. 21, 2022, 2:23 p.m. UTC | #2
Hi Conor,

On Wed, Dec 21, 2022 at 3:06 PM Conor Dooley <conor@kernel.org> wrote:
>
> Hey Alex!
>
> On Fri, Dec 16, 2022 at 05:21:39PM +0100, Alexandre Ghiti wrote:
> > The EFI stub must not use any KASAN instrumented code as the kernel
> > proper did not initialize the thread pointer and the mapping for the
> > KASAN shadow region.
> >
> > Avoid using generic string functions by copying stub dependencies from
> > lib/string.c to drivers/firmware/efi/libstub/string.c as RISC-V does
> > not implement architecture-specific versions of those functions.
>
> To the unaware among us, how does this interact with Heiko's custom
> functions for bitmanip extensions? Is this diametrically opposed to
> that, or does it actually help avoid having to have special handling
> for the efi stub?

I'm not sure which patchset you are referring to, but I guess you are
talking about arch-specific string functions:

- If they are written in assembly and are then not kasan-instrumented,
we'll be able to use them and then revert part of this patch.
- If they are written in C and are then kasan-instrumented (because
we'll want to instrument them), we'll keep using the implementation
added here.

Hope that answers your question!

Alex

>
> Also, checkpatch seems to be rather unhappy with you here:
> https://gist.github.com/conor-pwbot/e5b4c8f2c3b88b4a8fcab4df437613e2

Yes, those new functions are exact copies from lib/string.c, I did not
want to fix those checkpatch errors in this patchset.

>
> Thanks,
> Conor.
>
> >
> > Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
> > ---
> >  arch/riscv/kernel/image-vars.h        |   8 --
> >  drivers/firmware/efi/libstub/Makefile |   7 +-
> >  drivers/firmware/efi/libstub/string.c | 133 ++++++++++++++++++++++++++
> >  3 files changed, 137 insertions(+), 11 deletions(-)
> >
> > diff --git a/arch/riscv/kernel/image-vars.h b/arch/riscv/kernel/image-vars.h
> > index d6e5f739905e..15616155008c 100644
> > --- a/arch/riscv/kernel/image-vars.h
> > +++ b/arch/riscv/kernel/image-vars.h
> > @@ -23,14 +23,6 @@
> >   * linked at. The routines below are all implemented in assembler in a
> >   * position independent manner
> >   */
> > -__efistub_memcmp             = memcmp;
> > -__efistub_memchr             = memchr;
> > -__efistub_strlen             = strlen;
> > -__efistub_strnlen            = strnlen;
> > -__efistub_strcmp             = strcmp;
> > -__efistub_strncmp            = strncmp;
> > -__efistub_strrchr            = strrchr;
> > -
> >  __efistub__start             = _start;
> >  __efistub__start_kernel              = _start_kernel;
> >  __efistub__end                       = _end;
> > diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
> > index b1601aad7e1a..031d2268bab5 100644
> > --- a/drivers/firmware/efi/libstub/Makefile
> > +++ b/drivers/firmware/efi/libstub/Makefile
> > @@ -130,9 +130,10 @@ STUBCOPY_RELOC-$(CONFIG_ARM)     := R_ARM_ABS
> >  # also means that we need to be extra careful to make sure that the stub does
> >  # not rely on any absolute symbol references, considering that the virtual
> >  # kernel mapping that the linker uses is not active yet when the stub is
> > -# executing. So build all C dependencies of the EFI stub into libstub, and do
> > -# a verification pass to see if any absolute relocations exist in any of the
> > -# object files.
> > +# executing. In addition, we need to make sure that the stub does not use KASAN
> > +# instrumented code like the generic string functions. So build all C
> > +# dependencies of the EFI stub into libstub, and do a verification pass to see
> > +# if any absolute relocations exist in any of the object files.
> >  #
> >  STUBCOPY_FLAGS-$(CONFIG_ARM64)       += --prefix-alloc-sections=.init \
> >                                  --prefix-symbols=__efistub_
> > diff --git a/drivers/firmware/efi/libstub/string.c b/drivers/firmware/efi/libstub/string.c
> > index 5d13e43869ee..5154ae6e7f10 100644
> > --- a/drivers/firmware/efi/libstub/string.c
> > +++ b/drivers/firmware/efi/libstub/string.c
> > @@ -113,3 +113,136 @@ long simple_strtol(const char *cp, char **endp, unsigned int base)
> >
> >       return simple_strtoull(cp, endp, base);
> >  }
> > +
> > +#ifndef __HAVE_ARCH_STRLEN
> > +/**
> > + * strlen - Find the length of a string
> > + * @s: The string to be sized
> > + */
> > +size_t strlen(const char *s)
> > +{
> > +     const char *sc;
> > +
> > +     for (sc = s; *sc != '\0'; ++sc)
> > +             /* nothing */;
> > +     return sc - s;
> > +}
> > +EXPORT_SYMBOL(strlen);
> > +#endif
> > +
> > +#ifndef __HAVE_ARCH_STRNLEN
> > +/**
> > + * strnlen - Find the length of a length-limited string
> > + * @s: The string to be sized
> > + * @count: The maximum number of bytes to search
> > + */
> > +size_t strnlen(const char *s, size_t count)
> > +{
> > +     const char *sc;
> > +
> > +     for (sc = s; count-- && *sc != '\0'; ++sc)
> > +             /* nothing */;
> > +     return sc - s;
> > +}
> > +EXPORT_SYMBOL(strnlen);
> > +#endif
> > +
> > +#ifndef __HAVE_ARCH_STRCMP
> > +/**
> > + * strcmp - Compare two strings
> > + * @cs: One string
> > + * @ct: Another string
> > + */
> > +int strcmp(const char *cs, const char *ct)
> > +{
> > +     unsigned char c1, c2;
> > +
> > +     while (1) {
> > +             c1 = *cs++;
> > +             c2 = *ct++;
> > +             if (c1 != c2)
> > +                     return c1 < c2 ? -1 : 1;
> > +             if (!c1)
> > +                     break;
> > +     }
> > +     return 0;
> > +}
> > +EXPORT_SYMBOL(strcmp);
> > +#endif
> > +
> > +#ifndef __HAVE_ARCH_STRRCHR
> > +/**
> > + * strrchr - Find the last occurrence of a character in a string
> > + * @s: The string to be searched
> > + * @c: The character to search for
> > + */
> > +char *strrchr(const char *s, int c)
> > +{
> > +     const char *last = NULL;
> > +     do {
> > +             if (*s == (char)c)
> > +                     last = s;
> > +     } while (*s++);
> > +     return (char *)last;
> > +}
> > +EXPORT_SYMBOL(strrchr);
> > +#endif
> > +
> > +#ifndef __HAVE_ARCH_MEMCMP
> > +/**
> > + * memcmp - Compare two areas of memory
> > + * @cs: One area of memory
> > + * @ct: Another area of memory
> > + * @count: The size of the area.
> > + */
> > +#undef memcmp
> > +__visible int memcmp(const void *cs, const void *ct, size_t count)
> > +{
> > +     const unsigned char *su1, *su2;
> > +     int res = 0;
> > +
> > +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
> > +     if (count >= sizeof(unsigned long)) {
> > +             const unsigned long *u1 = cs;
> > +             const unsigned long *u2 = ct;
> > +             do {
> > +                     if (get_unaligned(u1) != get_unaligned(u2))
> > +                             break;
> > +                     u1++;
> > +                     u2++;
> > +                     count -= sizeof(unsigned long);
> > +             } while (count >= sizeof(unsigned long));
> > +             cs = u1;
> > +             ct = u2;
> > +     }
> > +#endif
> > +     for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
> > +             if ((res = *su1 - *su2) != 0)
> > +                     break;
> > +     return res;
> > +}
> > +EXPORT_SYMBOL(memcmp);
> > +#endif
> > +
> > +#ifndef __HAVE_ARCH_MEMCHR
> > +/**
> > + * memchr - Find a character in an area of memory.
> > + * @s: The memory area
> > + * @c: The byte to search for
> > + * @n: The size of the area.
> > + *
> > + * returns the address of the first occurrence of @c, or %NULL
> > + * if @c is not found
> > + */
> > +void *memchr(const void *s, int c, size_t n)
> > +{
> > +     const unsigned char *p = s;
> > +     while (n-- != 0) {
> > +             if ((unsigned char)c == *p++) {
> > +                     return (void *)(p - 1);
> > +             }
> > +     }
> > +     return NULL;
> > +}
> > +EXPORT_SYMBOL(memchr);
> > +#endif
> > --
> > 2.37.2
> >
> >
Conor Dooley Dec. 21, 2022, 3 p.m. UTC | #3
On Wed, Dec 21, 2022 at 03:23:36PM +0100, Alexandre Ghiti wrote:
> Hi Conor,
> 
> On Wed, Dec 21, 2022 at 3:06 PM Conor Dooley <conor@kernel.org> wrote:
> >
> > Hey Alex!
> >
> > On Fri, Dec 16, 2022 at 05:21:39PM +0100, Alexandre Ghiti wrote:
> > > The EFI stub must not use any KASAN instrumented code as the kernel
> > > proper did not initialize the thread pointer and the mapping for the
> > > KASAN shadow region.
> > >
> > > Avoid using generic string functions by copying stub dependencies from
> > > lib/string.c to drivers/firmware/efi/libstub/string.c as RISC-V does
> > > not implement architecture-specific versions of those functions.
> >
> > To the unaware among us, how does this interact with Heiko's custom
> > functions for bitmanip extensions? Is this diametrically opposed to
> > that, or does it actually help avoid having to have special handling
> > for the efi stub?
> 
> I'm not sure which patchset you are referring to, but I guess you are
> talking about arch-specific string functions:

Oh sorry, I thought I had linked it..
https://lore.kernel.org/linux-riscv/20221130225614.1594256-1-heiko@sntech.de/

> - If they are written in assembly and are then not kasan-instrumented,
> we'll be able to use them and then revert part of this patch.

They are indeed written in assembly. Ard had left some comments there.
Heiko's intention was to keep them out of the efistub, so perhaps your
patchset helps him out.

> - If they are written in C and are then kasan-instrumented (because
> we'll want to instrument them), we'll keep using the implementation
> added here.
> 
> Hope that answers your question!
> 
> Alex
> 
> >
> > Also, checkpatch seems to be rather unhappy with you here:
> > https://gist.github.com/conor-pwbot/e5b4c8f2c3b88b4a8fcab4df437613e2
> 
> Yes, those new functions are exact copies from lib/string.c, I did not
> want to fix those checkpatch errors in this patchset.

I figured from the description that that was likely, just mentioned it
as I was already replying! Apologies for not looking at the source of
the copy.

Thanks!

> > >
> > > Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
> > > ---
> > >  arch/riscv/kernel/image-vars.h        |   8 --
> > >  drivers/firmware/efi/libstub/Makefile |   7 +-
> > >  drivers/firmware/efi/libstub/string.c | 133 ++++++++++++++++++++++++++
> > >  3 files changed, 137 insertions(+), 11 deletions(-)
> > >
> > > diff --git a/arch/riscv/kernel/image-vars.h b/arch/riscv/kernel/image-vars.h
> > > index d6e5f739905e..15616155008c 100644
> > > --- a/arch/riscv/kernel/image-vars.h
> > > +++ b/arch/riscv/kernel/image-vars.h
> > > @@ -23,14 +23,6 @@
> > >   * linked at. The routines below are all implemented in assembler in a
> > >   * position independent manner
> > >   */
> > > -__efistub_memcmp             = memcmp;
> > > -__efistub_memchr             = memchr;
> > > -__efistub_strlen             = strlen;
> > > -__efistub_strnlen            = strnlen;
> > > -__efistub_strcmp             = strcmp;
> > > -__efistub_strncmp            = strncmp;
> > > -__efistub_strrchr            = strrchr;
> > > -
> > >  __efistub__start             = _start;
> > >  __efistub__start_kernel              = _start_kernel;
> > >  __efistub__end                       = _end;
> > > diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
> > > index b1601aad7e1a..031d2268bab5 100644
> > > --- a/drivers/firmware/efi/libstub/Makefile
> > > +++ b/drivers/firmware/efi/libstub/Makefile
> > > @@ -130,9 +130,10 @@ STUBCOPY_RELOC-$(CONFIG_ARM)     := R_ARM_ABS
> > >  # also means that we need to be extra careful to make sure that the stub does
> > >  # not rely on any absolute symbol references, considering that the virtual
> > >  # kernel mapping that the linker uses is not active yet when the stub is
> > > -# executing. So build all C dependencies of the EFI stub into libstub, and do
> > > -# a verification pass to see if any absolute relocations exist in any of the
> > > -# object files.
> > > +# executing. In addition, we need to make sure that the stub does not use KASAN
> > > +# instrumented code like the generic string functions. So build all C
> > > +# dependencies of the EFI stub into libstub, and do a verification pass to see
> > > +# if any absolute relocations exist in any of the object files.
> > >  #
> > >  STUBCOPY_FLAGS-$(CONFIG_ARM64)       += --prefix-alloc-sections=.init \
> > >                                  --prefix-symbols=__efistub_
> > > diff --git a/drivers/firmware/efi/libstub/string.c b/drivers/firmware/efi/libstub/string.c
> > > index 5d13e43869ee..5154ae6e7f10 100644
> > > --- a/drivers/firmware/efi/libstub/string.c
> > > +++ b/drivers/firmware/efi/libstub/string.c
> > > @@ -113,3 +113,136 @@ long simple_strtol(const char *cp, char **endp, unsigned int base)
> > >
> > >       return simple_strtoull(cp, endp, base);
> > >  }
> > > +
> > > +#ifndef __HAVE_ARCH_STRLEN
> > > +/**
> > > + * strlen - Find the length of a string
> > > + * @s: The string to be sized
> > > + */
> > > +size_t strlen(const char *s)
> > > +{
> > > +     const char *sc;
> > > +
> > > +     for (sc = s; *sc != '\0'; ++sc)
> > > +             /* nothing */;
> > > +     return sc - s;
> > > +}
> > > +EXPORT_SYMBOL(strlen);
> > > +#endif
> > > +
> > > +#ifndef __HAVE_ARCH_STRNLEN
> > > +/**
> > > + * strnlen - Find the length of a length-limited string
> > > + * @s: The string to be sized
> > > + * @count: The maximum number of bytes to search
> > > + */
> > > +size_t strnlen(const char *s, size_t count)
> > > +{
> > > +     const char *sc;
> > > +
> > > +     for (sc = s; count-- && *sc != '\0'; ++sc)
> > > +             /* nothing */;
> > > +     return sc - s;
> > > +}
> > > +EXPORT_SYMBOL(strnlen);
> > > +#endif
> > > +
> > > +#ifndef __HAVE_ARCH_STRCMP
> > > +/**
> > > + * strcmp - Compare two strings
> > > + * @cs: One string
> > > + * @ct: Another string
> > > + */
> > > +int strcmp(const char *cs, const char *ct)
> > > +{
> > > +     unsigned char c1, c2;
> > > +
> > > +     while (1) {
> > > +             c1 = *cs++;
> > > +             c2 = *ct++;
> > > +             if (c1 != c2)
> > > +                     return c1 < c2 ? -1 : 1;
> > > +             if (!c1)
> > > +                     break;
> > > +     }
> > > +     return 0;
> > > +}
> > > +EXPORT_SYMBOL(strcmp);
> > > +#endif
> > > +
> > > +#ifndef __HAVE_ARCH_STRRCHR
> > > +/**
> > > + * strrchr - Find the last occurrence of a character in a string
> > > + * @s: The string to be searched
> > > + * @c: The character to search for
> > > + */
> > > +char *strrchr(const char *s, int c)
> > > +{
> > > +     const char *last = NULL;
> > > +     do {
> > > +             if (*s == (char)c)
> > > +                     last = s;
> > > +     } while (*s++);
> > > +     return (char *)last;
> > > +}
> > > +EXPORT_SYMBOL(strrchr);
> > > +#endif
> > > +
> > > +#ifndef __HAVE_ARCH_MEMCMP
> > > +/**
> > > + * memcmp - Compare two areas of memory
> > > + * @cs: One area of memory
> > > + * @ct: Another area of memory
> > > + * @count: The size of the area.
> > > + */
> > > +#undef memcmp
> > > +__visible int memcmp(const void *cs, const void *ct, size_t count)
> > > +{
> > > +     const unsigned char *su1, *su2;
> > > +     int res = 0;
> > > +
> > > +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
> > > +     if (count >= sizeof(unsigned long)) {
> > > +             const unsigned long *u1 = cs;
> > > +             const unsigned long *u2 = ct;
> > > +             do {
> > > +                     if (get_unaligned(u1) != get_unaligned(u2))
> > > +                             break;
> > > +                     u1++;
> > > +                     u2++;
> > > +                     count -= sizeof(unsigned long);
> > > +             } while (count >= sizeof(unsigned long));
> > > +             cs = u1;
> > > +             ct = u2;
> > > +     }
> > > +#endif
> > > +     for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
> > > +             if ((res = *su1 - *su2) != 0)
> > > +                     break;
> > > +     return res;
> > > +}
> > > +EXPORT_SYMBOL(memcmp);
> > > +#endif
> > > +
> > > +#ifndef __HAVE_ARCH_MEMCHR
> > > +/**
> > > + * memchr - Find a character in an area of memory.
> > > + * @s: The memory area
> > > + * @c: The byte to search for
> > > + * @n: The size of the area.
> > > + *
> > > + * returns the address of the first occurrence of @c, or %NULL
> > > + * if @c is not found
> > > + */
> > > +void *memchr(const void *s, int c, size_t n)
> > > +{
> > > +     const unsigned char *p = s;
> > > +     while (n-- != 0) {
> > > +             if ((unsigned char)c == *p++) {
> > > +                     return (void *)(p - 1);
> > > +             }
> > > +     }
> > > +     return NULL;
> > > +}
> > > +EXPORT_SYMBOL(memchr);
> > > +#endif
> > > --
> > > 2.37.2
> > >
> > >
Heiko Stuebner Jan. 4, 2023, 3:38 p.m. UTC | #4
Am Freitag, 16. Dezember 2022, 17:21:39 CET schrieb Alexandre Ghiti:
> The EFI stub must not use any KASAN instrumented code as the kernel
> proper did not initialize the thread pointer and the mapping for the
> KASAN shadow region.
> 
> Avoid using generic string functions by copying stub dependencies from
> lib/string.c to drivers/firmware/efi/libstub/string.c as RISC-V does
> not implement architecture-specific versions of those functions.
> 
> Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>

I think a similar change already went into 6.2-rc1 [0],
though it seems to leave strcmp in place in image-vars.h



[0] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=da8dd0c75b3f82eb366eb1745fb473ea92c8c087
diff mbox series

Patch

diff --git a/arch/riscv/kernel/image-vars.h b/arch/riscv/kernel/image-vars.h
index d6e5f739905e..15616155008c 100644
--- a/arch/riscv/kernel/image-vars.h
+++ b/arch/riscv/kernel/image-vars.h
@@ -23,14 +23,6 @@ 
  * linked at. The routines below are all implemented in assembler in a
  * position independent manner
  */
-__efistub_memcmp		= memcmp;
-__efistub_memchr		= memchr;
-__efistub_strlen		= strlen;
-__efistub_strnlen		= strnlen;
-__efistub_strcmp		= strcmp;
-__efistub_strncmp		= strncmp;
-__efistub_strrchr		= strrchr;
-
 __efistub__start		= _start;
 __efistub__start_kernel		= _start_kernel;
 __efistub__end			= _end;
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index b1601aad7e1a..031d2268bab5 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -130,9 +130,10 @@  STUBCOPY_RELOC-$(CONFIG_ARM)	:= R_ARM_ABS
 # also means that we need to be extra careful to make sure that the stub does
 # not rely on any absolute symbol references, considering that the virtual
 # kernel mapping that the linker uses is not active yet when the stub is
-# executing. So build all C dependencies of the EFI stub into libstub, and do
-# a verification pass to see if any absolute relocations exist in any of the
-# object files.
+# executing. In addition, we need to make sure that the stub does not use KASAN
+# instrumented code like the generic string functions. So build all C
+# dependencies of the EFI stub into libstub, and do a verification pass to see
+# if any absolute relocations exist in any of the object files.
 #
 STUBCOPY_FLAGS-$(CONFIG_ARM64)	+= --prefix-alloc-sections=.init \
 				   --prefix-symbols=__efistub_
diff --git a/drivers/firmware/efi/libstub/string.c b/drivers/firmware/efi/libstub/string.c
index 5d13e43869ee..5154ae6e7f10 100644
--- a/drivers/firmware/efi/libstub/string.c
+++ b/drivers/firmware/efi/libstub/string.c
@@ -113,3 +113,136 @@  long simple_strtol(const char *cp, char **endp, unsigned int base)
 
 	return simple_strtoull(cp, endp, base);
 }
+
+#ifndef __HAVE_ARCH_STRLEN
+/**
+ * strlen - Find the length of a string
+ * @s: The string to be sized
+ */
+size_t strlen(const char *s)
+{
+	const char *sc;
+
+	for (sc = s; *sc != '\0'; ++sc)
+		/* nothing */;
+	return sc - s;
+}
+EXPORT_SYMBOL(strlen);
+#endif
+
+#ifndef __HAVE_ARCH_STRNLEN
+/**
+ * strnlen - Find the length of a length-limited string
+ * @s: The string to be sized
+ * @count: The maximum number of bytes to search
+ */
+size_t strnlen(const char *s, size_t count)
+{
+	const char *sc;
+
+	for (sc = s; count-- && *sc != '\0'; ++sc)
+		/* nothing */;
+	return sc - s;
+}
+EXPORT_SYMBOL(strnlen);
+#endif
+
+#ifndef __HAVE_ARCH_STRCMP
+/**
+ * strcmp - Compare two strings
+ * @cs: One string
+ * @ct: Another string
+ */
+int strcmp(const char *cs, const char *ct)
+{
+	unsigned char c1, c2;
+
+	while (1) {
+		c1 = *cs++;
+		c2 = *ct++;
+		if (c1 != c2)
+			return c1 < c2 ? -1 : 1;
+		if (!c1)
+			break;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(strcmp);
+#endif
+
+#ifndef __HAVE_ARCH_STRRCHR
+/**
+ * strrchr - Find the last occurrence of a character in a string
+ * @s: The string to be searched
+ * @c: The character to search for
+ */
+char *strrchr(const char *s, int c)
+{
+	const char *last = NULL;
+	do {
+		if (*s == (char)c)
+			last = s;
+	} while (*s++);
+	return (char *)last;
+}
+EXPORT_SYMBOL(strrchr);
+#endif
+
+#ifndef __HAVE_ARCH_MEMCMP
+/**
+ * memcmp - Compare two areas of memory
+ * @cs: One area of memory
+ * @ct: Another area of memory
+ * @count: The size of the area.
+ */
+#undef memcmp
+__visible int memcmp(const void *cs, const void *ct, size_t count)
+{
+	const unsigned char *su1, *su2;
+	int res = 0;
+
+#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+	if (count >= sizeof(unsigned long)) {
+		const unsigned long *u1 = cs;
+		const unsigned long *u2 = ct;
+		do {
+			if (get_unaligned(u1) != get_unaligned(u2))
+				break;
+			u1++;
+			u2++;
+			count -= sizeof(unsigned long);
+		} while (count >= sizeof(unsigned long));
+		cs = u1;
+		ct = u2;
+	}
+#endif
+	for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
+		if ((res = *su1 - *su2) != 0)
+			break;
+	return res;
+}
+EXPORT_SYMBOL(memcmp);
+#endif
+
+#ifndef __HAVE_ARCH_MEMCHR
+/**
+ * memchr - Find a character in an area of memory.
+ * @s: The memory area
+ * @c: The byte to search for
+ * @n: The size of the area.
+ *
+ * returns the address of the first occurrence of @c, or %NULL
+ * if @c is not found
+ */
+void *memchr(const void *s, int c, size_t n)
+{
+	const unsigned char *p = s;
+	while (n-- != 0) {
+		if ((unsigned char)c == *p++) {
+			return (void *)(p - 1);
+		}
+	}
+	return NULL;
+}
+EXPORT_SYMBOL(memchr);
+#endif