summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/lib/libc/port/print/asprintf.c10
-rw-r--r--usr/src/pkg/manifests/system-test-libctest.p5m2
-rw-r--r--usr/src/test/libc-tests/runfiles/default.run2
-rw-r--r--usr/src/test/libc-tests/tests/Makefile4
-rw-r--r--usr/src/test/libc-tests/tests/asprintf-14933.c97
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);
+}