1 | /* Check for GLOB_TIDLE heap allocation issues (bugs 22320, 22325, 22332). |
2 | Copyright (C) 2017-2022 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 <glob.h> |
20 | #include <mcheck.h> |
21 | #include <nss.h> |
22 | #include <pwd.h> |
23 | #include <stdlib.h> |
24 | #include <string.h> |
25 | #include <support/check.h> |
26 | #include <support/support.h> |
27 | |
28 | /* Flag which indicates whether to pass the GLOB_ONLYDIR flag. */ |
29 | static int do_onlydir; |
30 | |
31 | /* Flag which indicates whether to pass the GLOB_NOCHECK flag. */ |
32 | static int do_nocheck; |
33 | |
34 | /* Flag which indicates whether to pass the GLOB_MARK flag. */ |
35 | static int do_mark; |
36 | |
37 | /* Flag which indicates whether to pass the GLOB_NOESCAPE flag. */ |
38 | static int do_noescape; |
39 | |
40 | static void |
41 | one_test (const char *prefix, const char *middle, const char *suffix) |
42 | { |
43 | char *pattern = xasprintf (format: "%s%s%s" , prefix, middle, suffix); |
44 | int flags = GLOB_TILDE; |
45 | if (do_onlydir) |
46 | flags |= GLOB_ONLYDIR; |
47 | if (do_nocheck) |
48 | flags |= GLOB_NOCHECK; |
49 | if (do_mark) |
50 | flags |= GLOB_MARK; |
51 | if (do_noescape) |
52 | flags |= GLOB_NOESCAPE; |
53 | glob_t gl; |
54 | /* This glob call might result in crashes or memory leaks. */ |
55 | if (glob (pattern, flags, NULL, &gl) == 0) |
56 | globfree (&gl); |
57 | free (ptr: pattern); |
58 | } |
59 | |
60 | enum |
61 | { |
62 | /* The largest base being tested. */ |
63 | largest_base_size = 500000, |
64 | |
65 | /* The actual size is the base size plus a variable whose absolute |
66 | value is not greater than this. This helps malloc to trigger |
67 | overflows. */ |
68 | max_size_skew = 16, |
69 | |
70 | /* The maximum string length supported by repeating_string |
71 | below. */ |
72 | repeat_size = largest_base_size + max_size_skew, |
73 | }; |
74 | |
75 | /* Used to construct strings which repeat a single character 'x'. */ |
76 | static char *repeat; |
77 | |
78 | /* Return a string of SIZE characters. */ |
79 | const char * |
80 | repeating_string (int size) |
81 | { |
82 | TEST_VERIFY (size >= 0); |
83 | TEST_VERIFY (size <= repeat_size); |
84 | const char *repeated_shifted = repeat + repeat_size - size; |
85 | TEST_VERIFY (strlen (repeated_shifted) == size); |
86 | return repeated_shifted; |
87 | } |
88 | |
89 | static int |
90 | do_test (void) |
91 | { |
92 | /* Avoid network-based NSS modules and initialize nss_files with a |
93 | dummy lookup. This has to come before mtrace because NSS does |
94 | not free all memory. */ |
95 | __nss_configure_lookup (dbname: "passwd" , string: "files" ); |
96 | (void) getpwnam (name: "root" ); |
97 | |
98 | mtrace (); |
99 | |
100 | repeat = xmalloc (n: repeat_size + 1); |
101 | memset (repeat, 'x', repeat_size); |
102 | repeat[repeat_size] = '\0'; |
103 | |
104 | /* These numbers control the size of the user name. The values |
105 | cover the minimum (0), a typical size (8), a large |
106 | stack-allocated size (100000), and a somewhat large |
107 | heap-allocated size (largest_base_size). */ |
108 | static const int base_sizes[] = { 0, 8, 100, 100000, largest_base_size, -1 }; |
109 | |
110 | for (do_onlydir = 0; do_onlydir < 2; ++do_onlydir) |
111 | for (do_nocheck = 0; do_nocheck < 2; ++do_nocheck) |
112 | for (do_mark = 0; do_mark < 2; ++do_mark) |
113 | for (do_noescape = 0; do_noescape < 2; ++do_noescape) |
114 | for (int base_idx = 0; base_sizes[base_idx] >= 0; ++base_idx) |
115 | { |
116 | for (int size_skew = -max_size_skew; size_skew <= max_size_skew; |
117 | ++size_skew) |
118 | { |
119 | int size = base_sizes[base_idx] + size_skew; |
120 | if (size < 0) |
121 | continue; |
122 | |
123 | const char *user_name = repeating_string (size); |
124 | one_test (prefix: "~" , middle: user_name, suffix: "/a/b" ); |
125 | one_test (prefix: "~" , middle: user_name, suffix: "x\\x\\x////x\\a" ); |
126 | } |
127 | |
128 | const char *user_name = repeating_string (size: base_sizes[base_idx]); |
129 | one_test (prefix: "~" , middle: user_name, suffix: "" ); |
130 | one_test (prefix: "~" , middle: user_name, suffix: "/" ); |
131 | one_test (prefix: "~" , middle: user_name, suffix: "/a" ); |
132 | one_test (prefix: "~" , middle: user_name, suffix: "/*/*" ); |
133 | one_test (prefix: "~" , middle: user_name, suffix: "\\/" ); |
134 | one_test (prefix: "/~" , middle: user_name, suffix: "" ); |
135 | one_test (prefix: "*/~" , middle: user_name, suffix: "/a/b" ); |
136 | } |
137 | |
138 | free (ptr: repeat); |
139 | |
140 | return 0; |
141 | } |
142 | |
143 | #define TIMEOUT 200 |
144 | #include <support/test-driver.c> |
145 | |