[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAHk-=wj4BZei4JTiX9qsAwk8PEKnPrvkG5FU0i_HNkcDpy7NGQ@mail.gmail.com>
Date: Fri, 20 Oct 2023 10:56:31 -0700
From: Linus Torvalds <torvalds@...ux-foundation.org>
To: Justin Stitt <justinstitt@...gle.com>
Cc: Christoph Hellwig <hch@....de>, Kees Cook <keescook@...omium.org>,
Keith Busch <kbusch@...nel.org>, Jens Axboe <axboe@...nel.dk>,
Sagi Grimberg <sagi@...mberg.me>,
linux-nvme@...ts.infradead.org, linux-kernel@...r.kernel.org,
linux-hardening@...r.kernel.org, ksummit@...ts.linux.dev
Subject: Re: the nul-terminated string helper desk chair rearrangement
On Fri, 20 Oct 2023 at 10:40, Justin Stitt <justinstitt@...gle.com> wrote:
>
> There's some docs at [1]. Perhaps there could be more?
>
> [1]: https://elixir.bootlin.com/linux/v6.6-rc6/source/include/linux/fortify-string.h#L292
Note that we have so few 'strlcpy()' calls that we really should
remove that horrid horrid interface. It's a buggy piece of sh*t.
'strlcpy()' is fundamentally unsafe BY DESIGN if you don't trust the
source string - which is one of the alleged reasons to use it.
That said, while 'strscpy()' fixes the fundamental conceptual bugs of
strlcpy(), it's worth noting that it has *two* differences wrt
strlcpy:
- it doesn't have the broken return value
- it copies things in word-size chunks to be more efficient
And because of that word-size thing it will possibly insert more than
one NUL character at the end of the result.
To give an example, if you have
dst[64] = "abcdefghijklmnopqrstuvwxyz";
src[64] = "123\0........";
strlcpy(dst, src, 64);
then the strlcpy() will return 3 (the size of the copy), but the
destination will end up looking like
dst[64] = "123\0\0\0\0\0ijklmnopqrstuvwxyz...";
This odd "possibly word padding" is basically never relevant (and it's
obviously always also limited by the size you gave it), but *if* you
are doing something really odd, and you expect the end of the
destination string to not be modified at all past the final NUL of the
copy, you need to be aware of this.
It does mean that if you used to have
dst[4];
strlcpy(dst, "abc", 8);
then that *used* to work (because it would copy four bytes: "abc\0"
and that fits in 'dst[]'). But
dst[4];
strscpy(dst, "abc", 8);
will overflow dst[], because it will do a word-copy and you told
'strscpy()' that you had a 8-byte buffer, and it will try to write
"abc\0\0\0\0\0" into the destination.
The above is insane code, but it's an example of why a blind
strlcpy->strscpy conversion might change semantics.
Linus
Powered by blists - more mailing lists