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
45const 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
65const 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
85static int
86test_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
115static int
116do_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

source code of glibc/elf/tst-env-setuid-tunables.c