1 /* Copyright © 2013, Intel Corporation
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31 #include <sys/types.h>
37 #include <linux/limits.h>
44 /* Terminate a string representing a filename at the final '/' to
45 * eliminate the final filename component, (leaving only the directory
46 * portions of the original path).
48 * Notes: A path containing no '/' character will not be modified.
49 * A path consisting only of "/" will not be modified.
52 chop_trailing_path_component (char *path)
56 slash = strrchr (path, '/');
67 /* Find the absolute path of the currently executing binary.
69 * Returns: a string talloc'ed to 'ctx'
72 get_bin_name (void *ctx)
74 const char *link = "/proc/self/exe";
77 /* Yes, PATH_MAX is cheesy. I would have preferred to have
78 * used lstat and read the resulting st_size, but everytime I
79 * did that with /proc/self/exe I got a value of 0, (whereas
80 * with a "real" symbolic link I make myself I get the length
81 * of the filename being linked to). Go figure. */
82 int name_len = PATH_MAX + 1;
84 name = talloc_size (ctx, name_len - 1);
86 fprintf (stderr, "Out of memory.\n");
90 name_len = readlink (link, name, name_len);
92 fprintf (stderr, "Failed to readlink %s: %s\n", link,
97 name[name_len + 1] = '\0';
102 /* Does path exist? */
104 exists (const char *path)
109 err = stat (path, &st);
111 /* Failed to stat. It either doesn't exist, or might as well not. */
118 /* Given a program name, search the PATH environment variable and
119 * return the first absolute path to 'program'.
121 * Returns: A string talloc'ed to 'ctx'.
123 * Note: This function aborts the current program if 'program' cannot
124 * be located by searching PATH.
127 search_path_for_program (void *ctx, const char *program)
129 char *orig_path, *path, *colon, *dir, *candidate;
130 void *local = talloc_new (ctx);
132 /* If the program name already contains a slash, then this is
133 * an absolute (or relative) path. Either way, we don't search
134 * PATH, since we can directly open this filename. */
135 if (strchr (program, '/'))
136 return talloc_strdup (ctx, program);
138 orig_path = path = getenv ("PATH");
141 colon = strchr (path, ':');
144 dir = talloc_strndup (local, path, colon - path);
148 path = path + strlen (path);
151 candidate = talloc_asprintf(local, "%s/%s", dir, program);
153 if (exists (candidate)) {
154 talloc_steal (ctx, candidate);
158 talloc_free (candidate);
162 fprintf (stderr, "Cannot find program %s (looked in %s)\n",
167 /* Is the given elf program 32 or 64 bit?
169 * Note: This function aborts the current program if 'program' cannot
170 * be opened as a valid ELF file. */
172 elf_bits (const char *program)
177 void *local = talloc_new (NULL);
178 char *absolute_program = search_path_for_program (local, program);
180 fd = open (absolute_program, O_RDONLY, 0);
182 fprintf (stderr, "Failed to open %s: %s\n", absolute_program,
187 if (elf_version (EV_CURRENT ) == EV_NONE) {
188 fprintf (stderr, "Failed to initialize elf library: %s\n",
193 elf = elf_begin (fd, ELF_C_READ, NULL);
195 fprintf (stderr, "Call to elf_begin on %s failed: %s\n",
196 absolute_program, elf_errmsg(-1));
200 if (elf_kind (elf) != ELF_K_ELF) {
201 fprintf (stderr, "Not an ELF object: %s\n", absolute_program);
205 if (gelf_getehdr (elf, &ehdr) == NULL) {
206 fprintf (stderr, "getehdr on %s failed: %s\n",
207 absolute_program, elf_errmsg (-1));
211 class = gelf_getclass (elf);
213 if (class == ELFCLASSNONE) {
214 fprintf (stderr, "getclass on %s failed: %s\n",
215 absolute_program, elf_errmsg (-1));
221 if (class == ELFCLASS32)
228 /* Find the appropriate path to the libfips wrapper.
230 * This involves, first, examining the elf header of the 'program'
231 * binary to be executed to know whether we should look for
232 * libfips-32.so or libfips-64.so.
234 * Next, we find the absolute patch containing the library as follows:
236 * 1. Look in same directory as current executable image
238 * This is to support running from the source directory, without
239 * having installed anything.
241 * 2. Look in relative path from $(foo)/$(bindir) to
242 * $(foo)/$(libdir)/fips based on $(foo) from current executable
243 * image and configured $(bindir) and $(libdir).
245 * We do this rather than looking directly at the configured
246 * $(libdir) to support cases where the application may have been
247 * moved after being installed, (in particular, we want to be
248 * particularly careful not to mix one program with a different
249 * wrapper---so this "nearest search" should most often be
252 * Returns: a string talloc'ed to 'ctx'
255 find_libfips_path (void *ctx, const char *program)
257 char *bin_path, *library, *lib_path;
260 bits = elf_bits (program);
262 library = talloc_asprintf(ctx, "libfips-%d.so", bits);
264 bin_path = get_bin_name (ctx);
266 chop_trailing_path_component (bin_path);
268 lib_path = talloc_asprintf(ctx, "%s/%s", bin_path, library);
270 if (exists (lib_path))
273 talloc_free (lib_path);
275 lib_path = talloc_asprintf(ctx, "%s/" BINDIR_TO_LIBFIPSDIR "/%s",
278 if (exists (lib_path))
281 fprintf (stderr, "Error: Failed to find library %s.\n", library);
282 fprintf (stderr, "Looked in both:\n"
285 "\t%s/" BINDIR_TO_LIBFIPSDIR "\n", bin_path, bin_path);
289 /* After forking, set LD_PRELOAD to preload libfips-{32,64}.so within
290 * child environment, then exec given arguments.
293 fork_exec_with_fips_preload_and_wait (char * const argv[])
302 void *ctx = talloc_new (NULL);
304 char *ld_preload_value;
306 lib_path = find_libfips_path (ctx, argv[0]);
308 ld_preload_value = getenv ("LD_PRELOAD");
310 if (ld_preload_value) {
311 ld_preload_value = talloc_asprintf(ctx, "%s:%s",
315 ld_preload_value = lib_path;
318 setenv ("LD_PRELOAD", ld_preload_value, 1);
322 execvp (argv[0], argv);
323 fprintf (stderr, "Failed to execute:");
324 for (i = 0; argv[i]; i++) {
325 fprintf (stderr, " %s", argv[i]);
327 fprintf (stderr, "\n");
332 waitpid (pid, &status, 0);
333 if (WIFEXITED (status)) {
334 return (WEXITSTATUS (status));
336 if (WIFSIGNALED (status)) {
337 fprintf (stderr, "Child terminated by signal %d\n",
344 execute_with_fips_preload (int argc, char * const argv[])
349 execvp_args = malloc((argc + 1) * sizeof(char *));
350 if (execvp_args == NULL) {
351 fprintf (stderr, "Out of memory,\n");
355 for (i = 0; i < argc; i++) {
356 execvp_args[i] = argv[i];
359 /* execvp needs final NULL */
360 execvp_args[i] = NULL;
362 return fork_exec_with_fips_preload_and_wait (execvp_args);