[v1,1/1] seq_file: Replace strncpy()+nul by strscpy()

Message ID 20230717093332.54236-1-andriy.shevchenko@linux.intel.com
State New
Headers
Series [v1,1/1] seq_file: Replace strncpy()+nul by strscpy() |

Commit Message

Andy Shevchenko July 17, 2023, 9:33 a.m. UTC
  Privided seq_show_option_n() macro breaks build with -Werror
and W=1, e.g.:

In function ‘strncpy’,
    inlined from ‘ocfs2_show_options’ at fs/ocfs2/super.c:1520:3:
include/linux/fortify-string.h:68:33: error: ‘__builtin_strncpy’ output may be truncated copying 4 bytes from a string of length 4 [-Werror=stringop-truncation]
   68 | #define __underlying_strncpy    __builtin_strncpy
      |                                 ^
include/linux/fortify-string.h:151:16: note: in expansion of macro ‘__underlying_strncpy’
  151 |         return __underlying_strncpy(p, q, size);
      |                ^~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors

While -Werror wasn't enabled by default at the time of the original code
landed into mainline, strscpy() was already there and preferred over strncpy().
Due to above mentioned issues, use the latter in seq_show_option_n().

Fixes: a068acf2ee77 ("fs: create and use seq_show_option for escaping")
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 include/linux/seq_file.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
  

Comments

Kees Cook July 17, 2023, 3:43 p.m. UTC | #1
On Mon, Jul 17, 2023 at 12:33:32PM +0300, Andy Shevchenko wrote:
> Privided seq_show_option_n() macro breaks build with -Werror
> and W=1, e.g.:
> 
> In function ‘strncpy’,
>     inlined from ‘ocfs2_show_options’ at fs/ocfs2/super.c:1520:3:
> include/linux/fortify-string.h:68:33: error: ‘__builtin_strncpy’ output may be truncated copying 4 bytes from a string of length 4 [-Werror=stringop-truncation]
>    68 | #define __underlying_strncpy    __builtin_strncpy
>       |                                 ^

While I totally agree with the removal of strncpy(), I'm confused about
how this warning is being produced:

                seq_show_option_n(s, "cluster_stack", osb->osb_cluster_stack,
                                  OCFS2_STACK_LABEL_LEN);

fs/ocfs2/ocfs2.h:389:   char osb_cluster_stack[OCFS2_STACK_LABEL_LEN + 1];

fs/ocfs2/ocfs2_fs.h:#define OCFS2_STACK_LABEL_LEN               4

#define seq_show_option_n(m, name, value, length) {  \
     char val_buf[length + 1];                       \
     strncpy(val_buf, value, length);                \
...

the source buffer is OCFS2_STACK_LABEL_LEN + 1 long, and the dest buffer
is OCFS2_STACK_LABEL_LEN + 1 long. ??

I think this doesn't need to use seq_show_option_n() at all.

> include/linux/fortify-string.h:151:16: note: in expansion of macro ‘__underlying_strncpy’
>   151 |         return __underlying_strncpy(p, q, size);
>       |                ^~~~~~~~~~~~~~~~~~~~
> cc1: all warnings being treated as errors
> 
> While -Werror wasn't enabled by default at the time of the original code
> landed into mainline, strscpy() was already there and preferred over strncpy().
> Due to above mentioned issues, use the latter in seq_show_option_n().
> 
> Fixes: a068acf2ee77 ("fs: create and use seq_show_option for escaping")
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
>  include/linux/seq_file.h | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
> index bd023dd38ae6..e87d635ca24f 100644
> --- a/include/linux/seq_file.h
> +++ b/include/linux/seq_file.h
> @@ -260,8 +260,7 @@ static inline void seq_show_option(struct seq_file *m, const char *name,
>   */
>  #define seq_show_option_n(m, name, value, length) {	\
>  	char val_buf[length + 1];			\
> -	strncpy(val_buf, value, length);		\
> -	val_buf[length] = '\0';				\
> +	strscpy(val_buf, value, sizeof(val_buf));	\
>  	seq_show_option(m, name, val_buf);		\
>  }

Reviewed-by: Kees Cook <keescook@chromium.org>

-Kees
  
Andy Shevchenko July 17, 2023, 4:05 p.m. UTC | #2
On Mon, Jul 17, 2023 at 08:43:55AM -0700, Kees Cook wrote:
> On Mon, Jul 17, 2023 at 12:33:32PM +0300, Andy Shevchenko wrote:

...

> I think this doesn't need to use seq_show_option_n() at all.

Quite likely. Nevertheless, it's one of the dozens (?) warnings like this.

...

> Reviewed-by: Kees Cook <keescook@chromium.org>

Thank you for the review!

I think it's you who may take it as seq_file.h seems everybody's playground.
  
Kees Cook July 17, 2023, 10:58 p.m. UTC | #3
On Mon, Jul 17, 2023 at 07:05:44PM +0300, Andy Shevchenko wrote:
> On Mon, Jul 17, 2023 at 08:43:55AM -0700, Kees Cook wrote:
> > On Mon, Jul 17, 2023 at 12:33:32PM +0300, Andy Shevchenko wrote:
> 
> ...
> 
> > I think this doesn't need to use seq_show_option_n() at all.
> 
> Quite likely. Nevertheless, it's one of the dozens (?) warnings like this.
> 
> ...
> 
> > Reviewed-by: Kees Cook <keescook@chromium.org>
> 
> Thank you for the review!
> 
> I think it's you who may take it as seq_file.h seems everybody's playground.

Ah, good point. :P
  
Kees Cook July 17, 2023, 11:09 p.m. UTC | #4
On Mon, 17 Jul 2023 12:33:32 +0300, Andy Shevchenko wrote:
> Privided seq_show_option_n() macro breaks build with -Werror
> and W=1, e.g.:
> 
> In function ‘strncpy’,
>     inlined from ‘ocfs2_show_options’ at fs/ocfs2/super.c:1520:3:
> include/linux/fortify-string.h:68:33: error: ‘__builtin_strncpy’ output may be truncated copying 4 bytes from a string of length 4 [-Werror=stringop-truncation]
>    68 | #define __underlying_strncpy    __builtin_strncpy
>       |                                 ^
> include/linux/fortify-string.h:151:16: note: in expansion of macro ‘__underlying_strncpy’
>   151 |         return __underlying_strncpy(p, q, size);
>       |                ^~~~~~~~~~~~~~~~~~~~
> cc1: all warnings being treated as errors
> 
> [...]

Applied, thanks!

[1/1] seq_file: Replace strncpy()+nul by strscpy()
      https://git.kernel.org/kees/c/c30417b20f49

Best regards,
  
David Laight July 18, 2023, 9:42 a.m. UTC | #5
From: Andy Shevchenko
> Sent: 17 July 2023 10:34
...
>  #define seq_show_option_n(m, name, value, length) {	\
>  	char val_buf[length + 1];			\
> -	strncpy(val_buf, value, length);		\
> -	val_buf[length] = '\0';				\
> +	strscpy(val_buf, value, sizeof(val_buf));	\
>  	seq_show_option(m, name, val_buf);		\
>  }

Why the extra double-copy with (potentially) a VLA?

seq_show_option() calls seq_escape_str(),
seq_escape_str calls seq_escape_mem(...  strlen(src) ...).

Implement seq_show_option() as seq_show_option_n(... strlen(value))
and use seq_escape_mem() for the value.

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
  
Kees Cook July 19, 2023, 5 a.m. UTC | #6
On Mon, Jul 17, 2023 at 04:09:23PM -0700, Kees Cook wrote:
> 
> On Mon, 17 Jul 2023 12:33:32 +0300, Andy Shevchenko wrote:
> > Privided seq_show_option_n() macro breaks build with -Werror
> > and W=1, e.g.:
> > 
> > In function ‘strncpy’,
> >     inlined from ‘ocfs2_show_options’ at fs/ocfs2/super.c:1520:3:
> > include/linux/fortify-string.h:68:33: error: ‘__builtin_strncpy’ output may be truncated copying 4 bytes from a string of length 4 [-Werror=stringop-truncation]
> >    68 | #define __underlying_strncpy    __builtin_strncpy
> >       |                                 ^
> > include/linux/fortify-string.h:151:16: note: in expansion of macro ‘__underlying_strncpy’
> >   151 |         return __underlying_strncpy(p, q, size);
> >       |                ^~~~~~~~~~~~~~~~~~~~
> > cc1: all warnings being treated as errors
> > 
> > [...]
> 
> Applied, thanks!
> 
> [1/1] seq_file: Replace strncpy()+nul by strscpy()
>       https://git.kernel.org/kees/c/c30417b20f49

Gah, I dropped this from my tree since it was actually wrong[1]. This is an
ugly corner case with strscpy vs strncpy: the cast be32 from hfs/hfsplus[2]
looks unterminated to strscpy, so it would return -E2BIG, but really
FORTIFY noticed the over-read (strscpy is correctly checking the 5th
byte for NUL).

So... I think we need to fix seq_show_option_n() using memcpy+NUL, drop
the ocfs2 usage, and clarify that the seq_show_option_n() docs mean
"n means _exactly_ n bytes"...

-Kees

[1] https://lore.kernel.org/lkml/0000000000000a88cb0600ccef54@google.com/
[2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/hfsplus/options.c?h=v6.4#n221
  
Andy Shevchenko July 19, 2023, 5:26 a.m. UTC | #7
On Tue, Jul 18, 2023 at 10:00:24PM -0700, Kees Cook wrote:
> On Mon, Jul 17, 2023 at 04:09:23PM -0700, Kees Cook wrote:
> > On Mon, 17 Jul 2023 12:33:32 +0300, Andy Shevchenko wrote:
> > > Privided seq_show_option_n() macro breaks build with -Werror
> > > and W=1, e.g.:
> > > 
> > > In function ‘strncpy’,
> > >     inlined from ‘ocfs2_show_options’ at fs/ocfs2/super.c:1520:3:
> > > include/linux/fortify-string.h:68:33: error: ‘__builtin_strncpy’ output may be truncated copying 4 bytes from a string of length 4 [-Werror=stringop-truncation]
> > >    68 | #define __underlying_strncpy    __builtin_strncpy
> > >       |                                 ^
> > > include/linux/fortify-string.h:151:16: note: in expansion of macro ‘__underlying_strncpy’
> > >   151 |         return __underlying_strncpy(p, q, size);
> > >       |                ^~~~~~~~~~~~~~~~~~~~
> > > cc1: all warnings being treated as errors
> > > 
> > > [...]
> > 
> > Applied, thanks!
> > 
> > [1/1] seq_file: Replace strncpy()+nul by strscpy()
> >       https://git.kernel.org/kees/c/c30417b20f49
> 
> Gah, I dropped this from my tree since it was actually wrong[1]. This is an
> ugly corner case with strscpy vs strncpy: the cast be32 from hfs/hfsplus[2]
> looks unterminated to strscpy, so it would return -E2BIG, but really
> FORTIFY noticed the over-read (strscpy is correctly checking the 5th
> byte for NUL).
> 
> So... I think we need to fix seq_show_option_n() using memcpy+NUL, drop
> the ocfs2 usage, and clarify that the seq_show_option_n() docs mean
> "n means _exactly_ n bytes"...

Sounds like a plan!

Please go ahead with that. My intention is to make eventually build kernel with
`make W=1` when CONFIG_WERROR=y.

> [1] https://lore.kernel.org/lkml/0000000000000a88cb0600ccef54@google.com/
> [2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/hfsplus/options.c?h=v6.4#n221
  

Patch

diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
index bd023dd38ae6..e87d635ca24f 100644
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -260,8 +260,7 @@  static inline void seq_show_option(struct seq_file *m, const char *name,
  */
 #define seq_show_option_n(m, name, value, length) {	\
 	char val_buf[length + 1];			\
-	strncpy(val_buf, value, length);		\
-	val_buf[length] = '\0';				\
+	strscpy(val_buf, value, sizeof(val_buf));	\
 	seq_show_option(m, name, val_buf);		\
 }