diff mbox series

[1/2] Fix regression by introducing strlcpy

Message ID 20200415123138.17661-1-sbabic@denx.de
State Accepted
Headers show
Series [1/2] Fix regression by introducing strlcpy | expand

Commit Message

Stefano Babic April 15, 2020, 12:31 p.m. UTC
The implemented strlcpy is buggy, fixed it.

Signed-off-by: Stefano Babic <sbabic@denx.de>
---
 core/util.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

Comments

Michael Adler April 15, 2020, 1:26 p.m. UTC | #1
Hi Stefano,

I was just about to submit a patch for the same regression (parsing `sw->software_set`), but you were a little bit
faster :-)

> The implemented strlcpy is buggy, fixed it.

Since I spent some time on this issue as well, I was wondering what is the origin of your `strlcpy` implementation?  You
said [1] that you took it from FreeBSD, however the implementation there is different from yours and doesn't seem to
suffer from this bug:

- https://github.com/freebsd/freebsd/blob/master/sys/libkern/strlcpy.c
- https://github.com/freedesktop/libbsd/blob/master/src/strlcpy.c

Is it an issue with the BSD license?

Kind regards,
  Michael

[1] https://groups.google.com/forum/#!topic/swupdate/wHPTpn4Tcc8
Stefano Babic April 15, 2020, 1:43 p.m. UTC | #2
Hi Michael,

On 15.04.20 15:26, Michael Adler wrote:
> Hi Stefano,
> 
> I was just about to submit a patch for the same regression (parsing `sw->software_set`), but you were a little bit
> faster :-)

I am running some tests before relase for end of the week, and I have
hit these issues on a target.

> 
>> The implemented strlcpy is buggy, fixed it.
> 
> Since I spent some time on this issue as well, I was wondering what is the origin of your `strlcpy` implementation?  You
> said [1] that you took it from FreeBSD,

The strlcpy() is present in FreeBSD and not in Linux, but solves the
issue report by coverity because it ensures that a copied string is
always terminated.

After saying this, I have implemented myself (and adding a bug due to
copy&paste from first lines, sigh !).

> however the implementation there is different from yours and doesn't seem to
> suffer from this bug:
> 
> - https://github.com/freebsd/freebsd/blob/master/sys/libkern/strlcpy.c
> - https://github.com/freedesktop/libbsd/blob/master/src/strlcpy.c

I have seen these, but I thought that calling memcpy() (also because
thare shoudl be an assembly version in libc) is faster as iterating the
buffer.

> 
> Is it an issue with the BSD license?

No - I can take FreeBSD code and license it under GPLv2 as far as I know.

Best regards,
Stefano

> 
> Kind regards,
>   Michael
> 
> [1] https://groups.google.com/forum/#!topic/swupdate/wHPTpn4Tcc8
>
Michael Adler April 15, 2020, 2:13 p.m. UTC | #3
> After saying this, I have implemented myself (and adding a bug due to
> copy&paste from first lines, sigh !).

I see, so it's actually not the implementation from FreeBSD (FWIW, I think the origin of strlcpy is actually OpenBSD).

> I have seen these, but I thought that calling memcpy() (also because
> thare shoudl be an assembly version in libc) is faster as iterating the
> buffer.

`memcpy()` is certainly faster, but I wonder if it really matters for the usages in SWUpdate?
However, having a secure and correct implementation of strlcpy certainly matters. For instance, I'm still a little wary
about the usage of `strlen` in your implementation: calling `strlen` on a non-zero terminated string is undefined
behavior.
Yes, all passed in strings have to be zero-terminated. Fair enough, but people make mistakes and sooner or later someone
will call this function with non-zero terminated input again. And in fact, it already happened in the case of
`parse_image_selector`. So, maybe it's safer to use `strnlen` instead. But even then, I cannot say for sure that there
are no other problems with it.

Kind regards,
  Michael
Stefano Babic April 15, 2020, 2:17 p.m. UTC | #4
On 15.04.20 16:13, Michael Adler wrote:
>> After saying this, I have implemented myself (and adding a bug due to
>> copy&paste from first lines, sigh !).
> 
> I see, so it's actually not the implementation from FreeBSD (FWIW, I think the origin of strlcpy is actually OpenBSD).
> 
>> I have seen these, but I thought that calling memcpy() (also because
>> thare shoudl be an assembly version in libc) is faster as iterating the
>> buffer.
> 
> `memcpy()` is certainly faster, but I wonder if it really matters for the usages in SWUpdate?

It does not really matter.

> However, having a secure and correct implementation of strlcpy certainly matters. For instance, I'm still a little wary
> about the usage of `strlen` in your implementation: calling `strlen` on a non-zero terminated string is undefined
> behavior.

Well, its is the base for a string copy..

> Yes, all passed in strings have to be zero-terminated. Fair enough, but people make mistakes and sooner or later someone
> will call this function with non-zero terminated input again. And in fact, it already happened in the case of
> `parse_image_selector`. So, maybe it's safer to use `strnlen` instead.

Agree.

> But even then, I cannot say for sure that there
> are no other problems with it.

So your suggestion is just to take FreeBSD implementation ? There are no
license issues, so this can be done.

Regards,
Stefano

> 
> Kind regards,
>   Michael
>
Michael Adler April 15, 2020, 2:37 p.m. UTC | #5
> So your suggestion is just to take FreeBSD implementation ? There are no
> license issues, so this can be done.

Yep. That version is very well tested and has been reviewed by much smarter people than me. It's just too easy to get
something wrong (or unsafe) in C. Thus, I would just go with upstream and worry about things in my software :)

Kind regards,
  Michael
diff mbox series

Patch

diff --git a/core/util.c b/core/util.c
index 86057cf..0ed75ff 100644
--- a/core/util.c
+++ b/core/util.c
@@ -220,12 +220,17 @@  strlcpy(char *dst, const char * src, size_t size)
 {
 
     size_t len = strlen(src);
+    /*
+     * src is null termintaed,
+     * copy the last '\0', too.
+     */
     if (len < size) {
         memcpy(dst, src, len + 1);
     } else if (len) {
-        memcpy(dst, src, len - 1);
+	/* truncate string */
+        memcpy(dst, src, size - 1);
 	/* Add C string terminator */
-        dst[len - 1] = '\0';
+        dst[size - 1] = '\0';
     }
     return len;
 }