1 | /* Check the usability of <dlfcn.h> functions in audit modules. Audit module. |
2 | Copyright (C) 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 <dlfcn.h> |
20 | #include <first-versions.h> |
21 | #include <gnu/lib-names.h> |
22 | #include <link.h> |
23 | #include <stdio.h> |
24 | #include <string.h> |
25 | #include <unistd.h> |
26 | |
27 | #include <support/check.h> |
28 | #include <support/xdlfcn.h> |
29 | |
30 | unsigned int |
31 | la_version (unsigned int current) |
32 | { |
33 | /* Exercise various <dlfcn.h> functions. */ |
34 | |
35 | /* Check dlopen, dlsym, dlclose. */ |
36 | void *handle = xdlopen (LIBM_SO, RTLD_LOCAL | RTLD_NOW); |
37 | void *ptr = xdlsym (handle, symbol: "sincos" ); |
38 | TEST_VERIFY (ptr != NULL); |
39 | ptr = dlsym (handle: handle, name: "SINCOS" ); |
40 | TEST_VERIFY (ptr == NULL); |
41 | const char *message = dlerror (); |
42 | TEST_VERIFY (strstr (message, ": undefined symbol: SINCOS" ) != NULL); |
43 | ptr = dlsym (handle: handle, name: "SINCOS" ); |
44 | TEST_VERIFY (ptr == NULL); |
45 | xdlclose (handle); |
46 | TEST_COMPARE_STRING (dlerror (), NULL); |
47 | |
48 | handle = xdlopen (LIBC_SO, RTLD_LOCAL | RTLD_NOW | RTLD_NOLOAD); |
49 | |
50 | /* Check dlvsym. _exit is unlikely to gain another symbol |
51 | version. */ |
52 | TEST_VERIFY (xdlsym (handle, "_exit" ) |
53 | == xdlvsym (handle, "_exit" , FIRST_VERSION_libc__exit_STRING)); |
54 | |
55 | /* Check dlinfo. */ |
56 | { |
57 | void *handle2 = NULL; |
58 | TEST_COMPARE (dlinfo (handle, RTLD_DI_LINKMAP, &handle2), 0); |
59 | TEST_VERIFY (handle2 == handle); |
60 | } |
61 | |
62 | /* Check dladdr and dladdr1. */ |
63 | Dl_info info = { }; |
64 | TEST_VERIFY (dladdr (&_exit, &info) != 0); |
65 | if (strcmp (s1: info.dli_sname, s2: "_Exit" ) != 0) /* _Exit is an alias. */ |
66 | TEST_COMPARE_STRING (info.dli_sname, "_exit" ); |
67 | TEST_VERIFY (info.dli_saddr == &_exit); |
68 | TEST_VERIFY (strstr (info.dli_fname, LIBC_SO)); |
69 | void *; |
70 | memset (s: &info, c: 0, n: sizeof (info)); |
71 | TEST_VERIFY (dladdr1 (&_exit, &info, &extra_info, RTLD_DL_LINKMAP) != 0); |
72 | TEST_VERIFY (extra_info == handle); |
73 | |
74 | /* Check _dl_find_object. */ |
75 | struct dl_find_object dlfo; |
76 | TEST_COMPARE (_dl_find_object (__builtin_return_address (0), &dlfo), 0); |
77 | /* "ld.so" is seen with --enable-hardcoded-path-in-tests. */ |
78 | if (strcmp (s1: basename (filename: dlfo.dlfo_link_map->l_name), s2: "ld.so" ) != 0) |
79 | TEST_COMPARE_STRING (basename (dlfo.dlfo_link_map->l_name), LD_SO); |
80 | TEST_COMPARE (_dl_find_object (dlsym (handle, "environ" ), &dlfo), 0); |
81 | TEST_COMPARE_STRING (basename (dlfo.dlfo_link_map->l_name), LIBC_SO); |
82 | TEST_COMPARE (_dl_find_object ((void *) 1, &dlfo), -1); |
83 | TEST_COMPARE (_dl_find_object ((void *) -1, &dlfo), -1); |
84 | |
85 | /* Verify that dlmopen creates a new namespace. */ |
86 | void *dlmopen_handle = xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW); |
87 | TEST_VERIFY (dlmopen_handle != handle); |
88 | memset (s: &info, c: 0, n: sizeof (info)); |
89 | extra_info = NULL; |
90 | ptr = xdlsym (handle: dlmopen_handle, symbol: "_exit" ); |
91 | TEST_VERIFY (dladdr1 (ptr, &info, &extra_info, RTLD_DL_LINKMAP) != 0); |
92 | TEST_VERIFY (extra_info == dlmopen_handle); |
93 | xdlclose (handle: dlmopen_handle); |
94 | |
95 | /* Terminate the process with an error state. This does not happen |
96 | automatically because the audit module state is not shared with |
97 | the main program. */ |
98 | if (support_record_failure_is_failed ()) |
99 | { |
100 | fflush (stdout); |
101 | fflush (stderr); |
102 | _exit (status: 1); |
103 | } |
104 | |
105 | return LAV_CURRENT; |
106 | } |
107 | |
108 | char * |
109 | la_objsearch (const char *name, uintptr_t *cookie, unsigned int flag) |
110 | { |
111 | if (strcmp (s1: name, s2: "mapped to libc" ) == 0) |
112 | return (char *) LIBC_SO; |
113 | else |
114 | return (char *) name; |
115 | } |
116 | |