]> git.cworth.org Git - fips/blobdiff - execute.c
fixup __dlsym
[fips] / execute.c
index b102a4a2b4b4945e8cc20dc1cfeadeb43f90f789..3ed645a554a20dcedc4564ecb3e537ca2b4ef1ea 100644 (file)
--- a/execute.c
+++ b/execute.c
@@ -36,6 +36,9 @@
 
 #include <linux/limits.h>
 
+#include <fcntl.h>
+#include <gelf.h>
+
 #include "execute.h"
 
 /* Terminate a string representing a filename at the final '/' to
@@ -112,8 +115,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, "Failed to open %s: %s\n", absolute_program,
+                        strerror (errno));
+               exit (1);
+       }
+
+       if (elf_version (EV_CURRENT ) == EV_NONE) {
+               fprintf (stderr, "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, "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, "Not an ELF object: %s\n", absolute_program);
+               exit (1);
+       }
+
+       if (gelf_getehdr (elf, &ehdr) == NULL) {
+               fprintf (stderr, "getehdr on %s failed: %s\n",
+                        absolute_program, elf_errmsg (-1));
+               exit (1);
+       }
+
+       class = gelf_getclass (elf);
+
+       if (class == ELFCLASSNONE) {
+               fprintf (stderr, "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 +252,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);
 
@@ -163,14 +286,11 @@ resolve_path (void *ctx, const char *library)
        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. */
+/* After forking, set LD_PRELOAD to preload libfips-{32,64}.so within
+ * child environment, then exec given arguments.
+ */
 static int
-fork_exec_with_preload_and_wait (char * const argv[], const char *library)
+fork_exec_with_fips_preload_and_wait (char * const argv[])
 {
        pid_t pid;
        int i, status;
@@ -182,7 +302,7 @@ fork_exec_with_preload_and_wait (char * const argv[], const char *library)
                void *ctx = talloc_new (NULL);
                char *lib_path;
 
-               lib_path = resolve_path (ctx, library);
+               lib_path = find_libfips_path (ctx, argv[0]);
 
                setenv ("LD_PRELOAD", lib_path, 1);
 
@@ -210,7 +330,7 @@ fork_exec_with_preload_and_wait (char * const argv[], const char *library)
 }
 
 int
-execute_with_preload (int argc, char * const argv[], const char *library)
+execute_with_fips_preload (int argc, char * const argv[])
 {
        char **execvp_args;
        int i;
@@ -228,5 +348,5 @@ 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);
+       return fork_exec_with_fips_preload_and_wait (execvp_args);
 }