From: Martin Wilck <mwilck@suse.com>
To: Benjamin Marzinski <bmarzins@redhat.com>
Cc: dm-devel@redhat.com
Subject: Re: [PATCH 12/35] libmultipath: strlcpy()/strlcat(): use restrict qualifier
Date: Tue, 04 Aug 2020 22:15:53 +0200 [thread overview]
Message-ID: <e978bc3dd9244d705eb4b1673490816768fffb5c.camel@suse.com> (raw)
In-Reply-To: <20200804172936.GK19233@octiron.msp.redhat.com>
On Tue, 2020-08-04 at 12:29 -0500, Benjamin Marzinski wrote:
> On Tue, Aug 04, 2020 at 05:36:31PM +0200, Martin Wilck wrote:
> > On Thu, 2020-07-16 at 17:18 -0500, Benjamin Marzinski wrote:
> > > On Thu, Jul 09, 2020 at 12:15:57PM +0200, mwilck@suse.com wrote:
> > > > From: Martin Wilck <mwilck@suse.com>
> > > >
> > > > Also remove the redundant local variables. It's not necessary
> > > > to
> > > > make "restrict" work, but it makes the intention more clear.
> > > >
> > > > Signed-off-by: Martin Wilck <mwilck@suse.com>
> > > > ---
> > > > libmultipath/util.c | 28 ++++++++++++----------------
> > > > libmultipath/util.h | 4 ++--
> > > > 2 files changed, 14 insertions(+), 18 deletions(-)
> > > >
> > > > diff --git a/libmultipath/util.c b/libmultipath/util.c
> > > > index 957fb97..f965094 100644
> > > > --- a/libmultipath/util.c
> > > > +++ b/libmultipath/util.c
> > > >
> > > > -size_t strlcat(char *dst, const char *src, size_t size)
> > > > +size_t strlcat(char * restrict dst, const char * restrict src,
> > > > size_t size)
> > > > {
> > > > size_t bytes = 0;
> > > > - char *q = dst;
> > > > - const char *p = src;
> > > > char ch;
> > > >
> > > > - while (bytes < size && *q) {
> > > > - q++;
> > > > + while (bytes < size && *dst) {
> > > > + dst++;
> > > > bytes++;
> > > > }
> > > > if (bytes == size)
> > >
> > > this should return the strlen(dst) + strlen(src). It wouldn't in
> > > the
> > > admittedly weird case where size isn't large enough to fit dst.
> >
> > Are you sure?
> >
>
> Nope. But I might be right.
>
> > https://linux.die.net/man/3/strlcat
> >
> > "Note, however, that if strlcat() traverses size characters without
> > finding a NUL, the length of the string is considered to be size
> > and
> > the destination string will not be NUL-terminated (since there was
> > no
> > space for the NUL)."
> >
> > The way I understand this is that the current code is actually
> > correct
> > in returning bytes + strlen(src).
> >
> > This is also consistent with what I see elsewhere
> >
> > https://github.com/ffainelli/uClibc/blob/master/libc/string/strlcat.c
>
> This returns bytes + strlen(src) like you think is correct
>
> > https://github.com/freebsd/freebsd/blob/master/crypto/heimdal/lib/roken/strlcat.c
>
> This returns strlen(dst) + strlen(src) like I think is correct
... only if strnlen() is unavailable. Otherwise it returns
dst_sz + strlen(src) (= bytes + strlen(src)), because len never exceeds
dst_sz.
This one:
https://opensource.apple.com/source/Libc/Libc-1244.30.3/string/strlcat.c.auto.html
also behaves like the current code (using strnlen()).
To be fair, https://www.sudo.ws/todd/papers/strlcpy.html
says that strlcat should return "the number of bytes needed to store
the entire string".
On https://elixir.bootlin.com/linux/latest/source/lib/string.c#L325
we see that the kernel would actually crash in the corner case we're
discussing.
> I would argue that the important lines from
> https://linux.die.net/man/3/strlcat
> are
>
> "The strlcpy() and strlcat() functions return the total length of the
> string they tried to create."
>
> and
>
> "For strlcat() that means the initial length of dst plus the length
> of
> src."
>
>
> The alternative to strlen(dst) + strlen(src) (which follows the
> snprintf
> convention, and I think makes the most sense) seems to be "the length
> of
> the string is considered to be size" which I assume means it should
> return bytes. According to the man page, the reason for this is to
> keep
> "strlcat() from running off the end of a string". I admit to being
> kinda
> confused about this. I suppose if you assume that you can't trust the
> strings enough to run strlen() this makes sense. But if you can't
> trust
> strlen(dst), you shouldn't be able to trust strlen(src) either, which
> means that strlcat() should never return more than bytes, and that is
> clearly at odds with other statements in the man page.
>
> In my mind, there is value in returning strlen(dst) + strlen(src),
> since
> that is the size needed to hold the strings. Returning bytes means
> you can
> write strlcat to avoid trusting strlen(). bytes + strlen(src) is a
> meaningless value, and getting that value doesn't protect you against
> src not being null terminated.
I agree with everything you say. Except that I believe that the authors
thought indeed this is a security feature.
https://stackoverflow.com/questions/33154740/strlcat-is-dst-always-nul-terminated-what-are-size-and-the-returned-value
provides a hint about the rationale:
"size is expected to be the size of the memory region containing dst,
so that dst[size] is assumed to be an invalid memory reference." With
this in mind, passing a non-nul-terminated string to strlcat is an
error for "src", but not for "dst", and calling strlen(dst) from
strlcat() would be a bug.
> Clearly this is a nitpicky corner case, and I don't think we need
> protection against src not being null terminated, so I'm not strongly
> against bytes + strlen(src), if you prefer that.
rationale
That code line wasn't touched by my patch anyway, so I propose that we
leave it as-is for now.
Best,
Martin
next prev parent reply other threads:[~2020-08-04 20:15 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-07-09 10:15 [PATCH 00/35] multipath-tools series part I: minor changes mwilck
2020-07-09 10:15 ` [PATCH 01/35] multipath-tools tests/util: separate group for bitmask tests mwilck
2020-07-09 10:15 ` [PATCH 02/35] multipath-tools tests/directio: fix missing initializers mwilck
2020-07-09 10:15 ` [PATCH 03/35] tests: __wrap_dlog: use check_expected() mwilck
2020-07-09 10:15 ` [PATCH 04/35] multipath tools tests: add strchop() test mwilck
2020-07-09 10:15 ` [PATCH 05/35] libmultipath: improve strchop() mwilck
2020-07-09 10:15 ` [PATCH 06/35] multipath-tools tests: add test for devt2devname mwilck
2020-07-09 10:15 ` [PATCH 07/35] libmultipath: devt2devname(): simplify using libudev mwilck
2020-07-09 10:15 ` [PATCH 08/35] libmultipath: create bitfield abstraction mwilck
2020-07-16 21:17 ` Benjamin Marzinski
2020-08-04 15:04 ` Martin Wilck
2020-08-04 15:18 ` Martin Wilck
2020-08-04 16:26 ` Benjamin Marzinski
2020-08-04 19:35 ` Martin Wilck
2020-08-10 18:05 ` Benjamin Marzinski
2020-08-10 18:59 ` Martin Wilck
2020-07-09 10:15 ` [PATCH 09/35] libmultipath: use bitfields in group_by_match() mwilck
2020-07-09 10:15 ` [PATCH 10/35] libmultipath: util: constify function arguments mwilck
2020-07-09 10:15 ` [PATCH 11/35] multipath-tools tests: add unit tests for strlcat mwilck
2020-07-09 10:15 ` [PATCH 12/35] libmultipath: strlcpy()/strlcat(): use restrict qualifier mwilck
2020-07-16 22:18 ` Benjamin Marzinski
2020-08-04 15:36 ` Martin Wilck
2020-08-04 17:29 ` Benjamin Marzinski
2020-08-04 20:15 ` Martin Wilck [this message]
2020-07-09 10:15 ` [PATCH 13/35] libmultipath: constify blacklist code mwilck
2020-07-09 10:15 ` [PATCH 14/35] libmultipath: rlookup_binding(): remove newline in log message mwilck
2020-07-09 10:16 ` [PATCH 15/35] libmultipath: fix missing initializer warning from clang 3.9 mwilck
2020-07-09 10:16 ` [PATCH 16/35] libmultipath: fix gcc -Wstringop-overflow warning mwilck
2020-07-09 10:16 ` [PATCH 17/35] libmultipath: remove uevent listener failback mwilck
2020-07-09 10:16 ` [PATCH 18/35] libmultipath: uevent: use static linkage where possible mwilck
2020-07-09 10:16 ` [PATCH 19/35] libmultipath: uevent: inline trivial functions mwilck
2020-07-09 10:16 ` [PATCH 20/35] libmultipath: decrease log level of "SCSI target" log message mwilck
2020-07-09 10:16 ` [PATCH 21/35] libmultipath: get_udev_uid(): more appropriate error code mwilck
2020-07-09 10:16 ` [PATCH 22/35] libmultipath: get_uid(): improve log message on udev failure mwilck
2020-07-09 10:16 ` [PATCH 23/35] libmultipath: make sysfs_pathinfo() static and use const mwilck
2020-07-09 10:16 ` [PATCH 24/35] libmultipath: pathinfo(): improve a log message mwilck
2020-07-09 10:16 ` [PATCH 25/35] libmultipath: pathinfo(): don't filter emtpy devnode names mwilck
2020-07-09 10:16 ` [PATCH 26/35] libmultipath: io_err_stat_handle_pathfail(): less error conditions mwilck
2020-07-09 10:16 ` [PATCH 27/35] libmultipath: improve libdm logging mwilck
2020-07-09 10:16 ` [PATCH 28/35] libmultipath: snprint_devices(): use udev_enumerate mwilck
2020-07-09 10:16 ` [PATCH 29/35] libmultipath: snprint_devices(): print hidden/foreign status mwilck
2020-07-09 10:16 ` [PATCH 30/35] libmultipath: alloc_path(): initialize pp->initialized mwilck
2020-07-09 10:16 ` [PATCH 31/35] libmultipath: alloc_path_with_pathinfo(): treat devname overflow as error mwilck
2020-07-09 10:16 ` [PATCH 32/35] libmultipath: log table params in addmap() mwilck
2020-07-09 10:16 ` [PATCH 33/35] multipathd: remove set_multipath_wwid() mwilck
2020-07-09 10:16 ` [PATCH 34/35] kpartx: print an error message if removing a partition fails mwilck
2020-07-09 10:16 ` [PATCH 35/35] kpartx: add missing newline mwilck
2020-07-20 21:09 ` [PATCH 00/35] multipath-tools series part I: minor changes Benjamin Marzinski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=e978bc3dd9244d705eb4b1673490816768fffb5c.camel@suse.com \
--to=mwilck@suse.com \
--cc=bmarzins@redhat.com \
--cc=dm-devel@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.