guix-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

01/02: pack: "fakechroot" execution engine can load its audit module.


From: guix-commits
Subject: 01/02: pack: "fakechroot" execution engine can load its audit module.
Date: Tue, 28 Jul 2020 08:42:52 -0400 (EDT)

civodul pushed a commit to branch master
in repository guix.

commit c6c0d5a22c2ee3d7164dab0129b2e4852a4ae76c
Author: Ludovic Courtès <ludovic.courtes@inria.fr>
AuthorDate: Tue Jul 28 10:48:50 2020 +0200

    pack: "fakechroot" execution engine can load its audit module.
    
    Fixes <https://bugs.gnu.org/42558>.
    
    Until now, loading 'pack-audit.so' in a truly non-Guix environment would
    usually fail because 'pack-audit.so' depends on 'libgcc_s.so' and
    'libc.so', none of which could be found.
    
    Furthermore, the test was not working as expected: the trick
    
      unshare -mrf sh -c 'mount -t tmpfs none /gnu ; ...'
    
    would allow the fakechroot engine to make its store available as
    /gnu/store as a result of another bug.
    
    * gnu/packages/aux-files/run-in-namespace.c (relocated_search_path): New
    function.
    (exec_with_loader): Pass "--library-path" to the loader.
    * guix/scripts/pack.scm (wrapped-package)[build](runpath): New procedure.
    (elf-loader-compile-flags): Pass "-DLOADER_AUDIT_RUNPATH".
    * tests/guix-pack-relocatable.sh: Remove 'STORE_PARENT'.
    (run_without_store): New function.  Erase $NIX_STORE_DIR instead of
    $STORE_PARENT.
    Use 'run_without_store' throughout.
---
 gnu/packages/aux-files/run-in-namespace.c | 48 +++++++++++++++++--
 guix/scripts/pack.scm                     | 17 +++++++
 tests/guix-pack-relocatable.sh            | 76 +++++++++++++++----------------
 3 files changed, 99 insertions(+), 42 deletions(-)

diff --git a/gnu/packages/aux-files/run-in-namespace.c 
b/gnu/packages/aux-files/run-in-namespace.c
index 5a6b932..7f7e5c6 100644
--- a/gnu/packages/aux-files/run-in-namespace.c
+++ b/gnu/packages/aux-files/run-in-namespace.c
@@ -371,24 +371,64 @@ exec_with_proot (const char *store, int argc, char 
*argv[])
 
 #if HAVE_EXEC_WITH_LOADER
 
+/* Traverse PATH, a NULL-terminated string array, and return a colon-separated
+   search path where each item of PATH has been relocated to STORE.  The
+   result is malloc'd.  */
+static char *
+relocated_search_path (const char *path[], const char *store)
+{
+  char *new_path;
+  size_t size = 0;
+
+  for (size_t i = 0; path[i] != NULL; i++)
+    size += strlen (store) + strlen (path[i]) + 1;  /* upper bound */
+
+  new_path = xmalloc (size + 1);
+  new_path[0] = '\0';
+
+  for (size_t i = 0; path[i] != NULL; i++)
+    {
+      if (strncmp (path[i], original_store,
+                  sizeof original_store - 1) == 0)
+       {
+         strcat (new_path, store);
+         strcat (new_path, path[i] + sizeof original_store - 1);
+       }
+      else
+       strcat (new_path, path[i]);       /* possibly $ORIGIN */
+
+      strcat (new_path, ":");
+    }
+
+  new_path[strlen (new_path) - 1] = '\0'; /* Remove trailing colon.  */
+
+  return new_path;
+}
+
 /* Execute the wrapped program by invoking the loader (ld.so) directly,
    passing it the audit module and preloading libfakechroot.so.  */
 static void
 exec_with_loader (const char *store, int argc, char *argv[])
 {
+  static const char *audit_library_path[] = LOADER_AUDIT_RUNPATH;
   char *loader = concat (store,
                         PROGRAM_INTERPRETER + sizeof original_store);
-  size_t loader_specific_argc = 6;
+  size_t loader_specific_argc = 8;
   size_t loader_argc = argc + loader_specific_argc;
   char *loader_argv[loader_argc + 1];
   loader_argv[0] = argv[0];
   loader_argv[1] = "--audit";
   loader_argv[2] = concat (store,
                           LOADER_AUDIT_MODULE + sizeof original_store);
-  loader_argv[3] = "--preload";
-  loader_argv[4] = concat (store,
+
+  /* The audit module depends on libc.so and libgcc_s.so.  */
+  loader_argv[3] = "--library-path";
+  loader_argv[4] = relocated_search_path (audit_library_path, store);
+
+  loader_argv[5] = "--preload";
+  loader_argv[6] = concat (store,
                           FAKECHROOT_LIBRARY + sizeof original_store);
-  loader_argv[5] = concat (store,
+  loader_argv[7] = concat (store,
                           "@WRAPPED_PROGRAM@" + sizeof original_store);
 
   for (size_t i = 0; i < argc; i++)
diff --git a/guix/scripts/pack.scm b/guix/scripts/pack.scm
index 5fb6aaa..75386de 100644
--- a/guix/scripts/pack.scm
+++ b/guix/scripts/pack.scm
@@ -744,11 +744,13 @@ last resort for relocation."
     (with-imported-modules (source-module-closure
                             '((guix build utils)
                               (guix build union)
+                              (guix build gremlin)
                               (guix elf)))
       #~(begin
           (use-modules (guix build utils)
                        ((guix build union) #:select (relative-file-name))
                        (guix elf)
+                       (guix build gremlin)
                        (ice-9 binary-ports)
                        (ice-9 ftw)
                        (ice-9 match)
@@ -786,6 +788,14 @@ last resort for relocation."
                                    bv 0 (bytevector-length bv))
                  (utf8->string bv)))))
 
+          (define (runpath file)
+            ;; Return the RUNPATH of FILE as a list of directories.
+            (let* ((bv      (call-with-input-file file get-bytevector-all))
+                   (elf     (parse-elf bv))
+                   (dyninfo (elf-dynamic-info elf)))
+              (or (and=> dyninfo elf-dynamic-info-runpath)
+                  '())))
+
           (define (elf-loader-compile-flags program)
             ;; Return the cpp flags defining macros for the ld.so/fakechroot
             ;; wrapper of PROGRAM.
@@ -807,6 +817,13 @@ last resort for relocation."
 
                             (string-append "-DLOADER_AUDIT_MODULE=\""
                                            #$(audit-module) "\"")
+                            (string-append "-DLOADER_AUDIT_RUNPATH={ "
+                                           (string-join
+                                            (map object->string
+                                                 (runpath
+                                                  #$(audit-module)))
+                                            ", " 'suffix)
+                                           "NULL }")
                             (if gconv
                                 (string-append "-DGCONV_DIRECTORY=\""
                                                gconv "\"")
diff --git a/tests/guix-pack-relocatable.sh b/tests/guix-pack-relocatable.sh
index 52d7212..1ba3889 100644
--- a/tests/guix-pack-relocatable.sh
+++ b/tests/guix-pack-relocatable.sh
@@ -38,51 +38,52 @@ then
     exit 77
 fi
 
-STORE_PARENT="`dirname $NIX_STORE_DIR`"
-export STORE_PARENT
-if test "$STORE_PARENT" = "/"; then exit 77; fi
-
-if unshare -mrf sh -c 'mount -t tmpfs none "$STORE_PARENT"'
-then
-    # Test the wrapper that relies on user namespaces.
-    relocatable_option="-R"
-else
-    case "`uname -m`" in
-       x86_64|i?86)
-           # Test the wrapper that falls back to PRoot.
-           relocatable_option="-RR";;
-       *)
-           # XXX: Our 'proot' package currently fails tests on non-Intel
-           # architectures, so skip this by default.
-           exit 77;;
-    esac
-fi
+# Attempt to run the given command in a namespace where the store is
+# invisible.  This makes sure the presence of the store does not hide
+# problems.
+run_without_store ()
+{
+    if unshare -r true         # Are user namespaces supported?
+    then
+       # Run that relocatable executable in a user namespace where we "erase"
+       # the store by mounting an empty file system on top of it.  That way,
+       # we exercise the wrapper code that creates the user namespace and
+       # bind-mounts the store.
+       unshare -mrf sh -c 'mount -t tmpfs -o ro none "$NIX_STORE_DIR"; '"$*"
+    else
+       # Run the relocatable program in the current namespaces.  This is a
+       # weak test because we're going to access store items from the host
+       # store.
+       $*
+    fi
+}
 
 test_directory="`mktemp -d`"
 export test_directory
 trap 'chmod -Rf +w "$test_directory"; rm -rf "$test_directory"' EXIT
 
-export relocatable_option
-tarball="`guix pack $relocatable_option -S /Bin=bin sed`"
-(cd "$test_directory"; tar xvf "$tarball")
-
-if unshare -r true             # Are user namespaces supported?
+if unshare -r true
 then
-    # Run that relocatable 'sed' in a user namespace where we "erase" the 
store by
-    # mounting an empty file system on top of it.  That way, we exercise the
-    # wrapper code that creates the user namespace and bind-mounts the store.
-    unshare -mrf sh -c 'mount -t tmpfs none "$STORE_PARENT"; echo 
"$STORE_PARENT"/*; "$test_directory/Bin/sed" --version > 
"$test_directory/output"'
+    # Test the 'userns' execution engine.
+    tarball="`guix pack -R -S /Bin=bin sed`"
+    (cd "$test_directory"; tar xvf "$tarball")
+
+    run_without_store "$test_directory/Bin/sed" --version > 
"$test_directory/output"
+    grep 'GNU sed' "$test_directory/output"
+
+    # Same with an explicit engine.
+    run_without_store GUIX_EXECUTION_ENGINE="userns" \
+                     "$test_directory/Bin/sed" --version > 
"$test_directory/output"
+    grep 'GNU sed' "$test_directory/output"
 
     # Check whether the exit code is preserved.
-    if unshare -mrf sh -c 'mount -t tmpfs none "$STORE_PARENT"; echo 
"$STORE_PARENT"/*; "$test_directory/Bin/sed" --does-not-exist';
+    if run_without_store "$test_directory/Bin/sed" --does-not-exist;
     then false; else true; fi
+
+    chmod -Rf +w "$test_directory"; rm -rf "$test_directory"/*
 else
-    # Run the relocatable 'sed' in the current namespaces.  This is a weak
-    # test because we're going to access store items from the host store.
-    "$test_directory/Bin/sed" --version > "$test_directory/output"
+    echo "'userns' execution tests skipped" >&2
 fi
-grep 'GNU sed' "$test_directory/output"
-chmod -Rf +w "$test_directory"; rm -rf "$test_directory"/*
 
 case "`uname -m`" in
     x86_64|i?86)
@@ -90,20 +91,19 @@ case "`uname -m`" in
        tarball="`guix pack -RR -S /Bin=bin sed`"
        tar tvf "$tarball" | grep /bin/proot
        (cd "$test_directory"; tar xvf "$tarball")
-       GUIX_EXECUTION_ENGINE="proot"
-       export GUIX_EXECUTION_ENGINE
+       run_without_store GUIX_EXECUTION_ENGINE="proot" \
        "$test_directory/Bin/sed" --version > "$test_directory/output"
        grep 'GNU sed' "$test_directory/output"
 
        # Now with fakechroot.
-       GUIX_EXECUTION_ENGINE="fakechroot"
+       run_without_store GUIX_EXECUTION_ENGINE="fakechroot" \
        "$test_directory/Bin/sed" --version > "$test_directory/output"
        grep 'GNU sed' "$test_directory/output"
 
        chmod -Rf +w "$test_directory"; rm -rf "$test_directory"/*
        ;;
     *)
-       echo "skipping PRoot test" >&2
+       echo "skipping PRoot and Fakechroot tests" >&2
        ;;
 esac
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]