X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=execute.c;h=eaedbb481602db781c8120d524cc326910b0ddf9;hb=158a5862aeea9224fcd60c28b0bb19cb6b9f9381;hp=b102a4a2b4b4945e8cc20dc1cfeadeb43f90f789;hpb=1f4014b53a4dc77768f3998a6fd3b67024431fa3;p=fips diff --git a/execute.c b/execute.c index b102a4a..eaedbb4 100644 --- a/execute.c +++ b/execute.c @@ -19,12 +19,8 @@ * THE SOFTWARE. */ -#include "config.h" +#include "fips.h" -#include -#include - -#include #include #include @@ -36,7 +32,11 @@ #include +#include +#include + #include "execute.h" +#include "xmalloc.h" /* Terminate a string representing a filename at the final '/' to * eliminate the final filename component, (leaving only the directory @@ -78,20 +78,20 @@ get_bin_name (void *ctx) * of the filename being linked to). Go figure. */ int name_len = PATH_MAX + 1; - name = talloc_size (ctx, name_len - 1); + name = talloc_size (ctx, name_len); if (name == NULL) { fprintf (stderr, "Out of memory.\n"); exit (1); } - name_len = readlink (link, name, name_len); + name_len = readlink (link, name, name_len - 1); if (name_len < 0) { - fprintf (stderr, "Failed to readlink %s: %s\n", link, + fprintf (stderr, "fips: Error: Failed to readlink %s: %s\n", link, strerror (errno)); exit (1); } - name[name_len + 1] = '\0'; + name[name_len] = '\0'; return name; } @@ -112,8 +112,123 @@ exists (const char *path) return 1; } -/* Given "library" filename resolve it to an absolute path to an - * existing file as follows: +/* Given a program name, search the PATH environment variable and + * return the first absolute path to 'program'. + * + * Returns: A string talloc'ed to 'ctx'. + * + * Note: This function aborts the current program if 'program' cannot + * be located by searching PATH. + */ +static char * +search_path_for_program (void *ctx, const char *program) +{ + char *orig_path, *path, *colon, *dir, *candidate; + void *local = talloc_new (ctx); + + /* If the program name already contains a slash, then this is + * an absolute (or relative) path. Either way, we don't search + * PATH, since we can directly open this filename. */ + if (strchr (program, '/')) + return talloc_strdup (ctx, program); + + orig_path = path = getenv ("PATH"); + + while (*path) { + colon = strchr (path, ':'); + + if (colon) { + dir = talloc_strndup (local, path, colon - path); + path = colon + 1; + } else { + dir = path; + path = path + strlen (path); + } + + candidate = talloc_asprintf(local, "%s/%s", dir, program); + + if (exists (candidate)) { + talloc_steal (ctx, candidate); + talloc_free (local); + return candidate; + } else { + talloc_free (candidate); + } + } + + fprintf (stderr, "Cannot find program %s (looked in %s)\n", + program, orig_path); + exit (1); +} + +/* Is the given elf program 32 or 64 bit? + * + * Note: This function aborts the current program if 'program' cannot + * be opened as a valid ELF file. */ +static int +elf_bits (const char *program) +{ + Elf *elf; + GElf_Ehdr ehdr; + int fd, class; + void *local = talloc_new (NULL); + char *absolute_program = search_path_for_program (local, program); + + fd = open (absolute_program, O_RDONLY, 0); + if (fd < 0) { + fprintf (stderr, "fips: Failed to open %s: %s\n", absolute_program, + strerror (errno)); + exit (1); + } + + if (elf_version (EV_CURRENT ) == EV_NONE) { + fprintf (stderr, "fips: Failed to initialize elf library: %s\n", + elf_errmsg (-1)); + exit (1); + } + + elf = elf_begin (fd, ELF_C_READ, NULL); + if (elf == NULL) { + fprintf (stderr, "fips: Call to elf_begin on %s failed: %s\n", + absolute_program, elf_errmsg(-1)); + exit (1); + } + + if (elf_kind (elf) != ELF_K_ELF) { + fprintf (stderr, "fips: Not an ELF object: %s\n", absolute_program); + exit (1); + } + + if (gelf_getehdr (elf, &ehdr) == NULL) { + fprintf (stderr, "fips: getehdr on %s failed: %s\n", + absolute_program, elf_errmsg (-1)); + exit (1); + } + + class = gelf_getclass (elf); + + if (class == ELFCLASSNONE) { + fprintf (stderr, "fips: getclass on %s failed: %s\n", + absolute_program, elf_errmsg (-1)); + exit (1); + } + + talloc_free (local); + + if (class == ELFCLASS32) + return 32; + else + return 64; + +} + +/* Find the appropriate path to the libfips wrapper. + * + * This involves, first, examining the elf header of the 'program' + * binary to be executed to know whether we should look for + * libfips-32.so or libfips-64.so. + * + * Next, we find the absolute patch containing the library as follows: * * 1. Look in same directory as current executable image * @@ -134,9 +249,14 @@ exists (const char *path) * Returns: a string talloc'ed to 'ctx' */ static char * -resolve_path (void *ctx, const char *library) +find_libfips_path (void *ctx, const char *program) { - char *bin_path, *lib_path; + char *bin_path, *library, *lib_path; + int bits; + + bits = elf_bits (program); + + library = talloc_asprintf(ctx, "libfips-%d.so", bits); bin_path = get_bin_name (ctx); @@ -160,66 +280,22 @@ resolve_path (void *ctx, const char *library) "\t%s\n" "and\n" "\t%s/" BINDIR_TO_LIBFIPSDIR "\n", bin_path, bin_path); - exit (1); -} - -/* After forking, set LD_PRELOAD to preload "library" within child - * environment, then exec given arguments. - * - * The "library" argument is the filename (without path) of a shared - * library to load. The complete path will be resolved with - * resolve_library_path above. */ -static int -fork_exec_with_preload_and_wait (char * const argv[], const char *library) -{ - pid_t pid; - int i, status; - - pid = fork (); - - /* Child */ - if (pid == 0) { - void *ctx = talloc_new (NULL); - char *lib_path; - - lib_path = resolve_path (ctx, library); - - setenv ("LD_PRELOAD", lib_path, 1); - talloc_free (ctx); - - execvp (argv[0], argv); - fprintf (stderr, "Failed to execute:"); - for (i = 0; argv[i]; i++) { - fprintf (stderr, " %s", argv[i]); - } - fprintf (stderr, "\n"); - exit (1); - } - - /* Parent */ - waitpid (pid, &status, 0); - if (WIFEXITED (status)) { - return (WEXITSTATUS (status)); - } - if (WIFSIGNALED (status)) { - fprintf (stderr, "Child terminated by signal %d\n", - WTERMSIG (status)); - } - return 1; + fprintf(stderr, "\nIt's possible fips was not compiled with support for %d-bit applications.\n", bits); + fprintf(stderr, "Perhaps you need to install gcc-multilib and re-compile fips?\n"); + exit (1); } int -execute_with_preload (int argc, char * const argv[], const char *library) +execute_with_fips_preload (int argc, char * const argv[]) { + void *ctx = talloc_new (NULL); + char *lib_path; + char *ld_preload_value; char **execvp_args; int i; - execvp_args = malloc((argc + 1) * sizeof(char *)); - if (execvp_args == NULL) { - fprintf (stderr, "Out of memory,\n"); - return 1; - } + execvp_args = xmalloc((argc + 1) * sizeof(char *)); for (i = 0; i < argc; i++) { execvp_args[i] = argv[i]; @@ -228,5 +304,27 @@ execute_with_preload (int argc, char * const argv[], const char *library) /* execvp needs final NULL */ execvp_args[i] = NULL; - return fork_exec_with_preload_and_wait (execvp_args, library); + lib_path = find_libfips_path (ctx, argv[0]); + + ld_preload_value = getenv ("LD_PRELOAD"); + + if (ld_preload_value) { + ld_preload_value = talloc_asprintf(ctx, "%s:%s", + ld_preload_value, + lib_path); + } else { + ld_preload_value = lib_path; + } + + setenv ("LD_PRELOAD", ld_preload_value, 1); + + talloc_free (ctx); + + execvp (argv[0], argv); + fprintf (stderr, "Failed to execute:"); + for (i = 0; argv[i]; i++) { + fprintf (stderr, " %s", argv[i]); + } + fprintf (stderr, "\n"); + exit (1); }