diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/lib/libc/port/print/asprintf.c | 10 | ||||
-rw-r--r-- | usr/src/pkg/manifests/system-test-libctest.p5m | 2 | ||||
-rw-r--r-- | usr/src/test/libc-tests/runfiles/default.run | 2 | ||||
-rw-r--r-- | usr/src/test/libc-tests/tests/Makefile | 4 | ||||
-rw-r--r-- | usr/src/test/libc-tests/tests/asprintf-14933.c | 97 |
5 files changed, 113 insertions, 2 deletions
diff --git a/usr/src/lib/libc/port/print/asprintf.c b/usr/src/lib/libc/port/print/asprintf.c index a66d1dee2f..0303369d9b 100644 --- a/usr/src/lib/libc/port/print/asprintf.c +++ b/usr/src/lib/libc/port/print/asprintf.c @@ -5,6 +5,7 @@ /* * Copyright (c) 2004 Darren Tucker. + * Copyright 2022 Oxide Computer Company * * Based originally on asprintf.c from OpenBSD: * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com> @@ -32,7 +33,6 @@ #define INIT_SZ 128 -/* VARARGS2 */ int vasprintf(char **str, const char *format, va_list ap) { @@ -49,7 +49,13 @@ vasprintf(char **str, const char *format, va_list ap) len = ret + 1; if ((newstr = malloc(len)) == NULL) return (-1); /* retain errno from malloc() */ - (void) strlcpy(newstr, string, len); + /* + * Prior versions of this used strlcpy. This has two problems. + * One, it doesn't handle embedded '\0' characters. Secondly, + * it's recalculating the length we already know. Please do not + * use a string-based copying function. + */ + (void) memcpy(newstr, string, len); *str = newstr; return (ret); } diff --git a/usr/src/pkg/manifests/system-test-libctest.p5m b/usr/src/pkg/manifests/system-test-libctest.p5m index 197013accc..92514e39fc 100644 --- a/usr/src/pkg/manifests/system-test-libctest.p5m +++ b/usr/src/pkg/manifests/system-test-libctest.p5m @@ -64,6 +64,8 @@ file path=opt/libc-tests/runfiles/default.run mode=0444 dir path=opt/libc-tests/tests file path=opt/libc-tests/tests/aligned_alloc.32 mode=0555 file path=opt/libc-tests/tests/aligned_alloc.64 mode=0555 +file path=opt/libc-tests/tests/asprintf-14933.32 mode=0555 +file path=opt/libc-tests/tests/asprintf-14933.64 mode=0555 file path=opt/libc-tests/tests/c11_threads.32 mode=0555 file path=opt/libc-tests/tests/c11_threads.64 mode=0555 file path=opt/libc-tests/tests/c11_tss.32 mode=0555 diff --git a/usr/src/test/libc-tests/runfiles/default.run b/usr/src/test/libc-tests/runfiles/default.run index f3139ced56..d2057a2152 100644 --- a/usr/src/test/libc-tests/runfiles/default.run +++ b/usr/src/test/libc-tests/runfiles/default.run @@ -95,6 +95,8 @@ timeout = 600 [/opt/libc-tests/tests/aligned_alloc.32] [/opt/libc-tests/tests/aligned_alloc.64] +[/opt/libc-tests/tests/asprintf-14933.32] +[/opt/libc-tests/tests/asprintf-14933.64] [/opt/libc-tests/tests/c11_threads.32] [/opt/libc-tests/tests/c11_threads.64] [/opt/libc-tests/tests/c11_tss.32] diff --git a/usr/src/test/libc-tests/tests/Makefile b/usr/src/test/libc-tests/tests/Makefile index d818722d41..16e4236a9f 100644 --- a/usr/src/test/libc-tests/tests/Makefile +++ b/usr/src/test/libc-tests/tests/Makefile @@ -36,6 +36,7 @@ SUBDIRS = \ PROGS = \ aligned_alloc \ + asprintf-14933 \ c11_threads \ c11_tss \ call_once \ @@ -74,6 +75,9 @@ aligned_alloc.64 := LDLIBS64 += -lproc posix_memalign.32 := LDLIBS += -lproc posix_memalign.64 := LDLIBS64 += -lproc +asprintf-14933.32 := CSTD=$(GNU_C99) +asprintf-14933.64 := CSTD=$(GNU_C99) + memset_s.32 := CPPFLAGS += -D__STDC_WANT_LIB_EXT1__=1 memset_s.64 := CPPFLAGS += -D__STDC_WANT_LIB_EXT1__=1 set_constraint_handler_s.32 := CPPFLAGS += -D__STDC_WANT_LIB_EXT1__=1 diff --git a/usr/src/test/libc-tests/tests/asprintf-14933.c b/usr/src/test/libc-tests/tests/asprintf-14933.c new file mode 100644 index 0000000000..e63c0436d1 --- /dev/null +++ b/usr/src/test/libc-tests/tests/asprintf-14933.c @@ -0,0 +1,97 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2022 Oxide Computer Company + */ + +/* + * This is a regression test for illumos#14933 where asprintf() in small buffers + * was thrown off by an embedded NUL. Test both short and large buffers with + * embedded NULs. "large" at the time 14933 was anything that exceeded 128 + * bytes. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> +#include <sys/sysmacros.h> + +const char *longstr = "0123456789abcdefghijklmnopqrstuvwxyz"; + +int +main(void) +{ + int eval = EXIT_SUCCESS; + char short_exp[] = { '0', '1', '2', '3', '\0', 'a', 'b', 'c', '\0' }; + size_t short_len = ARRAY_SIZE(short_exp); + size_t long_len; + char *out; + int ret; + + ret = asprintf(&out, "%s%c%s", "0123", '\0', "abc"); + if (ret != short_len - 1) { + (void) fprintf(stderr, "TEST FAILED: short asprintf returned " + "wrong length: found %u, expected %u\n", ret, + short_len - 1); + eval = EXIT_FAILURE; + } else { + (void) printf("TEST PASSED: short buffer embedded nul has " + "correct length\n"); + } + + if (memcmp(short_exp, out, short_len) != 0) { + (void) fprintf(stderr, "TEST FAILED: short example returned " + "wrong value\nexpected:"); + for (size_t i = 0; i < short_len; i++) { + (void) fprintf(stderr, " 0x%02x", short_exp[i]); + } + (void) fprintf(stderr, "\nactual: "); + for (size_t i = 0; i < short_len; i++) { + (void) fprintf(stderr, " 0x%02x", out[i]); + } + (void) fputc('\n', stderr); + eval = EXIT_FAILURE; + } else { + (void) printf("TEST PASSED: short buffer data contents " + "match\n"); + } + + free(out); + long_len = strlen(longstr) * 5 + 5; + ret = asprintf(&out, "%s%c%s%c%s%c%s%c%s", longstr, '\0', longstr, '\0', + longstr, '\0', longstr, '\0', longstr); + if (ret != long_len - 1) { + (void) fprintf(stderr, "TEST FAILED: long asprintf returned " + "wrong length: found %u, expected %u\n", ret, long_len - 1); + eval = EXIT_FAILURE; + } else { + (void) printf("TEST PASSED: long buffer embedded nul has " + "correct length\n"); + } + + bool large_pass = true; + for (uint_t i = 0; i < 5; i++) { + size_t offset = (strlen(longstr) + 1) * i; + if (strcmp(longstr, out + offset) != 0) { + (void) fprintf(stderr, "TEST FAILED: long asprintf " + "data buffer mismatch at copy %u\n", i); + eval = EXIT_FAILURE; + large_pass = false; + } + } + if (large_pass) { + (void) printf("TEST PASSED: long buffer data contents match\n"); + } + + return (eval); +} |