1 /* Check for file descriptor leak in alias :include: processing (bug 23521).
2 Copyright (C) 2018-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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/>. */
20 #include <array_length.h>
23 #include <gnu/lib-names.h>
27 #include <support/check.h>
28 #include <support/namespace.h>
29 #include <support/support.h>
30 #include <support/temp_file.h>
31 #include <support/test-driver.h>
32 #include <support/xstdio.h>
33 #include <support/xunistd.h>
35 static struct support_chroot
*chroot_env
;
37 /* Number of the aliases for the "many" user. This must be large
38 enough to trigger reallocation for the pointer array, but result in
39 answers below the maximum size tried in do_test. */
40 enum { many_aliases
= 30 };
43 prepare (int argc
, char **argv
)
45 chroot_env
= support_chroot_create
46 ((struct support_chroot_configuration
) { } );
48 char *path
= xasprintf ("%s/etc/aliases", chroot_env
->path_chroot
);
50 support_write_file_string
52 "user1: :include:/etc/aliases.user1\n"
53 "user2: :include:/etc/aliases.user2\n"
54 "comment: comment1, :include:/etc/aliases.comment\n"
55 "many: :include:/etc/aliases.many\n");
58 path
= xasprintf ("%s/etc/aliases.user1", chroot_env
->path_chroot
);
60 support_write_file_string (path
, "alias1\n");
63 path
= xasprintf ("%s/etc/aliases.user2", chroot_env
->path_chroot
);
65 support_write_file_string (path
, "alias1a, alias2\n");
68 path
= xasprintf ("%s/etc/aliases.comment", chroot_env
->path_chroot
);
70 support_write_file_string
72 /* The line must be longer than the line with the :include:
73 directive in /etc/aliases. */
74 "# Long line. ##############################################\n"
78 path
= xasprintf ("%s/etc/aliases.many", chroot_env
->path_chroot
);
80 FILE *fp
= xfopen (path
, "w");
81 for (int i
= 0; i
< many_aliases
; ++i
)
82 fprintf (fp
, "a%d\n", i
);
83 TEST_VERIFY_EXIT (! ferror (fp
));
88 /* The names of the users to test. */
89 static const char *users
[] = { "user1", "user2", "comment", "many" };
92 check_aliases (int id
, const struct aliasent
*e
)
94 TEST_VERIFY_EXIT (id
>= 0 || id
< array_length (users
));
95 const char *name
= users
[id
];
96 TEST_COMPARE_BLOB (e
->alias_name
, strlen (e
->alias_name
),
102 TEST_COMPARE (e
->alias_members_len
, 1);
103 TEST_COMPARE_BLOB (e
->alias_members
[0], strlen (e
->alias_members
[0]),
104 "alias1", strlen ("alias1"));
108 TEST_COMPARE (e
->alias_members_len
, 2);
109 TEST_COMPARE_BLOB (e
->alias_members
[0], strlen (e
->alias_members
[0]),
110 "alias1a", strlen ("alias1a"));
111 TEST_COMPARE_BLOB (e
->alias_members
[1], strlen (e
->alias_members
[1]),
112 "alias2", strlen ("alias2"));
116 TEST_COMPARE (e
->alias_members_len
, 2);
117 TEST_COMPARE_BLOB (e
->alias_members
[0], strlen (e
->alias_members
[0]),
118 "comment1", strlen ("comment1"));
119 TEST_COMPARE_BLOB (e
->alias_members
[1], strlen (e
->alias_members
[1]),
120 "comment2", strlen ("comment2"));
124 TEST_COMPARE (e
->alias_members_len
, many_aliases
);
125 for (int i
= 0; i
< e
->alias_members_len
; ++i
)
128 int len
= snprintf (alias
, sizeof (alias
), "a%d", i
);
129 TEST_VERIFY_EXIT (len
> 0);
130 TEST_COMPARE_BLOB (e
->alias_members
[i
], strlen (e
->alias_members
[i
]),
140 /* Make sure we don't try to load the module in the chroot. */
141 if (dlopen (LIBNSS_FILES_SO
, RTLD_NOW
) == NULL
)
142 FAIL_EXIT1 ("could not load " LIBNSS_FILES_SO
": %s", dlerror ());
144 /* Some of these descriptors will become unavailable if there is a
145 file descriptor leak. 10 is chosen somewhat arbitrarily. The
146 array must be longer than the number of files opened by nss_files
147 at the same time (currently that number is 2). */
148 int next_descriptors
[10];
149 for (size_t i
= 0; i
< array_length (next_descriptors
); ++i
)
151 next_descriptors
[i
] = dup (0);
152 TEST_VERIFY_EXIT (next_descriptors
[i
] > 0);
154 for (size_t i
= 0; i
< array_length (next_descriptors
); ++i
)
155 xclose (next_descriptors
[i
]);
157 support_become_root ();
158 if (!support_can_chroot ())
159 return EXIT_UNSUPPORTED
;
161 __nss_configure_lookup ("aliases", "files");
163 xchroot (chroot_env
->path_chroot
);
165 /* Attempt various buffer sizes. If the operation succeeds, we
166 expect correct data. */
167 for (int id
= 0; id
< array_length (users
); ++id
)
170 for (size_t size
= 1; size
<= 1000; ++size
)
172 void *buffer
= malloc (size
);
173 struct aliasent result
;
174 struct aliasent
*res
;
176 int ret
= getaliasbyname_r (users
[id
], &result
, buffer
, size
, &res
);
182 check_aliases (id
, res
);
186 support_record_failure ();
187 printf ("error: failed lookup for user \"%s\", size %zu\n",
191 else if (ret
!= ERANGE
)
193 support_record_failure ();
194 printf ("error: invalid return code %d (user \"%s\", size %zu)\n",
195 ret
, users
[id
], size
);
199 /* Make sure that we did not have a file descriptor leak. */
200 for (size_t i
= 0; i
< array_length (next_descriptors
); ++i
)
202 int new_fd
= dup (0);
203 if (new_fd
!= next_descriptors
[i
])
205 support_record_failure ();
206 printf ("error: descriptor %d at index %zu leaked"
207 " (user \"%s\", size %zu)\n",
208 next_descriptors
[i
], i
, users
[id
], size
);
210 /* Close unexpected descriptor, the leak probing
211 descriptors, and the leaked descriptor
212 next_descriptors[i]. */
214 for (size_t j
= 0; j
<= i
; ++j
)
215 xclose (next_descriptors
[j
]);
219 for (size_t i
= 0; i
< array_length (next_descriptors
); ++i
)
220 xclose (next_descriptors
[i
]);
227 support_record_failure ();
228 printf ("error: user %s not found\n", users
[id
]);
232 support_chroot_free (chroot_env
);
236 #define PREPARE prepare
237 #include <support/test-driver.c>