1 | /* Tests for fortified sprintf with unknown buffer bounds (bug 30039). |
2 | Copyright (C) 2023-2024 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <printf.h> |
20 | #include <stdarg.h> |
21 | #include <stdio.h> |
22 | #include <string.h> |
23 | #include <support/check.h> |
24 | |
25 | /* This test is not built with _FORTIFY_SOURCE. Instead it calls the |
26 | appropriate implementation directly. The fortify mode is specified |
27 | in this variable. */ |
28 | static int fortify_mode; |
29 | |
30 | /* This does not handle long-double redirects etc., but we test only |
31 | format strings that stay within the confines of the base |
32 | implementation. */ |
33 | int __vsprintf_chk (char *s, int flag, size_t slen, const char *format, |
34 | va_list ap); |
35 | |
36 | /* Invoke vsprintf or __vsprintf_chk according to fortify_mode. */ |
37 | static int |
38 | my_vsprintf (char *buf, const char *format, va_list ap) |
39 | { |
40 | int result; |
41 | if (fortify_mode == 0) |
42 | result = vsprintf (s: buf, format: format, arg: ap); |
43 | else |
44 | /* Call the fortified version with an unspecified length. */ |
45 | result = __vsprintf_chk (s: buf, flag: fortify_mode - 1, slen: -1, format, ap); |
46 | return result; |
47 | } |
48 | |
49 | /* Run one test, with the specified expected output. */ |
50 | static void __attribute ((format (printf, 2, 3))) |
51 | do_check (const char *expected, const char *format, ...) |
52 | { |
53 | va_list ap; |
54 | va_start (ap, format); |
55 | |
56 | char buf_expected[24]; |
57 | memset (buf_expected, '@', sizeof (buf_expected)); |
58 | TEST_VERIFY (strlen (expected) < sizeof (buf_expected)); |
59 | strcpy (buf_expected, expected); |
60 | |
61 | char buf[sizeof (buf_expected)]; |
62 | memset (buf, '@', sizeof (buf)); |
63 | |
64 | int ret = my_vsprintf (buf, format, ap); |
65 | TEST_COMPARE_BLOB (buf_expected, sizeof (buf_expected), buf, sizeof (buf)); |
66 | TEST_COMPARE (ret, strlen (expected)); |
67 | |
68 | va_end (ap); |
69 | } |
70 | |
71 | /* Run the tests in all fortify modes. */ |
72 | static void |
73 | do_tests (void) |
74 | { |
75 | for (fortify_mode = 0; fortify_mode <= 3; ++fortify_mode) |
76 | { |
77 | do_check (expected: "0" , format: "%d" , 0); |
78 | do_check (expected: "-2147483648" , format: "%d" , -2147483647 - 1); |
79 | do_check (expected: "-9223372036854775808" , format: "%lld" , -9223372036854775807LL - 1); |
80 | do_check (expected: "" , format: "%s" , "" ); |
81 | do_check (expected: " " , format: "%22s" , "" ); |
82 | do_check (expected: "XXXXXXXXXXXXXXXXXXXXXX" , format: "%s" , "XXXXXXXXXXXXXXXXXXXXXX" ); |
83 | do_check (expected: "1.125000" , format: "%f" , 1.125); |
84 | do_check (expected: "1.125" , format: "%g" , 1.125); |
85 | do_check (expected: "1.125" , format: "%.8g" , 1.125); |
86 | } |
87 | } |
88 | |
89 | /* printf callback that falls back to the glibc-supplied |
90 | implementation. */ |
91 | static int |
92 | dummy_printf_function (FILE *__stream, |
93 | const struct printf_info *__info, |
94 | const void *const *__args) |
95 | { |
96 | return -2; /* Request fallback. */ |
97 | } |
98 | |
99 | /* Likewise for the type information. */ |
100 | static int |
101 | dummy_arginfo_function (const struct printf_info *info, |
102 | size_t n, int *argtypes, int *size) |
103 | { |
104 | return -1; /* Request fallback. */ |
105 | } |
106 | |
107 | static int |
108 | do_test (void) |
109 | { |
110 | do_tests (); |
111 | |
112 | /* Activate __printf_function_invoke mode. */ |
113 | register_printf_specifier (spec: 'd', func: dummy_printf_function, |
114 | arginfo: dummy_arginfo_function); |
115 | register_printf_specifier (spec: 'g', func: dummy_printf_function, |
116 | arginfo: dummy_arginfo_function); |
117 | register_printf_specifier (spec: 's', func: dummy_printf_function, |
118 | arginfo: dummy_arginfo_function); |
119 | |
120 | /* Rerun the tests with callback functions. */ |
121 | do_tests (); |
122 | |
123 | return 0; |
124 | } |
125 | |
126 | #include <support/test-driver.c> |
127 | |