Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement internal safe_strcpy to replace the strncpy #620

Merged
merged 3 commits into from
Oct 18, 2024

Conversation

arnopo
Copy link
Collaborator

@arnopo arnopo commented Sep 30, 2024

Compiler complain aboiut the use of strncpy that is not safe.

Already 3 PRs propose a fix of the issue:

strlcpy seems to have been recently integrated into glibc, but it appears to only prevent overflow in the destination buffer without ensuring that we do not perform a read out of the source buffer.

@arnopo arnopo changed the title implementa intaerbnal strlcpy to replace the strncpy implement internal strlcpy to replace the strncpy Sep 30, 2024
@arnopo arnopo requested review from edmooring and tnmysh September 30, 2024 09:45
@arnopo
Copy link
Collaborator Author

arnopo commented Sep 30, 2024

@wyr-7, @tomi-font,
Please, Could you check that this PR fits your needs and, if so, review the PR?

lib/utils/string.c Outdated Show resolved Hide resolved
tomi-font pushed a commit to tomi-font/zephyr-open-amp that referenced this pull request Sep 30, 2024
The strlcpy() function has only recently become available in glibc.
To ensure compatibility with legacy libc versions, this commit
implements an internal version of strlcpy().

The function has been adapted from the FreeBSD implementation to
fit our needs.

Signed-off-by: Arnaud Pouliquen <[email protected]>
(cherry picked from commit c7c85bcfeb4f2c1be772efea8a889aa796d1a7c1)

Upstream PR: OpenAMP/open-amp#620

Signed-off-by: Tomi Fontanilles <[email protected]>
tomi-font pushed a commit to tomi-font/zephyr-open-amp that referenced this pull request Sep 30, 2024
The strncpy function does not ensure that the destination string is
null-terminated. To address this issue, replace strncpy with the
internal strlcpy function, which guarantees null-termination of the
destination string.

Note: (void)strlcpy(...) indicates that the return value is intentionally
ignored.

Signed-off-by: Arnaud Pouliquen <[email protected]>
(cherry picked from commit e83acc98ad18f27bd1c12de808aaed84a0091791)

Upstream PR: OpenAMP/open-amp#620

Signed-off-by: Tomi Fontanilles <[email protected]>
tomi-font pushed a commit to tomi-font/zephyr-open-amp that referenced this pull request Sep 30, 2024
The strncpy function does not ensure that the destination string is
null-terminated. To address this issue, replace strncpy with the
internal strlcpy function, which guarantees null-termination of the
destination string.

Note: (void)strlcpy(...) indicates that the return value is intentionally
ignored.

Signed-off-by: Arnaud Pouliquen <[email protected]>
(cherry picked from commit b1606070c9109ac581e1aa8dcff2871d0207e839)

Upstream PR: OpenAMP/open-amp#620

Signed-off-by: Tomi Fontanilles <[email protected]>
tejlmand pushed a commit to tejlmand/open-amp that referenced this pull request Sep 30, 2024
The strlcpy() function has only recently become available in glibc.
To ensure compatibility with legacy libc versions, this commit
implements an internal version of strlcpy().

The function has been adapted from the FreeBSD implementation to
fit our needs.

Signed-off-by: Arnaud Pouliquen <[email protected]>
(cherry picked from commit c7c85bcfeb4f2c1be772efea8a889aa796d1a7c1)

Upstream PR: OpenAMP/open-amp#620

Signed-off-by: Tomi Fontanilles <[email protected]>
Signed-off-by: Torsten Rasmussen <[email protected]>
tejlmand pushed a commit to tejlmand/open-amp that referenced this pull request Sep 30, 2024
The strncpy function does not ensure that the destination string is
null-terminated. To address this issue, replace strncpy with the
internal strlcpy function, which guarantees null-termination of the
destination string.

Note: (void)strlcpy(...) indicates that the return value is intentionally
ignored.

Signed-off-by: Arnaud Pouliquen <[email protected]>
(cherry picked from commit e83acc98ad18f27bd1c12de808aaed84a0091791)

Upstream PR: OpenAMP/open-amp#620

Signed-off-by: Tomi Fontanilles <[email protected]>
Signed-off-by: Torsten Rasmussen <[email protected]>
tejlmand pushed a commit to tejlmand/open-amp that referenced this pull request Sep 30, 2024
The strncpy function does not ensure that the destination string is
null-terminated. To address this issue, replace strncpy with the
internal strlcpy function, which guarantees null-termination of the
destination string.

Note: (void)strlcpy(...) indicates that the return value is intentionally
ignored.

Signed-off-by: Arnaud Pouliquen <[email protected]>
(cherry picked from commit b1606070c9109ac581e1aa8dcff2871d0207e839)

Upstream PR: OpenAMP/open-amp#620

Signed-off-by: Tomi Fontanilles <[email protected]>
Signed-off-by: Torsten Rasmussen <[email protected]>
arnopo added a commit to zephyrproject-rtos/open-amp that referenced this pull request Oct 2, 2024
The strlcpy() function has only recently become available in glibc.
To ensure compatibility with legacy libc versions, this commit
implements an internal version of strlcpy().

The function has been adapted from the FreeBSD implementation to
fit our needs.

Signed-off-by: Arnaud Pouliquen <[email protected]>
(cherry picked from commit c7c85bcfeb4f2c1be772efea8a889aa796d1a7c1)

Upstream PR: OpenAMP/open-amp#620

Signed-off-by: Tomi Fontanilles <[email protected]>
Signed-off-by: Torsten Rasmussen <[email protected]>
arnopo added a commit to zephyrproject-rtos/open-amp that referenced this pull request Oct 2, 2024
The strncpy function does not ensure that the destination string is
null-terminated. To address this issue, replace strncpy with the
internal strlcpy function, which guarantees null-termination of the
destination string.

Note: (void)strlcpy(...) indicates that the return value is intentionally
ignored.

Signed-off-by: Arnaud Pouliquen <[email protected]>
(cherry picked from commit e83acc98ad18f27bd1c12de808aaed84a0091791)

Upstream PR: OpenAMP/open-amp#620

Signed-off-by: Tomi Fontanilles <[email protected]>
Signed-off-by: Torsten Rasmussen <[email protected]>
arnopo added a commit to zephyrproject-rtos/open-amp that referenced this pull request Oct 2, 2024
The strncpy function does not ensure that the destination string is
null-terminated. To address this issue, replace strncpy with the
internal strlcpy function, which guarantees null-termination of the
destination string.

Note: (void)strlcpy(...) indicates that the return value is intentionally
ignored.

Signed-off-by: Arnaud Pouliquen <[email protected]>
(cherry picked from commit b1606070c9109ac581e1aa8dcff2871d0207e839)

Upstream PR: OpenAMP/open-amp#620

Signed-off-by: Tomi Fontanilles <[email protected]>
Signed-off-by: Torsten Rasmussen <[email protected]>
@arnopo arnopo requested a review from xiaoxiang781216 October 3, 2024 10:09
tomi-font pushed a commit to tomi-font/zephyr-open-amp that referenced this pull request Oct 3, 2024
Origin:
	OpenAMP/open-amp#620

Commits:
	e233473d14654f08468595ad0dbe8f7e58acf267
	8591566382d055acd33f9d23e6826a8a4b0a1881
	1aecdc737d463b4ff1ece36847f4f2e68d4ffe4a

Status:
	Cherry pick PR that fixes the `stringop-truncation`
	compilation errors due to former usage of `strncpy()`.

Signed-off-by: Tomi Fontanilles <[email protected]>
Copy link
Contributor

@edmooring edmooring left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to go.

@laxiLang
Copy link

laxiLang commented Oct 10, 2024

I got such AddressSanitizer error from the "string.c":

==794327==ERROR: AddressSanitizer: global-buffer-overflow on address 0x08202c63 at pc 0xed441cde bp 0xe71feba8 sp 0xe71fe778
READ of size 1 at 0x08202c63 thread T2
    #0 0xed441cdd in __interceptor_strlen ../../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:389
    #1 0x80bbf1b in strlcpy ../../../../../../../modules/lib/open-amp/open-amp/lib/utils/string.c:52
0x08202c63 is located 0 bytes to the right of global variable '*.LC24' defined in '../../../../../../../modules/lib/open-amp/open-amp/lib/rpmsg/rpmsg_virtio.c' (0x8202c60) of size 3
  '*.LC24' is ascii string 'NS'
SUMMARY: AddressSanitizer: global-buffer-overflow ../../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:389 in __interceptor_strlen

It can resolved with the changes in zephyrproject-rtos/open-amp#23

@arnopo
Copy link
Collaborator Author

arnopo commented Oct 14, 2024

I got such AddressSanitizer error from the "string.c":

==794327==ERROR: AddressSanitizer: global-buffer-overflow on address 0x08202c63 at pc 0xed441cde bp 0xe71feba8 sp 0xe71fe778
READ of size 1 at 0x08202c63 thread T2
    #0 0xed441cdd in __interceptor_strlen ../../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:389
    #1 0x80bbf1b in strlcpy ../../../../../../../modules/lib/open-amp/open-amp/lib/utils/string.c:52
0x08202c63 is located 0 bytes to the right of global variable '*.LC24' defined in '../../../../../../../modules/lib/open-amp/open-amp/lib/rpmsg/rpmsg_virtio.c' (0x8202c60) of size 3
  '*.LC24' is ascii string 'NS'
SUMMARY: AddressSanitizer: global-buffer-overflow ../../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:389 in __interceptor_strlen

@laxiLang could you tell me how to reproduce the test

It can resolved with the changes in zephyrproject-rtos/open-amp#23

Copy/past from comment zephyrproject-rtos/open-amp@cff00b6#r1792242968:

The function has to return the total length of the string it tried to create so the size of the source
(https://man.freebsd.org/cgi/man.cgi?strlcpy(3))
The freebsd add in code while (*src++) resulting in same overflow issue than strlen, but perhaps not...
If you detect a potential issue, please, comment #620 with your observation that I fix it in the openamp
repo

@laxiLang
Copy link

laxiLang commented Oct 14, 2024

@arnopo : I enabled the GCC address sanitizer check. It can be easily reproduced if run a test function as below:

int main(int argc, char ** argv)
{
	union
	{
	  char src[2];
	  int  i;
	} u;
 	u.i = 0xFFFFFFFF;
 	char dst[100];
 	strlcpy(dst, &u.src[0], sizeof(dst));
}

got such below error:
#######################################################################################

==904719==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffffffda54 at pc 0x555555555299 bp 0x7fffffffd9d0 sp 0x7fffffffd9c0

READ of size 1 at 0x7fffffffda54 thread T0

    #0 0x555555555298 in strlcpy /home/jos1/repos/jos1-public/samples/strlcpy.c:11

    #1 0x555555555493 in main /home/jos1/repos/jos1-public/samples/strlcpy.c:37

    #2 0x7ffff7029d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58

    #3 0x7ffff7029e3f in __libc_start_main_impl ../csu/libc-start.c:392

    #4 0x555555555164 in _start (/home/jos1/repos/jos1-public/samples/strlcpy_sanitized+0x1164)
 
Address 0x7fffffffda54 is located in stack of thread T0 at offset 36 in frame

    #0 0x555555555397 in main /home/jos1/repos/jos1-public/samples/strlcpy.c:26
 
  This frame has 2 object(s):

    [32, 36) 'u' (line 31) <== Memory access at offset 36 overflows this variable

    [48, 148) 'dst' (line 35)

HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork

      (longjmp and C++ exceptions *are* supported)

SUMMARY: AddressSanitizer: stack-buffer-overflow /home/jos1/repos/jos1-public/samples/strlcpy.c:11 in strlcpy

Shadow bytes around the buggy address:

  0x10007fff7af0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

  0x10007fff7b00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

  0x10007fff7b10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

  0x10007fff7b20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

  0x10007fff7b30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

=>0x10007fff7b40: 00 00 00 00 00 00 f1 f1 f1 f1[04]f2 00 00 00 00

  0x10007fff7b50: 00 00 00 00 00 00 00 00 04 f3 f3 f3 f3 f3 00 00

  0x10007fff7b60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

  0x10007fff7b70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

  0x10007fff7b80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

  0x10007fff7b90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Shadow byte legend (one shadow byte represents 8 application bytes):

  Addressable:           00

  Partially addressable: 01 02 03 04 05 06 07 

  Heap left redzone:       fa

#######################################################################################

To make address sanitizer check passed, the below change with still return total length of the string works.

 strlcpy(char *dst, const char *src, size_t size)
 {
        size_t nleft = size;
+     const char *s= src;
         /* Copy as many bytes as will fit. */
        if (nleft != 0) {
                while (--nleft != 0) {
-                       *dst = *src++;
+                       *dst = *s++;

@arnopo
Copy link
Collaborator Author

arnopo commented Oct 14, 2024

The strlcpy should return the length of the source, but in the end, it seems not possible to know the source size.
more than that we could read at some address that is out of the src string memory (this seems the case in @laxiLang example).

Based on this, it looks to me that strlcpy is not 100% safe. A safer approach would be to provide the size of the source string in addition to the destination size, and then return the size of the destination string.

metal_weak size_t safe_strcpy(char *dst, size_t d_size, const char *src, size_t s_size)
{
	size_t size = metal_min(s_size, d_size);
	size_t nleft = size + 1;
	char *d = dst;

	/* Copy as many bytes as will fit. */
	if (nleft != 0) {
		while (--nleft != 0) {
			*dst = *src++;
			if (*dst++ == '\0')
				break;
		}
	}

	/*Fill last characters with '\0' */
	if (size < d_size)
		memset(dst, '\0',  d_size - size + nleft);
	else
		d[d_size - 1] = '\0';

	return size - nleft;
}

@arnopo
Copy link
Collaborator Author

arnopo commented Oct 14, 2024

I have updated the PR in this way

lib/utils/CMakeLists.txt Outdated Show resolved Hide resolved
lib/utils/string.c Outdated Show resolved Hide resolved
@arnopo arnopo changed the title implement internal strlcpy to replace the strncpy implement internal safe_strcpy to replace the strncpy Oct 15, 2024
@arnopo arnopo force-pushed the strcpy branch 2 times, most recently from b293552 to 58e344f Compare October 15, 2024 16:39
lib/utils/utilities.c Outdated Show resolved Hide resolved
Copy link
Contributor

@edmooring edmooring left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aside from the above question about the documentation, this looks good to go.l

lib/include/internal/utilities.h Outdated Show resolved Hide resolved
@arnopo arnopo linked an issue Oct 17, 2024 that may be closed by this pull request
@arnopo arnopo requested a review from tnmysh October 17, 2024 14:00
@arnopo arnopo added this to the Release V2024.10 milestone Oct 17, 2024
The strlcpy() function has only recently become available in glibc.
While this function prevents destination buffer overflow, it seems
that it cannot guarantee read access only within the source buffer.
this is for instance the case if the source string is not terminated by
a'\0' character.
Implement a safe_strcpy to ensure that no access is done out of the
source and destination buffer ranges.

Signed-off-by: Arnaud Pouliquen <[email protected]>
The strncpy function does not ensure that the destination string is
null-terminated. To address this issue, replace strncpy with the
internal safe_strcpy() function, which guarantees null-termination of the
destination string but also access only in buffer memory ranges.

Note: (void)safe_strcpy(...) indicates that the return value is
intentionally ignored.

Signed-off-by: Arnaud Pouliquen <[email protected]>
The strncpy function does not ensure that the destination string is
null-terminated. To address this issue, replace strncpy with the
internal safe_strcpy() function, which guarantees null-termination of the
destination string but also access only in buffer memory ranges.

Note: (void)safe_strcpy(...) indicates that the return value is
intentionally ignored.

Signed-off-by: Arnaud Pouliquen <[email protected]>
@arnopo arnopo merged commit c3132d0 into OpenAMP:main Oct 18, 2024
3 checks passed
@arnopo arnopo deleted the strcpy branch October 21, 2024 15:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Unsafe use of strncpy() throughout OpenAMP
7 participants