1 /* Print diagnostics data in ld.so.
2    Copyright (C) 2021-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 <gnu/lib-names.h>
20 #include <stdbool.h>
21 #include <stddef.h>
22 #include <unistd.h>
23 
24 #include <dl-diagnostics.h>
25 #include <dl-hwcaps.h>
26 #include <dl-main.h>
27 #include <dl-procinfo.h>
28 #include <dl-sysdep.h>
29 #include <ldsodefs.h>
30 #include "trusted-dirs.h"
31 #include "version.h"
32 
33 /* Write CH to standard output.  */
34 static void
_dl_putc(char ch)35 _dl_putc (char ch)
36 {
37   _dl_write (STDOUT_FILENO, &ch, 1);
38 }
39 
40 /* Print CH to standard output, quoting it if necessary.  */
41 static void
print_quoted_char(char ch)42 print_quoted_char (char ch)
43 {
44   if (ch < ' ' || ch > '~')
45     {
46       char buf[4];
47       buf[0] = '\\';
48       buf[1] = '0' + ((ch >> 6) & 7);
49       buf[2] = '0' + ((ch >> 6) & 7);
50       buf[3] = '0' + (ch & 7);
51       _dl_write (STDOUT_FILENO, buf, 4);
52     }
53   else
54     {
55       if (ch == '\\' || ch == '"')
56         _dl_putc ('\\');
57       _dl_putc (ch);
58     }
59 }
60 
61 /* Print S of LEN bytes to standard output, quoting characters as
62    needed.  */
63 static void
print_string_length(const char * s,size_t len)64 print_string_length (const char *s, size_t len)
65 {
66   _dl_putc ('"');
67   for (size_t i = 0; i < len; ++i)
68     print_quoted_char (s[i]);
69   _dl_putc ('"');
70 }
71 
72 void
_dl_diagnostics_print_string(const char * s)73 _dl_diagnostics_print_string (const char *s)
74 {
75   if (s == NULL)
76     {
77       _dl_printf ("0x0");
78       return;
79     }
80 
81   _dl_putc ('"');
82   while (*s != '\0')
83     {
84       print_quoted_char (*s);
85       ++s;
86     }
87   _dl_putc ('"');
88 }
89 
90 void
_dl_diagnostics_print_labeled_string(const char * label,const char * s)91 _dl_diagnostics_print_labeled_string (const char *label, const char *s)
92 {
93   _dl_printf ("%s=", label);
94   _dl_diagnostics_print_string (s);
95   _dl_putc ('\n');
96 }
97 
98 void
_dl_diagnostics_print_labeled_value(const char * label,uint64_t value)99 _dl_diagnostics_print_labeled_value (const char *label, uint64_t value)
100 {
101   if (sizeof (value) == sizeof (unsigned long int))
102     /* _dl_printf can print 64-bit values directly.  */
103     _dl_printf ("%s=0x%lx\n", label, (unsigned long int) value);
104   else
105     {
106       uint32_t high = value >> 32;
107       uint32_t low = value;
108       if (high == 0)
109         _dl_printf ("%s=0x%x\n", label, low);
110       else
111         _dl_printf ("%s=0x%x%08x\n", label, high, low);
112     }
113 }
114 
115 /* Return true if ENV is an unfiltered environment variable.  */
116 static bool
unfiltered_envvar(const char * env,size_t * name_length)117 unfiltered_envvar (const char *env, size_t *name_length)
118 {
119   char *env_equal = strchr (env, '=');
120   if (env_equal == NULL)
121     {
122       /* Always dump malformed entries.  */
123       *name_length = strlen (env);
124       return true;
125     }
126   size_t envname_length = env_equal - env;
127   *name_length = envname_length;
128 
129   /* LC_ and LD_ variables.  */
130   if (env[0] == 'L' && (env[1] == 'C' || env[1] == 'D')
131       && env[2] == '_')
132     return true;
133 
134   /* MALLOC_ variables.  */
135   if (strncmp (env, "MALLOC_", strlen ("MALLOC_")) == 0)
136     return true;
137 
138   static const char unfiltered[] =
139     "DATEMSK\0"
140     "GCONV_PATH\0"
141     "GETCONF_DIR\0"
142     "GETCONF_DIR\0"
143     "GLIBC_TUNABLES\0"
144     "GMON_OUTPUT_PREFIX\0"
145     "HESIOD_CONFIG\0"
146     "HES_DOMAIN\0"
147     "HOSTALIASES\0"
148     "I18NPATH\0"
149     "IFS\0"
150     "LANG\0"
151     "LOCALDOMAIN\0"
152     "LOCPATH\0"
153     "MSGVERB\0"
154     "NIS_DEFAULTS\0"
155     "NIS_GROUP\0"
156     "NIS_PATH\0"
157     "NLSPATH\0"
158     "PATH\0"
159     "POSIXLY_CORRECT\0"
160     "RESOLV_HOST_CONF\0"
161     "RES_OPTIONS\0"
162     "SEV_LEVEL\0"
163     "TMPDIR\0"
164     "TZ\0"
165     "TZDIR\0"
166     /* Two null bytes at the end to mark the end of the list via an
167        empty substring.  */
168     ;
169   for (const char *candidate = unfiltered; *candidate != '\0'; )
170     {
171       size_t candidate_length = strlen (candidate);
172       if (candidate_length == envname_length
173           && memcmp (candidate, env, candidate_length) == 0)
174         return true;
175       candidate += candidate_length + 1;
176     }
177 
178   return false;
179 }
180 
181 /* Dump the process environment.  */
182 static void
print_environ(char ** environ)183 print_environ (char **environ)
184 {
185   unsigned int index = 0;
186   for (char **envp = environ; *envp != NULL; ++envp)
187     {
188       char *env = *envp;
189       size_t name_length;
190       bool unfiltered = unfiltered_envvar (env, &name_length);
191       _dl_printf ("env%s[0x%x]=",
192                   unfiltered ? "" : "_filtered", index);
193       if (unfiltered)
194         _dl_diagnostics_print_string (env);
195       else
196         print_string_length (env, name_length);
197       _dl_putc ('\n');
198       ++index;
199     }
200 }
201 
202 /* Print configured paths and the built-in search path.  */
203 static void
print_paths(void)204 print_paths (void)
205 {
206   _dl_diagnostics_print_labeled_string ("path.prefix", PREFIX);
207   _dl_diagnostics_print_labeled_string ("path.rtld", RTLD);
208   _dl_diagnostics_print_labeled_string ("path.sysconfdir", SYSCONFDIR);
209 
210   unsigned int index = 0;
211   static const char *system_dirs = SYSTEM_DIRS "\0";
212   for (const char *e = system_dirs; *e != '\0'; )
213     {
214       size_t len = strlen (e);
215       _dl_printf ("path.system_dirs[0x%x]=", index);
216       print_string_length (e, len);
217       _dl_putc ('\n');
218       ++index;
219       e += len + 1;
220     }
221 }
222 
223 /* Print information about the glibc version.  */
224 static void
print_version(void)225 print_version (void)
226 {
227   _dl_diagnostics_print_labeled_string ("version.release", RELEASE);
228   _dl_diagnostics_print_labeled_string ("version.version", VERSION);
229 }
230 
231 void
_dl_print_diagnostics(char ** environ)232 _dl_print_diagnostics (char **environ)
233 {
234   _dl_diagnostics_print_labeled_string ("dl_dst_lib", DL_DST_LIB);
235   _dl_diagnostics_print_labeled_value ("dl_hwcap", GLRO (dl_hwcap));
236   _dl_diagnostics_print_labeled_value ("dl_hwcap_important", HWCAP_IMPORTANT);
237   _dl_diagnostics_print_labeled_value ("dl_hwcap2", GLRO (dl_hwcap2));
238   _dl_diagnostics_print_labeled_string
239     ("dl_hwcaps_subdirs", _dl_hwcaps_subdirs);
240   _dl_diagnostics_print_labeled_value
241     ("dl_hwcaps_subdirs_active", _dl_hwcaps_subdirs_active ());
242   _dl_diagnostics_print_labeled_value ("dl_pagesize", GLRO (dl_pagesize));
243   _dl_diagnostics_print_labeled_string ("dl_platform", GLRO (dl_platform));
244   _dl_diagnostics_print_labeled_string
245     ("dl_profile_output", GLRO (dl_profile_output));
246   _dl_diagnostics_print_labeled_value
247     ("dl_string_platform", _dl_string_platform ( GLRO (dl_platform)));
248 
249   _dl_diagnostics_print_labeled_string ("dso.ld", LD_SO);
250   _dl_diagnostics_print_labeled_string ("dso.libc", LIBC_SO);
251 
252   print_environ (environ);
253   print_paths ();
254   print_version ();
255 
256   _dl_diagnostics_kernel ();
257   _dl_diagnostics_cpu ();
258 
259   _exit (EXIT_SUCCESS);
260 }
261