1 | /* Copyright (C) 2017-2022 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. |
3 | |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2.1 of the License, or (at your option) any later version. |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, see |
16 | <https://www.gnu.org/licenses/>. */ |
17 | |
18 | /* Verify that tunables correctly filter out unsafe tunables like |
19 | glibc.malloc.check and glibc.malloc.mmap_threshold but also retain |
20 | glibc.malloc.mmap_threshold in an unprivileged child. */ |
21 | |
22 | /* This is compiled as part of the testsuite but needs to see |
23 | HAVE_TUNABLES. */ |
24 | #define _LIBC 1 |
25 | #include "config.h" |
26 | #undef _LIBC |
27 | |
28 | #include <errno.h> |
29 | #include <fcntl.h> |
30 | #include <stdlib.h> |
31 | #include <stdint.h> |
32 | #include <stdio.h> |
33 | #include <string.h> |
34 | #include <sys/stat.h> |
35 | #include <sys/wait.h> |
36 | #include <unistd.h> |
37 | #include <intprops.h> |
38 | #include <array_length.h> |
39 | |
40 | #include <support/check.h> |
41 | #include <support/support.h> |
42 | #include <support/test-driver.h> |
43 | #include <support/capture_subprocess.h> |
44 | |
45 | const char *teststrings[] = |
46 | { |
47 | "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096" , |
48 | "glibc.malloc.check=2:glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096" , |
49 | "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096:glibc.malloc.check=2" , |
50 | "glibc.malloc.perturb=0x800" , |
51 | "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096" , |
52 | "glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096" , |
53 | "glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096" , |
54 | "not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096" , |
55 | "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096" , |
56 | "glibc.malloc.check=2" , |
57 | "glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2" , |
58 | "glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096" , |
59 | ":glibc.malloc.garbage=2:glibc.malloc.check=1" , |
60 | "glibc.malloc.check=1:glibc.malloc.check=2" , |
61 | "not_valid.malloc.check=2" , |
62 | "glibc.not_valid.check=2" , |
63 | }; |
64 | |
65 | const char *resultstrings[] = |
66 | { |
67 | "glibc.malloc.mmap_threshold=4096" , |
68 | "glibc.malloc.mmap_threshold=4096" , |
69 | "glibc.malloc.mmap_threshold=4096" , |
70 | "glibc.malloc.perturb=0x800" , |
71 | "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096" , |
72 | "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096" , |
73 | "glibc.malloc.mmap_threshold=4096" , |
74 | "glibc.malloc.mmap_threshold=4096" , |
75 | "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096" , |
76 | "" , |
77 | "" , |
78 | "" , |
79 | "" , |
80 | "" , |
81 | "" , |
82 | "" , |
83 | }; |
84 | |
85 | static int |
86 | test_child (int off) |
87 | { |
88 | const char *val = getenv (name: "GLIBC_TUNABLES" ); |
89 | |
90 | #if HAVE_TUNABLES |
91 | printf (format: " [%d] GLIBC_TUNABLES is %s\n" , off, val); |
92 | fflush (stdout); |
93 | if (val != NULL && strcmp (s1: val, s2: resultstrings[off]) == 0) |
94 | return 0; |
95 | |
96 | if (val != NULL) |
97 | printf (format: " [%d] Unexpected GLIBC_TUNABLES VALUE %s, expected %s\n" , |
98 | off, val, resultstrings[off]); |
99 | else |
100 | printf (format: " [%d] GLIBC_TUNABLES environment variable absent\n" , off); |
101 | |
102 | fflush (stdout); |
103 | |
104 | return 1; |
105 | #else |
106 | if (val != NULL) |
107 | { |
108 | printf ("[%d] GLIBC_TUNABLES not cleared\n" , off); |
109 | return 1; |
110 | } |
111 | return 0; |
112 | #endif |
113 | } |
114 | |
115 | static int |
116 | do_test (int argc, char **argv) |
117 | { |
118 | /* Setgid child process. */ |
119 | if (argc == 2) |
120 | { |
121 | if (getgid () == getegid ()) |
122 | /* This can happen if the file system is mounted nosuid. */ |
123 | FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n" , |
124 | (intmax_t) getgid ()); |
125 | |
126 | int ret = test_child (off: atoi (nptr: argv[1])); |
127 | |
128 | if (ret != 0) |
129 | exit (status: 1); |
130 | |
131 | /* Special return code to make sure that the child executed all the way |
132 | through. */ |
133 | exit (status: 42); |
134 | } |
135 | else |
136 | { |
137 | /* Spawn tests. */ |
138 | for (int i = 0; i < array_length (teststrings); i++) |
139 | { |
140 | char buf[INT_BUFSIZE_BOUND (int)]; |
141 | |
142 | printf (format: "[%d] Spawned test for %s\n" , i, teststrings[i]); |
143 | snprintf (s: buf, maxlen: sizeof (buf), format: "%d\n" , i); |
144 | fflush (stdout); |
145 | if (setenv (name: "GLIBC_TUNABLES" , value: teststrings[i], replace: 1) != 0) |
146 | { |
147 | printf (format: " [%d] Failed to set GLIBC_TUNABLES: %m" , i); |
148 | support_record_failure (); |
149 | continue; |
150 | } |
151 | |
152 | int status = support_capture_subprogram_self_sgid (child_id: buf); |
153 | |
154 | /* Bail out early if unsupported. */ |
155 | if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) |
156 | return EXIT_UNSUPPORTED; |
157 | |
158 | if (WEXITSTATUS (status) != 42) |
159 | { |
160 | printf (format: " [%d] child failed with status %d\n" , i, |
161 | WEXITSTATUS (status)); |
162 | support_record_failure (); |
163 | } |
164 | } |
165 | return 0; |
166 | } |
167 | } |
168 | |
169 | #define TEST_FUNCTION_ARGV do_test |
170 | #include <support/test-driver.c> |
171 | |